focusnoteapp

Productivity & Tasks
v1.0.0
Benign

Add text to today's daily note in FocusNote as a new bullet point.

733 downloads733 installsby @trongnguyen29

Setup & Installation

Install command

clawhub install trongnguyen29/focusnoteapp

If the CLI is not installed:

Install command

npx clawhub@latest install trongnguyen29/focusnoteapp

Or install with OpenClaw CLI:

Install command

openclaw skills install trongnguyen29/focusnoteapp

or paste the repo link into your assistant's chat

Install command

https://github.com/openclaw/skills/tree/main/skills/trongnguyen29/focusnoteapp

What This Skill Does

Adds user-provided text to FocusNote's daily note as a new bullet point. It reads the app's config to find the documents directory, then locates or creates a date-named note and appends a new node to its JSON structure. Changes appear in FocusNote immediately after saving.

Writes directly to FocusNote's internal file structure, so entries appear in the app without manual copy-paste or UI interaction.

When to Use It

  • Logging completed tasks at end of day
  • Capturing a quick reminder mid-conversation
  • Appending meeting action items to today's note
  • Recording ideas without switching apps
  • Adding follow-up items from a call
View original SKILL.md file
# FocusNote: Add to Daily Note

This skill adds user-provided text to today's daily note in FocusNote as a new bullet point.

## How It Works

1. Reads the FocusNote documents path from `~/.lucia/documents-path.txt`
2. Generates today's date in `YYYY-MM-DD` format
3. Locates or creates today's daily note
4. Adds the user's text as a new bullet point
5. Updates the document's JSON structure files

## Prerequisites

- FocusNote app must be running (it creates `~/.lucia/documents-path.txt` on startup)
- Node.js installed for running the helper script

## Implementation

When the user asks to add text to their daily note, follow these steps:

### Step 1: Read Documents Path

```javascript
const fs = require("fs");
const path = require("path");
const os = require("os");

// Read the documents path from FocusNote's config file
const focusnoteConfigPath = path.join(
  os.homedir(),
  ".lucia",
  "documents-path.txt",
);
const documentsPath = fs.readFileSync(focusnoteConfigPath, "utf-8").trim();
```

### Step 2: Generate Today's Date

```javascript
const today = new Date();
const year = today.getFullYear();
const month = String(today.getMonth() + 1).padStart(2, "0");
const day = String(today.getDate()).padStart(2, "0");
const todayDocName = `${year}-${month}-${day}`;
```

### Step 3: Locate Daily Note Folder

```javascript
const dailyNotePath = path.join(documentsPath, "notes", todayDocName);
const structurePath = path.join(dailyNotePath, "_structure.json");
const metadataPath = path.join(dailyNotePath, "_metadata.json");
const nodesDir = path.join(dailyNotePath, ".nodes");
```

### Step 4: Create Daily Note If It Doesn't Exist

```javascript
if (!fs.existsSync(dailyNotePath)) {
  // Create directory structure
  fs.mkdirSync(dailyNotePath, { recursive: true });
  fs.mkdirSync(nodesDir, { recursive: true });

  // Create metadata
  const metadata = {
    name: todayDocName,
    createdAt: Date.now(),
    updatedAt: Date.now(),
  };
  fs.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2));

  // Create empty structure
  const structure = {
    rootNodeIds: [],
    deletedNodeIds: [],
    nodes: {},
  };
  fs.writeFileSync(structurePath, JSON.stringify(structure, null, 2));
}
```

### Step 5: Create New Bullet Node

