Agent skill
siyuan-notes
思源笔记查询工具,如果用户的请求涉及查找、检索、浏览他们的笔记内容,就应该使用这个技能,例如:查询我的xxx
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/development/siyuan-notes
SKILL.md
技能使用指南
推荐调用方式
方式1:使用Bash工具
# 在技能目录中执行搜索
node index.js search "工作总结" 10
# 查询最近内容
node index.js recent 7
# 其他功能
node index.js check
方式2:使用node -e执行JS代码(使用显示的 skill Base directory 作为 cwd)
node -e "
const siyuan = require('./index.js');
(async () => {
const results = await siyuan.searchNotes('工作总结', 10);
console.log(siyuan.formatResults(results));
})();
"
注意事项:
- 直接执行index.js时:会自动从其所在目录加载.env文件,无需特殊路径处理
- 使用node -e时:用技能执行时显示的 "Base directory for this skill" 路径作为cwd参数
- 路径中包含空格时需要引号
- 不要用cd命令,直接用cwd参数控制工作目录
- 尽可能使用 node -e执行而非创建临时 js 文件
快速使用指南
核心 API 函数
const siyuan = require('./index.js');
// 搜索笔记内容
await siyuan.searchNotes('关键词', 20, 'p'); // 搜索段落
await siyuan.searchNotes('关键词', 10, 'h'); // 搜索标题
// 查询最近内容
await siyuan.getRecentBlocks(7, 'updated'); // 最近7天更新
// 查询任务
await siyuan.searchTasks('[ ]', 7); // 未完成任务
// 格式化结果
siyuan.formatResults(results); // 转换为可读格式
常见查询场景
1. 搜索工作总结/开发内容
// 搜索包含"工作"的内容
await siyuan.searchNotes('工作', 15);
// 搜索包含"开发"的内容
await siyuan.searchNotes('开发', 10);
// 搜索包含"总结"的标题
await siyuan.searchNotes('总结', 10, 'h');
// 查询最近7天的所有内容
await siyuan.getRecentBlocks(7, 'updated');
2. 任务管理
// 查询未完成任务
await siyuan.searchTasks('[ ]', 7);
// 查询已完成任务
await siyuan.searchTasks('[x]', 30);
// 查询所有任务(不限状态)
await siyuan.searchTasks('', 7);
3. 文档导航
// 列出所有文档
await siyuan.listDocuments();
// 查询特定文档的子块
await siyuan.getDocumentBlocks('文档ID');
// 查询文档标题
await siyuan.getDocumentHeadings('文档ID');
4. 标签和引用
// 按标签搜索
await siyuan.searchByTag('重要', 10);
// 查询反向链接
await siyuan.getBacklinks('块ID', 20);
命令行使用
# 基础搜索
node index.js search "工作" 10
node index.js search "总结" 5 h
# 查询最近内容
node index.js recent 7
node index.js recent 14 p
# 任务查询
node index.js tasks "[ ]" 7
# 其他功能
node index.js docs
node index.js tag "重要"
查询策略选择
何时使用 API 函数
- 简单搜索: 单个关键词搜索
- 常规查询: 获取最近内容、文档列表等
- 快速原型: 验证查询思路
- 标准化操作: 任务管理、标签查询等
何时使用 SQL
- 复杂条件: 多个 AND/OR 条件组合
- 跨表查询: 需要 JOIN 多个表
- 统计分析: COUNT、AVG、GROUP BY 等
- 性能优化: 需要精确控制查询逻辑
实际应用示例
查找工作总结 (混合策略)
const siyuan = require('./index.js');
// 1. 使用API快速搜索
const workResults = await siyuan.searchNotes('工作', 10);
const summaryResults = await siyuan.searchNotes('总结', 5, 'h');
// 2. 使用SQL进行精确查询
const complexResults = await siyuan.executeSiyuanQuery(`
SELECT content, hpath, created, type, subtype
FROM blocks
WHERE (content LIKE '%工作%' OR content LIKE '%总结%' OR content LIKE '%汇报%')
AND created >= '20251201000000'
AND type IN ('p', 'h', 'l')
AND length > 10
ORDER BY updated DESC
LIMIT 25
`);
// 3. 合并结果并去重
const allResults = [...workResults, ...summaryResults, ...complexResults];
const uniqueResults = allResults.filter(
(item, index, self) => index === self.findIndex((t) => t.id === item.id),
);
// 4. 格式化输出
return siyuan.formatResults(uniqueResults.slice(0, 20));
项目进展查询 (SQL 为主)
// 查找特定项目的所有相关内容
const projectQuery = `
SELECT content, type, subtype, hpath, created, updated
FROM blocks
WHERE (
content LIKE '%项目名称%'
OR content LIKE '%功能模块%'
OR hpath LIKE '%项目路径%'
)
AND created >= '20251201000000'
ORDER BY updated DESC, type DESC
LIMIT 30
`;
const projectResults = await siyuan.executeSiyuanQuery(projectQuery);
// 分类展示结果
const titles = projectResults.filter((item) => item.type === 'h');
const paragraphs = projectResults.filter((item) => item.type === 'p');
const tasks = projectResults.filter((item) => item.type === 'l');
return {
summary: `找到 ${projectResults.length} 条相关内容`,
titles: siyuan.formatResults(titles.slice(0, 5)),
keyContent: siyuan.formatResults(paragraphs.slice(0, 10)),
tasks: siyuan.formatResults(tasks.slice(0, 5)),
};
时间线分析 (统计查询)
// 分析最近的工作活动
const activityAnalysis = await siyuan.executeSiyuanQuery(`
SELECT
DATE(substr(created, 1, 8)) as work_date,
COUNT(*) as content_count,
COUNT(DISTINCT root_id) as doc_count,
SUM(CASE WHEN type = 'l' THEN 1 ELSE 0 END) as task_count
FROM blocks
WHERE created >= strftime('%Y%m%d%H%M%S', datetime('now', '-7 days'))
AND (content LIKE '%工作%' OR content LIKE '%开发%' OR content LIKE '%项目%')
GROUP BY DATE(substr(created, 1, 8))
ORDER BY work_date DESC
`);
return siyuan.formatStructuredResults(activityAnalysis);
sql要求
-
SQL 语法规范:
- 在默认的情况下,用户可以在思源的嵌入块中输入 SQL 代码查询,此时 SQL 查询语句必须以
select * from blocks开头:只允许查询 block 表,且不允许单独查询字段- 面向开发者的高级用法:用户还可以调用后端 API 接口,发送 SQL 查询,此时是可以使用更普遍的 SQL 语法结构的(查询别的表,返回特定字段)
- 使用 SQLite 的语法,如
strftime函数处理时间。 - 默认情况下,查询结果最多返回 64 个块,除非明确指定了
limit xxx
- 在默认的情况下,用户可以在思源的嵌入块中输入 SQL 代码查询,此时 SQL 查询语句必须以
-
输出:将查询语句放在一个 ```SQL 的 markdown 代码块当中,方便用户直接复制
表结构
blocks 表:
-
id: 内容块 ID,格式为时间-随机字符,例如20210104091228-d0rzbmm。 -
parent_id: 双亲块 ID,格式同id -
root_id: 文档块 ID,格式同id -
box: 笔记本 ID,格式同id -
path: 内容块所在文档路径,例如/20200812220555-lj3enxa/20210808180320-abz7w6k/20200825162036-4dx365o.sy -
hpath: 人类可读的内容块所在文档路径,例如/0 请从这里开始/编辑器/排版元素 -
name: 内容块名称 -
alias: 内容块别名 -
memo: 内容块备注 -
tag: 标签,例如#标签1 #标签2# #标签3# -
content: 去除了 Markdown 标记符的文本 -
fcontent: 存储容器块第一个子块的内容 -
markdown: 包含完整 Markdown 标记符的文本 -
length:markdown字段文本长度 -
type: 内容块类型d: 文档,h: 标题,m: 数学公式,c: 代码块,t: 表格块,l: 列表块,b: 引述块,s: 超级块,p:段落块,av:树形视图(俗称数据库,注意区分,这只是一个内容块的叫法)
-
subtype: 特定类型的内容块还存在子类型- 标题块的
h1到h6 - 列表块的
u(无序),t(任务),o(有序)
- 标题块的
-
ial: 内联属性列表,形如{: name="value"},例如{: id="20210104091228-d0rzbmm" updated="20210604222535"} -
sort: 排序权重,数值越小排序越靠前 -
created: 创建时间,格式为YYYYMMDDHHmmss,例如20210104091228 -
updated: 更新时间,格式同created
refs 表:
id: 引用 ID,格式为时间-随机字符,例如20211127144458-idb32wkdef_block_id: 被引用块的块 ID,格式同iddef_block_root_id: 被引用块所在文档的 ID,格式同iddef_block_path: 被引用块所在文档的路径,例如/20200812220555-lj3enxa/20210808180320-fqgskfj/20200905090211-2vixtlf.syblock_id: 引用所在内容块 ID,格式同idroot_id: 引用所在文档块 ID,格式同idbox: 引用所在笔记本 ID,格式同idpath: 引用所在文档块路径,例如/20200812220555-lj3enxa/20210808180320-fqgskfj/20200905090211-2vixtlf.sycontent: 引用锚文本
attributes 表:
-
id: 属性 ID,格式为时间-随机字符,例如20211127144458-h7y55zu -
name: 属性名称- 注意:思源中的用户自定义属性必须加上
custom-前缀 - 例如
name是块的内置属性,但custom-name就是用户的自定义属性了
- 注意:思源中的用户自定义属性必须加上
-
value: 属性值 -
type: 类型,例如b -
block_id: 块 ID,格式同id -
root_id: 文档 ID,格式同id -
box: 笔记本 ID,格式同id -
path: 文档文件路径,例如/20200812220555-lj3enxa.sy。
查询要点提示
-
所有 SQL 查询语句如果没有明确指定
limit,则会被思源查询引擎默认设置limit 64 -
块属性格式相关
- 块 ID 格式统一为
时间-随机字符, 例如20210104091228-d0rzbmm - 块的时间属性,如 created updated 的格式为
YYYYMMDDHHmmss例如20210104091228
- 块 ID 格式统一为
-
块之间的关系
-
层级关系:块大致可以分为
-
内容块(叶子块):仅包含内容的块,例如段落
p,公式块m,代码块c,标题块h,表格块t等- 内容块的
content和markdown字段为块的内容
- 内容块的
-
容器块:包含其他内容块或者容器块的块,例如 列表块
l,列表项块i,引述块/引用块b,超级块s- 每个块的
parent_id指向他直接上层的容器块 - 容器块的
content和markdown字段为容器内所有块的内容
- 每个块的
-
文档块:包含同一文档中所有内容块和容器块的块,
d- 每个块的
root_id指向他所在的文档 - 容器块的
content字段为文档的标题
- 每个块的
-
-
引用关系:当一个块引用了另一个块的时候,会在 refs 表中建立联系
- 如果有多个块引用了同一个块,那么对这个被引用的块而言,这些引用它的块构成了它的反向链接(反链)
- 所有引用关系被存放在 ref 表当中;使用的时候将 blocks 表和 ref 表搭配进行查询
-
-
Daily Note:又称日记,每日笔记,是一种特殊的文档块
- daily note 文档有特殊属性:
custom-dailynote-<yyyyMMdd>=<yyyyMMdd>;被标识了这个属性的文档块(type='d'),会被视为是对应日期的 daily note - 例如
custom-dailynote-20240101=20240101的文档,被视为 2024-01-01 这天的 daily note 文档 - 请注意! daily note (日记)是一个文档块!如果要查询日记内部的内容,请使用
root_id字段来关联日记文档和内部的块的关系
- daily note 文档有特殊属性:
-
书签:含有属性
bookmark=<书签名>的块会被加入对应的书签
SQL 示例
-
查询所有文档块
sqlselect * from blocks where type='d' -
查询所有二级标题块
sqlselect * from blocks where subtype = 'h2' -
查询某个文档的子文裆
sqlselect * from blocks where path like '%/<当前文档id>/%' and type='d' -
随机漫游某个文档内所有标题块
sqlSELECT * FROM blocks WHERE root_id LIKE '<文档 id>' AND type = 'h' ORDER BY random() LIMIT 1 -
查询含有关键词「唯物主义」的段落块
sqlselect * from blocks where markdown like '%唯物主义%' and type ='p' ORDER BY updated desc -
查询过去 7 天内没有完成的任务(任务列表项)
注:思源中,任务列表项的 markdown 为
* [ ] Task text如果是已经完成的任务,则是* [x] Task TextsqlSELECT * from blocks WHERE type = 'l' AND subtype = 't' AND created > strftime('%Y%m%d%H%M%S', datetime('now', '-7 day')) AND markdown like'* [ ] %' AND parent_id not in ( select id from blocks where subtype = 't' ) -
查询某个块所有的反链块(引用了这个块的所有块)
sqlselect * from blocks where id in ( select block_id from refs where def_block_id = '<被引用的块ID>' ) limit 999 -
查询某个时间段内的 daily note(日记)
注意由于没有指定 limit,最大只能查询 64 个
sqlselect distinct B.* from blocks as B join attributes as A on B.id = A.block_id where A.name like 'custom-dailynote-%' and B.type='d' and A.value >= '20231010' and A.value <= '20231013' order by A.value desc; -
查询某个笔记本下没有被引用过的文档,限制 128 个
sqlselect * from blocks as B where B.type='d' and box='<笔记本 BoxID>' and B.id not in ( select distinct R.def_block_id from refs as R ) order by updated desc limit 128
Didn't find tool you were looking for?