FocusNote 每日笔记插入器:自动化日志 - Openclaw Skills
作者:互联网
2026-03-26
什么是 FocusNote 每日笔记插入器?
此技能在 AI 代理与 FocusNote(一款本地优先的笔记应用)之间架起了一座桥梁。通过利用 Openclaw Skills,开发人员可以编程化地将想法、提醒或已完成的任务注入到每日笔记中,而无需手动打开应用。它处理 FocusNote 所需的复杂基于 Lexical 的 JSON 结构,确保每个条目都在应用的本机数据库中完美格式化和索引。
该集成专为希望从命令行界面或 AI 驱动的工作流中直接维持持续的意识流或记录工作进度的用户而设计。通过直接与文件系统交互,它在保持 FocusNote 生态系统内数据完整性的同时,确保了高性能和可靠性。
下载入口:https://github.com/openclaw/skills/tree/main/skills/trongnguyen29/focusnoteapp
安装与下载
1. ClawHub CLI
从源直接安装技能的最快方式。
npx clawhub@latest install focusnoteapp
2. 手动安装
将技能文件夹复制到以下位置之一
全局模式~/.openclaw/skills/
工作区
/skills/
优先级:工作区 > 本地 > 内置
3. 提示词安装
将此提示词复制到 OpenClaw 即可自动安装。
请帮我使用 Clawhub 安装 focusnoteapp。如果尚未安装 Clawhub,请先安装(npm i -g clawhub)。
FocusNote 每日笔记插入器 应用场景
- 在整个工作日中快速捕捉想法或思绪,无需切换窗口。
- 自动将已完成的编码任务或 git 提交记录到每日日志中。
- 将提醒附加到每日日志,以便在早会期间进行后续回顾。
- 如果当天的第一个条目是通过 AI 代理生成的,则自动创建每日笔记结构。
- 通过读取用户主目录中的配置文件定位 FocusNote 文档存储路径。
- 解析当前日期以确定 YYYY-MM-DD 格式的特定每日笔记目录名称。
- 验证每日笔记文件夹及其内部结构是否存在,必要时进行创建。
- 为新内容节点生成唯一 ID,并将用户的文本格式化为兼容 Lexical 的 JSON 对象。
- 将节点数据写入 .nodes 目录内的分片文件系统中,以维持性能。
- 将新节点的 ID 附加到根结构中,并更新文档的元数据以反映更改。
FocusNote 每日笔记插入器 配置指南
要将其集成到您的 Openclaw Skills 工作流中,请按照以下步骤操作:
- 确保已安装并运行 FocusNote,以在
~/.lucia/documents-path.txt生成所需的配置路径。 - 在本地机器上安装 Node.js。
- 将实现脚本保存为技能目录中的
add-to-daily-note.js。 - 安装所需的依赖项:
npm install uuid
- 授予脚本执行权限:
chmod +x add-to-daily-note.js
FocusNote 每日笔记插入器 数据架构与分类体系
该技能与 FocusNote 存储路径中的特定目录层级结构进行交互:
| 文件/文件夹 | 描述 |
|---|---|
notes/[YYYY-MM-DD]/ |
特定日期内容的根文件夹。 |
_metadata.json |
包含文档名称、创建和更新时间戳。 |
_structure.json |
定义节点层级、父子关系和显示顺序。 |
.nodes/[shard]/ |
用于节点存储的分片目录(UUID 的前 2 个字符)。 |
node-[id].json |
包含 Lexical JSON 和状态标志的单个内容块。 |
name: focusnote-add-to-daily-note
description: Add text to today's daily note in FocusNote as a new bullet point
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
- Reads the FocusNote documents path from
~/.lucia/documents-path.txt - Generates today's date in
YYYY-MM-DDformat - Locates or creates today's daily note
- Adds the user's text as a new bullet point
- Updates the document's JSON structure files
Prerequisites
- FocusNote app must be running (it creates
~/.lucia/documents-path.txton 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
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
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
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
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
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
// 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
// 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:
#!/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.
# 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.
node add-to-daily-note.js "Reminder to call mom tomorrow"
Installation
- Save the script as
add-to-daily-note.jsin your OpenClaw skills directory - Install dependencies:
npm install uuid - 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.txtexists
Bullets not appearing in FocusNote
- Try closing and reopening the daily note
- Check that the node files were created in
.nodes/directory - Verify
_structure.jsonwas updated correctly
相关推荐
专题
+ 收藏
+ 收藏
+ 收藏
+ 收藏
+ 收藏
最新数据
相关文章
Context Engineer:Openclaw 技能的 Token 优化专家
韩国发票:自动化估价单与税务发票 - Openclaw Skills
小红书文案教练:爆款笔记生成器 - Openclaw Skills
慕尼黑 MVG & S-Bahn 实时追踪命令行工具 - Openclaw Skills
Reddit 研究技能:自动化社群洞察 - Openclaw Skills
豆包聊天:带有联网搜索功能的免费 AI 对话 - Openclaw Skills
NightPatch:自动化工作流优化 - Openclaw 技能
国产 AI 视频生成器:Wan2.6 与可灵集成 - Openclaw Skills
Sonos Announce:智能音频状态恢复 - Openclaw Skills
Hypha Payment:P2P 代理协作与 USDT 结算 - Openclaw Skills
AI精选