```javascript
const { v4: uuidv4 } = require("uuid"); // npm install uuid

// Generate unique node ID
const nodeId = uuidv4();
const timestamp = Date.now();

// Create Lexical bullet structure
const lexicalContent = {
  root: {
    children: [
      {
        children: [
          {
            children: [
              {
                detail: 0,
                format: 0,
                mode: "normal",
                style: "",
                text: userText, // The text from the user
                type: "text",
                version: 1,
              },
            ],
            direction: "ltr",
            format: "",
            indent: 0,
            type: "listitem",
            version: 1,
            value: 1,
          },
        ],
        direction: "ltr",
        format: "",
        indent: 0,
        type: "list",
        version: 1,
        listType: "bullet",
        start: 1,
        tag: "ul",
      },
    ],
    direction: "ltr",
    format: "",
    indent: 0,
    type: "root",
    version: 1,
  },
};

// Create node object
const newNode = {
  id: nodeId,
  content: JSON.stringify(lexicalContent),
  isFolded: false,
  isTodo: false,
  isDone: false,
  isInProgress: false,
  isBlurred: false,
  backgroundColor: null,
  createdAt: timestamp,
  updatedAt: timestamp,
};
```

### Step 6: Save Node to Sharded Directory

```javascript
// Shard by first 2 characters of node ID
const shard = nodeId.substring(0, 2);
const shardDir = path.join(nodesDir, shard);

if (!fs.existsSync(shardDir)) {
  fs.mkdirSync(shardDir, { recursive: true });
}

const nodeFilePath = path.join(shardDir, `node-${nodeId}.json`);
fs.writeFileSync(nodeFilePath, JSON.stringify(newNode, null, 2));
```

### Step 7: Update Structure File

```javascript
// Read current structure
const structure = JSON.parse(fs.readFileSync(structurePath, "utf-8"));

// Add node to structure
structure.rootNodeIds.push(nodeId);
structure.nodes[nodeId] = {
  parentId: null,
  orderIndex: structure.rootNodeIds.length - 1,
  childIds: [],
};

// Update timestamp
structure.updatedAt = timestamp;

// Save updated structure
fs.writeFileSync(structurePath, JSON.stringify(structure, null, 2));
```

### Complete Script Example

Here's a complete Node.js script you can use:

```javascript
#!/usr/bin/env node

const fs = require("fs");
const path = require("path");
const os = require("os");
const { v4: uuidv4 } = require("uuid");

function addToDailyNote(userText) {
  try {
    // Step 1: Read documents path
    const focusnoteConfigPath = path.join(
      os.homedir(),
      ".lucia",
      "documents-path.txt",
    );
    if (!fs.existsSync(focusnoteConfigPath)) {
      throw new Error(
        "FocusNote config file not found. Make sure FocusNote is running.",
      );
    }
    const documentsPath = fs.readFileSync(focusnoteConfigPath, "utf-8").trim();

    // Step 2: Generate today's date
    const today = new Date();
    const year = today.getFullYear();
    const month = String(today.getMonth() + 1).padStart(2, "0");
    const day = String(today.getDate()).padStart(2, "0");
    const todayDocName = `${year}-${month}-${day}`;

    // Step 3: Set up paths
    const dailyNotePath = path.join(documentsPath, "notes", todayDocName);
    const structurePath = path.join(dailyNotePath, "_structure.json");
    const metadataPath = path.join(dailyNotePath, "_metadata.json");
    const nodesDir = path.join(dailyNotePath, ".nodes");

    // Step 4: Create daily note if needed
    if (!fs.existsSync(dailyNotePath)) {
      fs.mkdirSync(dailyNotePath, { recursive: true });
      fs.mkdirSync(nodesDir, { recursive: true });

      const metadata = {
        name: todayDocName,
        createdAt: Date.now(),
        updatedAt: Date.now(),
      };
      fs.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2));

      const structure = {
        rootNodeIds: [],
        deletedNodeIds: [],
        nodes: {},
      };
      fs.writeFileSync(structurePath, JSON.stringify(structure, null, 2));
    }

    // Step 5: Create new bullet node
    const nodeId = uuidv4();
    const timestamp = Date.now();

    const lexicalContent = {
      root: {
        children: [
          {
            children: [
              {
                children: [
                  {
                    detail: 0,
                    format: 0,
                    mode: "normal",
                    style: "",
                    text: userText,
                    type: "text",
                    version: 1,
                  },
                ],
                direction: "ltr",
                format: "",
                indent: 0,
                type: "listitem",
                version: 1,
                value: 1,
              },
            ],
            direction: "ltr",
            format: "",
            indent: 0,
            type: "list",
            version: 1,
            listType: "bullet",
            start: 1,
            tag: "ul",
          },
        ],
        direction: "ltr",
        format: "",
        indent: 0,
        type: "root",
        version: 1,
      },
    };

    const newNode = {
      id: nodeId,
      content: JSON.stringify(lexicalContent),
      isFolded: false,
      isTodo: false,
      isDone: false,
      isInProgress: false,
      isBlurred: false,
      backgroundColor: null,
      createdAt: timestamp,
      updatedAt: timestamp,
    };

    // Step 6: Save node file
    const shard = nodeId.substring(0, 2);
    const shardDir = path.join(nodesDir, shard);

    if (!fs.existsSync(shardDir)) {
      fs.mkdirSync(shardDir, { recursive: true });
    }

    const nodeFilePath = path.join(shardDir, `node-${nodeId}.json`);
    fs.writeFileSync(nodeFilePath, JSON.stringify(newNode, null, 2));

    // Step 7: Update structure
    const structure = JSON.parse(fs.readFileSync(structurePath, "utf-8"));
    structure.rootNodeIds.push(nodeId);
    structure.nodes[nodeId] = {
      parentId: null,
      orderIndex: structure.rootNodeIds.length - 1,
      childIds: [],
    };
    structure.updatedAt = timestamp;
    fs.writeFileSync(structurePath, JSON.stringify(structure, null, 2));

    console.log(`✅ Added bullet to ${todayDocName}: "${userText}"`);
    return { success: true, documentName: todayDocName, nodeId };
  } catch (error) {
    console.error("❌ Error adding to daily note:", error.message);
    return { success: false, error: error.message };
  }
}

// Example usage
if (require.main === module) {
  const userText = process.argv.slice(2).join(" ") || "New bullet point";
  addToDailyNote(userText);
}

module.exports = { addToDailyNote };
```

## Usage Examples

**User:** "Add to my daily note: Finished the OpenClaw skill implementation"

**Assistant:** I'll add that to your daily note.

```bash
# Run the script
node add-to-daily-note.js "Finished the OpenClaw skill implementation"
```

**Output:** ✅ Added bullet to 2026-02-11: "Finished the OpenClaw skill implementation"

---

**User:** "Add a reminder to call mom tomorrow"

**Assistant:** I'll add that to today's note.

```bash
node add-to-daily-note.js "Reminder to call mom tomorrow"
```

## Installation

1. Save the script as `add-to-daily-note.js` in your OpenClaw skills directory
2. Install dependencies: `npm install uuid`
3. Make it executable: `chmod +x add-to-daily-note.js`

## Notes

- The skill creates a new bullet point each time it's called
- Bullets are added to the end of the daily note
- If the daily note doesn't exist, it will be created automatically
- The FocusNote app must be running for the documents path file to exist
- Changes are immediately visible when you open/refresh the daily note in FocusNote

## Troubleshooting

**Error: "FocusNote config file not found"**

- Make sure FocusNote is running
- Check that `~/.lucia/documents-path.txt` exists

**Bullets not appearing in FocusNote**

- Try closing and reopening the daily note
- Check that the node files were created in `.nodes/` directory
- Verify `_structure.json` was updated correctly

Example Workflow

Here's how your AI assistant might use this skill in practice.

INPUT

User asks: Logging completed tasks at end of day

AGENT
  1. 1Logging completed tasks at end of day
  2. 2Capturing a quick reminder mid-conversation
  3. 3Appending meeting action items to today's note
  4. 4Recording ideas without switching apps
  5. 5Adding follow-up items from a call
OUTPUT
Add text to today's daily note in FocusNote as a new bullet point.

Share this skill

Security Audits

VirusTotalBenign
OpenClawBenign
View full report

These signals reflect official OpenClaw status values. A Suspicious status means the skill should be used with extra caution.

Details

LanguageMarkdown
Last updatedFeb 25, 2026