Compare commits
21
Commits
@@ -1,14 +1,29 @@
|
|||||||
{
|
{
|
||||||
"name": "yixiong-tools",
|
"name": "yixiong-claude-hub",
|
||||||
"owner": {
|
"owner": {
|
||||||
"name": "蚁熊团队"
|
"name": "蚁熊团队"
|
||||||
},
|
},
|
||||||
"description": "蚁熊公司内部 Claude Code 技能市场",
|
"description": "蚁熊官方出品的 Claude Code 能力增强平台。这里汇聚了团队在工程实践中沉淀的精选技能与工作流插件——从代码审查到数据工程,从项目管理到 AI 辅助写作,每一个插件都源自真实业务场景的打磨。装上它,让 Claude Code 更懂蚁熊。",
|
||||||
"plugins": [
|
"plugins": [
|
||||||
{
|
{
|
||||||
"name": "example-skill",
|
"name": "huanxi",
|
||||||
"source": "./plugins/example-skill",
|
"source": "./plugins/huanxi",
|
||||||
"description": "示例插件,演示 Plugin 结构"
|
"description": "寰汐企业管理系统 · 个人端:日报、负责人日报、任务、议题、会议、组织检索六个工作流技能,自动配置个人端 MCP 连接(hxp_ Token,在寰汐个人中心自助生成)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "huanxi-admin",
|
||||||
|
"source": "./plugins/huanxi-admin",
|
||||||
|
"description": "寰汐企业管理系统 · 管理端:汇报盘点、模块与成员配置、运维简报三个工作流技能,自动配置管理端 MCP 连接(hxa_ Token,由后台管理员发放)。普通员工无需安装"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "memcore",
|
||||||
|
"source": "./plugins/memcore",
|
||||||
|
"description": "记忆体系核心引擎:memory-sync(全量同步)、memory-update(增量写入)、memory-lint(健康校验)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "obsidian",
|
||||||
|
"source": "./plugins/obsidian",
|
||||||
|
"description": "Obsidian 知识库 AI 协作插件族:检测到 .obsidian/ 目录自动激活,含 vault 管理、搜索图谱、frontmatter、任务、每日笔记、Bases 数据库、Canvas 视觉层、版本历史、插件配置、PKM 编排工作流共 10 个技能"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# Memory Index
|
||||||
|
> _Last synced: 2026-07-10 | Base commit: `a13898b`_
|
||||||
|
|
||||||
|
| 文件 | 描述 | 类型 | 引用 | Commit |
|
||||||
|
|------|------|------|------|--------|
|
||||||
|
| decisions.md | 关键架构决策:无版本号/userConfig/Bearer Token/SKILL.md规范/路径锁定/memcore三项优化/memcore-shared共享层/lint_report保活/Base commit兜底/obsidian社区对标审查/memory-lint速度分档过期检测 | project | 2 | a13898b |
|
||||||
|
| project_overview.md | 项目定位、目录结构、插件规范、发布流程(huanxi/memcore/obsidian 10 技能) | project | 1 | fad7335 |
|
||||||
|
| feedback_plugin_dev.md | 插件开发协作规范:同步四处/路径解析/工具签名对照/MCP docstring单一真相/签名变更全量扫描 | feedback | 1 | 38beecb |
|
||||||
|
| lint_report.md | memory-lint 最新执行结果 | lint | 0 | 38beecb |
|
||||||
@@ -0,0 +1,176 @@
|
|||||||
|
---
|
||||||
|
name: 架构决策
|
||||||
|
description: Marketplace 设计中的关键技术决策及其原因:无版本号/userConfig/Bearer Token/SKILL.md规范/路径锁定/memcore三项优化/memcore-shared共享层/lint_report保活/Base commit兜底/obsidian社区对标审查/memory-lint速度分档过期检测
|
||||||
|
type: project
|
||||||
|
last_updated: 2026-07-10
|
||||||
|
commit: a13898b
|
||||||
|
---
|
||||||
|
|
||||||
|
# 关键架构决策
|
||||||
|
|
||||||
|
## plugin.json 不设 version 字段
|
||||||
|
|
||||||
|
**结论**:所有 plugin.json 均不含 `version` 字段。
|
||||||
|
|
||||||
|
**Why**:Claude Code 官方文档说明,若 plugin.json 设置了固定 `version`,推送新 commit 不改 version 字符串时,已安装用户看不到更新。省略 version 后,Claude Code 自动用 git commit SHA 做版本判断,每次推送 main 分支即为新版本。
|
||||||
|
|
||||||
|
**How to apply**:新增插件时不要加 `version` 字段。memcore 和 huanxi 均已按此规范执行。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## huanxi plugin 使用 userConfig 而非环境变量传 Token
|
||||||
|
|
||||||
|
**结论**:`plugin.json` 用 `userConfig` + `sensitive: true` 声明 Bearer Token 输入,`mcpServers.headers` 中用 `${user_config.token}` 引用。
|
||||||
|
|
||||||
|
**Why**:`sensitive: true` 将 token 存入系统钥匙链(或 `~/.claude/.credentials.json`),不会出现在 settings.json 中,避免随仓库提交泄露。Claude Code 安装插件时自动弹窗提示用户输入,体验好于环境变量。
|
||||||
|
|
||||||
|
**How to apply**:其他需要用户配置 API Key/Token 的插件,均应使用此模式,不要用 `${ENV_VAR}` 方式。
|
||||||
|
|
||||||
|
```json
|
||||||
|
"userConfig": {
|
||||||
|
"token": {
|
||||||
|
"type": "string",
|
||||||
|
"title": "寰汐 Personal Token",
|
||||||
|
"description": "在寰汐系统后台生成,hxp_ 前缀",
|
||||||
|
"sensitive": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**See Also**:[[project_overview.md#已发布插件]]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## huanxi MCP Server 认证:Bearer Token 直连,不改后端
|
||||||
|
|
||||||
|
**结论**:plugin.json 配置 `Authorization: Bearer ${user_config.token}` header,MCP server 已有的 `_PersonalTokenVerifier` 直接验证 `hxp_` token,无需改后端。
|
||||||
|
|
||||||
|
**Why**:后端已有 ASGI 中间件模式(AdminMcpAuthMiddleware)和 PersonalTokenVerifier,Bearer Token 天然支持。OAuth2 Discovery Flow 是 FastMCP 框架层的特性,当客户端直接在 header 中传 Bearer Token 时可绕过 OAuth 流程。改后端风险高且无必要。
|
||||||
|
|
||||||
|
**How to apply**:未来新增 MCP server 插件时,只需在 plugin.json 配置 header,不需要修改后端认证逻辑。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## memcore memory-update/lint 路径锁定:禁止写入系统自动记忆路径
|
||||||
|
|
||||||
|
**结论**:`memory-update` 和 `memory-lint` 的唯一操作路径锁定为 `$PROJECT_DIR/.claude/memory/`;严禁写入 `~/.claude/projects/*/memory/`;两个技能执行期间不触发 auto memory 系统写入。
|
||||||
|
|
||||||
|
**Why**:Claude Code 的 auto memory 是 system-level 指令,在技能执行期间始终有效。若技能只在 description 中说"不推送远程"而无显式路径约束,AI 会在执行 memory-update/lint 时被 auto memory 指令并发触发,将内容写入系统级路径(`~/.claude/projects/xxx/memory/`),背离"项目本地 .claude/memory/ 是唯一权威"的初衷。
|
||||||
|
|
||||||
|
**How to apply**:两个技能均在正文最前加"⚠ 路径锁定"块(含禁止路径清单 + 执行前断言代码),memory-sync 的 Phase 3 加方向锁定注释(Phase 10 是唯一远程写入窗口)。未来新增操作本地记忆的技能也应遵循同等约束。
|
||||||
|
|
||||||
|
**See Also**:[[project_overview.md#已发布插件]]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## memcore:synonyms.md 作为独立等价词表文件
|
||||||
|
|
||||||
|
**结论**:等价表述清单以独立的 `synonyms.md`(`type: reference`)存放于 `.claude/memory/`,而非内嵌到 feedback.md。
|
||||||
|
|
||||||
|
**Why**:feedback.md 存放协作规范(含 Why + How to apply),语义上属于"决策";synonyms.md 是纯配置数据,在 lint Phase 4 矛盾检测前作为输入加载。两者职责不同,混放会让 lint 的加载逻辑复杂化。`type: reference` 符合"外部参考资料"语义,且该类型已在 frontmatter 枚举中。
|
||||||
|
|
||||||
|
**How to apply**:新建项目记忆体系时,若项目有领域专有术语缩写(如 PG/PostgreSQL、KT/Kotlin),在 `.claude/memory/synonyms.md` 中维护等价组(每行逗号分隔)。幽灵检测自动排除该文件,不纳入 MEMORY.md 索引。
|
||||||
|
|
||||||
|
**See Also**:[[decisions.md#memcore memory-update/lint 路径锁定:禁止写入系统自动记忆路径]]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## memcore:synthesis 三触发分工——快扫 vs 精扫
|
||||||
|
|
||||||
|
**结论**:synthesis 升级触发拆为三路:A 会话内主动、B Phase 3C 即时快扫(每次 memory-update 必跑)、C lint Top 反向触发(月度运行)。
|
||||||
|
|
||||||
|
**Why**:原双触发中,B 路径依赖 lint 生成 `lint_report.md` 的「条目级高频引用 Top」段,短会话或任务型对话中 lint 常被跳过,导致高频引用条目长期未升级为 synthesis。Phase 3C 快扫在每次 memory-update 结束时强制执行,覆盖短会话盲区;lint 精扫按源文件去重计数,用于月度深度检查。两者以 `**Synthesized:**` 标记作为唯一判重依据,不重复创建文件。
|
||||||
|
|
||||||
|
**How to apply**:实现新的 memory-update 类技能时,引用计数类检查应分"即时快扫"和"月度精扫"两档,分别对应"覆盖率"和"准确率"的不同优先级。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## memcore memory-sync:冲突检测必须先于 git commit
|
||||||
|
|
||||||
|
**结论**:memory-sync Phase 0 重构为两步:Step 1 冲突优先检测(`diff --diff-filter=U`)→ Step 2 普通变更提交。冲突语义合并完成后才允许 commit,再进入 Phase 1。
|
||||||
|
|
||||||
|
**Why**:原设计中 Phase 0 先执行 `git add + commit`,Phase 0.5 才检测冲突。若文件存在 git merge conflict markers,`git commit` 会静默失败(git 拒绝提交含冲突标记的文件),整个 sync 流程进入不确定状态且无明显报错。改为"先检测再提交"消除了这条静默失败路径。
|
||||||
|
|
||||||
|
**How to apply**:设计任何含"检测 + 操作"两步的流程时,检测必须先于操作,且检测结果应作为操作的前置条件,而非事后处理。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## memcore-shared:路径锁定 + 全局常量的单一来源
|
||||||
|
|
||||||
|
**结论**:把路径锁定、全局常量(SYNTHESIS_THRESHOLD / LINT_STALE_*_DAYS / MULTI_HOST_WARN_DAYS)、PROJECT_DIR 跨平台解析提取到独立 skill `memcore-shared`,三个主技能(memory-sync / memory-update / memory-lint)开头 `Read ../memcore-shared/SKILL.md` 引用其约束。description 中显式说明"内部 include,不由用户直接调用"。
|
||||||
|
|
||||||
|
**Why**:原设计中 memory-update 和 memory-lint 各自维护一份 20 行的"路径锁定"块,完全重复;阈值常量 `≥3`、`≥30/90 天`、`≥7 天` 分散硬编码在多个文件多个位置,调整需多处改动。共享层独立成 skill 后:① 单点维护、② 阈值修改只动一处、③ 与 huanxi-shared 同模式,可演进性强。
|
||||||
|
|
||||||
|
**How to apply**:未来 memcore 类多 skill 插件如出现「共享约束 + 多处硬编码常量」时,提取为独立 `<plugin>-shared` skill;常量声明在共享 skill 顶部表格,子技能引用常量名而非裸数字。
|
||||||
|
|
||||||
|
**See Also**:[[decisions.md#memcore memory-update/lint 路径锁定:禁止写入系统自动记忆路径]] [[feedback_plugin_dev.md#skill 不要重写 MCP 参数表,引用 docstring 为单一真相]]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## memcore lint_report 增量保活:稳定 ID + resolved 跳过
|
||||||
|
|
||||||
|
**结论**:lint Phase 8 生成 NEED-HUMAN 条目时,末尾附 `<!-- id: 8位sha1 -->`(基于 phase + 文件 + 章节 + 关键事实计算)。Phase 8-pre 提取旧 `lint_report.md` 中带 `<!-- resolved -->` 标记的 ID 集合,新报告中同 ID 条目跳过。
|
||||||
|
|
||||||
|
**Why**:原 lint_report.md 每次覆盖写入,用户即使在 NEED-HUMAN 条目处理完或决定"不处理"后,下次 lint 仍会重新列出。导致信号疲劳,长期看反而忽视所有 lint 提示。引入稳定 ID + resolved 标记后,用户对每个条目的判断(处理/接受现状)能跨多次 lint 持续生效,lint_report 变成只列"真正待处理"的事项。
|
||||||
|
|
||||||
|
**How to apply**:任何"周期性扫描 + 报告生成"的 lint/check 系统,凡有用户主观判断维度(不只是机器判定)时,输出条目都应有稳定 ID + 用户标记跳过机制。ID 计算用「问题本体」字段(位置+事实),不要包含执行时间/扫描序号。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## memory-update Phase 1 锚点丢失兜底
|
||||||
|
|
||||||
|
**结论**:memory-update Phase 1 读 `Base commit` 锚点时,若 MEMORY.md 头部该行缺失或为 N/A,从各 memory 文件 frontmatter 的 `commit:` 字段取最旧值兜底,避免退化为全量。
|
||||||
|
|
||||||
|
**Why**:MEMORY.md 头部 `Base commit: HASH` 是单一锚点来源,一旦用户手动编辑误删此行,整个 git diff 范围退化为全量审查,触发 memory-update 对所有文件做"按变更维度重写"。即使大部分文件没真实变化,也会被刷一次 last_updated 和 commit 字段,造成虚假改动。兜底机制从各文件 frontmatter 取最旧 commit,确保覆盖所有真实差量而非无差别全量。
|
||||||
|
|
||||||
|
**How to apply**:任何"单点配置 → 关键路径"的设计,必须考虑配置丢失时的退路。优先级:单点 → 多点冗余 → 兜底推导。memcore 当前是「单点 + 兜底推导」,无需冗余存储。
|
||||||
|
|
||||||
|
**See Also**:[[decisions.md#memcore memory-sync:冲突检测必须先于 git commit]]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## SKILL.md frontmatter 只保留 name 和 description
|
||||||
|
|
||||||
|
**结论**:SKILL.md frontmatter 只写 `name` 和 `description` 两个字段,去掉 `version`。
|
||||||
|
|
||||||
|
**Why**:Claude Code 插件规范中 SKILL.md frontmatter 只定义了 `name` 和 `description`。`version` 字段不在规范内,silently ignored,且与 plugin.json 层面的版本管理重复。已从所有 huanxi skill 文件中移除。
|
||||||
|
|
||||||
|
**How to apply**:新建 SKILL.md 时只写这两个字段。`description` 字段写用户实际口语触发词(第三人称描述),不要用"当需要…时触发"的内部视角表达。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## obsidian skill 集对标社区基准的审查 + 优化(2026-06-12)
|
||||||
|
|
||||||
|
**结论**:基于公开社区调研结果(kepano/obsidian-skills 31.8k★、AgriciDaniel/claude-obsidian 15 技能、qhuang20/obsidian-skills、pablo-mano/Obsidian-CLI-skill),对本地 9 技能完成全量审查并执行方案 B(中等扩展):
|
||||||
|
|
||||||
|
1. **P1 描述去冗余**:8 个子技能 description 末尾"检测到 .obsidian/ 时与核心技能同步激活"全部删除——Claude Code 路由器按关键词独立打分,没有"伴随激活"机制,此声明纯占预算。
|
||||||
|
2. **P5 obsidian-plugins 缩范围**:从"控制面板"宽泛定位收敛到"环境层(插件/主题/CSS/Templates/快捷键/命令)",加"首次配置 vault 批量装常用插件"高频场景。
|
||||||
|
3. **P6 obsidian-workflow-pkm 加引导**:description 显式声明"多步骤复合需求优先匹配本技能,单一原子操作走子技能",让"清理 inbox"等短指令更易命中编排层。
|
||||||
|
4. **P3 核心 obsidian 补 OFM 语法速查**:在第 4 章末尾增"Obsidian Flavored Markdown 语法速查"小节,覆盖 wikilinks/embeds/callouts/block refs/highlight/math 全表 + 写入时高频陷阱。
|
||||||
|
5. **P4 workflow-pkm 补 Workflow 8 Web Clip → Permanent**:单篇网页剪藏轻量流,引用 defuddle(Obsidian 团队官方 web→md 清洗工具)+ WebFetch 兜底,明确与 Workflow 7(批量文献)的边界。
|
||||||
|
6. **P2 新增 obsidian-canvas skill**:JSON Canvas 1.0 schema 速查 + 16 hex ID 生成 + 直接 Read/Write JSON 路线(社区共识:obsidian-cli 不原生支持 .canvas 写入)+ 安全 SOP 4 选项对照表(A git stash / B .bak / C 原子写 / D File Recovery)。
|
||||||
|
|
||||||
|
**Why**:
|
||||||
|
- 社区呈现两条路线:kepano「按文件格式分技能」(5 技能/精)、AgriciDaniel「按方法论分技能」(15 技能/全)。我们的「按工作域分技能」(9→10 技能)取中间路线,保留跨插件感知和职责互斥声明的独特优势。
|
||||||
|
- 8 处"伴随激活"提示是隐蔽设计错误——它假设了 Claude Code 路由器看不懂的联动语义,是单次审查中最大的描述质量收益点(每技能省 ~28 字符预算给真触发词)。
|
||||||
|
- canvas 是 Obsidian 开放格式且独立于 Markdown 体系,社区标杆都作为独立 skill 维护;不加 canvas 等于把"视觉知识图"这类高频场景拱手让人。
|
||||||
|
|
||||||
|
**How to apply**:
|
||||||
|
- 新增 skill 时,description 末尾**不要写"检测到 X 时与 Y 同步激活"**——Claude Code 路由按关键词独立打分。
|
||||||
|
- 触发词列表用 `触发词:A、B、C` 显式列;`不用于:X(技能名)` 显式互斥;这种结构提升路由准确率。
|
||||||
|
- 涉及 vault 内格式(.canvas/.base/.md)的能力,**默认独立成 skill**——不要塞进核心 obsidian。
|
||||||
|
- 学习模式契机:obsidian-canvas 的"AI 大批量写入回滚策略"4 选项对照表留给团队/用户决策,AI 不强制做掉,默认采用 C+D 作为决策前兜底。
|
||||||
|
|
||||||
|
**See Also**:[[feedback_plugin_dev.md#MCP 后端工具签名变更后必须全量扫描所有 skill]]、kepano/obsidian-skills、AgriciDaniel/claude-obsidian
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## memory-lint 过期检测改用提交速度分档,弃用固定 30/90 天阈值(2026-07-10)
|
||||||
|
|
||||||
|
**结论**:`/memory-lint` Phase 5 过期检测从固定 `LINT_STALE_WARN_DAYS=30` / `LINT_STALE_ERROR_DAYS=90` 改为「自 last_updated 以来的全仓库提交速度」分档:`LINT_STALE_MIN_DAYS=7`(不足 7 天跳过检测)+ 速度 ≥`LINT_HIGH_VELOCITY`(1.0 次/天) → ERROR,≥`LINT_LOW_VELOCITY`(0.3 次/天) → WARN,低于此速度不判定过期,但 `LINT_STALE_ABSOLUTE_DAYS`(180 天) 绝对兜底。
|
||||||
|
|
||||||
|
**Why**:AI 辅助开发下代码迭代速度远超传统人工节奏,高频项目 7 天内可能已发生大量架构变更,30 天固定阈值严重滞后不报警;反过来低活跃期项目(如进入维护期)超过 30 天没提交,旧记忆大概率仍准确,固定天数会误报过期。纯日历天数无法区分"高频漂移"和"低频稳定"两种情况,需要用提交速度代理"内容漂移风险"。
|
||||||
|
|
||||||
|
**How to apply**:新增/调整任何"距离上次更新多久算过期"的判定逻辑时,优先考虑用活跃度信号(提交频次、变更行数等)分档,而非固定日历阈值。常量集中在 `memcore-shared` 全局常量表单点维护,调整数值只改一处。
|
||||||
|
|
||||||
|
**See Also**:[[decisions.md#memcore-shared:路径锁定 + 全局常量的单一来源]]
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
---
|
||||||
|
name: 插件开发协作反馈
|
||||||
|
description: 在此 marketplace 项目中开发插件时需遵守的协作规范和经验教训
|
||||||
|
type: feedback
|
||||||
|
last_updated: 2026-06-12
|
||||||
|
commit: 38beecb
|
||||||
|
---
|
||||||
|
|
||||||
|
# 插件开发协作规范
|
||||||
|
|
||||||
|
## 新增插件时必须同步更新四个位置
|
||||||
|
|
||||||
|
**规范**:新增插件必须同步修改:① `plugins/<name>/` 目录 ② `plugins/<name>/.claude-plugin/plugin.json` ③ `.claude-plugin/marketplace.json` 的 plugins 数组 ④ `CLAUDE.md` 的已发布插件表格。
|
||||||
|
|
||||||
|
**Why**:marketplace.json 是 Claude Code 的安装入口,CLAUDE.md 是新会话的参考文档,两者不更新会导致插件不可被发现。
|
||||||
|
|
||||||
|
**How to apply**:每次创建插件后用 checklist 验证四处都已修改。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## cp -r 复制目录时注意目标路径存在与否
|
||||||
|
|
||||||
|
**规范**:用 `cp -r source/ dest/` 复制 skill 目录时,若 `dest/` 目录不存在,source 内容会直接成为 `dest/`(而非 `dest/source/`)。
|
||||||
|
|
||||||
|
**Why**:本次将 huanxi-shared 复制到 skills/ 目录时,因为 skills/ 不存在,SKILL.md 直接落在了 skills/ 下而非 skills/huanxi-shared/ 下,需要手动修复。
|
||||||
|
|
||||||
|
**How to apply**:多目录批量复制时,先 `mkdir -p` 目标目录,再逐个 `cp -r`;或改用第一个 `cp -r` 后检查结构。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 引入 Skill 相对路径时需考虑运行时路径解析
|
||||||
|
|
||||||
|
**规范**:SKILL.md 中引用其他 skill 文件时使用 `../sibling-skill/SKILL.md` 的相对路径(如 huanxi-* 系列引用 huanxi-shared),这种模式在 Claude Code 插件的 skill 目录结构下是可行的,但依赖 Claude 正确解析路径。
|
||||||
|
|
||||||
|
**Why**:validator 审查时指出相对路径存在解析风险,但由于 huanxi-* 系列已在用户本地以相同目录结构正常工作,打包后一致性可保持。
|
||||||
|
|
||||||
|
**How to apply**:若未来发现 Read 相对路径失败,改为在每个 skill 内联关键共享规则(工具签名表、缓存 TTL),降低对 Read 成功的依赖。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## SKILL.md description 使用用户口语,不用内部视角
|
||||||
|
|
||||||
|
**规范**:frontmatter 的 `description` 字段应描述用户会说的话("我有哪些模块"、"帮我写日报"),不要写内部触发条件("当需要解析模块名/人员名为 ID 时触发")。
|
||||||
|
|
||||||
|
**Why**:description 是 Claude Code 判断何时触发该技能的依据,也是展示给用户的摘要。内部视角语言对用户无意义,且不能有效触发。
|
||||||
|
|
||||||
|
**How to apply**:新建 skill 时,先想"用户实际会怎么说这个需求",用这些词写 description。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## plugin-validator 和 skill-reviewer 审查之后要对照实际代码修正工具签名
|
||||||
|
|
||||||
|
**规范**:Plugin 审查发现工具名称错误时(如 report_submit vs report_submit_item),必须回到源代码(`huanxi_mcp/tools/*.py`)确认实际函数签名,以代码为准修正 skill 描述。
|
||||||
|
|
||||||
|
**Why**:本次发现 huanxi-shared 工具索引中 report_submit/withdraw 用了旧名,leader_report_submit/withdraw 缺必填参数,weekly_report_save 参数名用 week 而非 week_number,这些都是 MCP 升级后 skill 未同步导致的。
|
||||||
|
|
||||||
|
**How to apply**:每次 MCP server 工具链升级后,运行 plugin-validator 对照检查 skill 中的工具调用。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## skill 不要重写 MCP 参数表,引用 docstring 为单一真相
|
||||||
|
|
||||||
|
**规范**:MCP 工具的参数细节(字段名、必填、枚举值、类型)以后端 Python 函数 docstring 为**单一真相来源**。skill 文档不要重画完整字段表,最多给一个 happy path 的调用示例 + 历史踩坑说明,在 reference 文档顶部统一声明"参数细节以 MCP `<tool_name>` 的 docstring 为准"。
|
||||||
|
|
||||||
|
**Why**:本次发现 `huanxi-report/references/report-draft.md` 的字段表与后端 `report_save_draft` docstring 大幅漂移(缺 module_id 必填、progress 字段名错为 progress 应为 progress_update、虚构 status 字段),直接导致用户日报频繁报"参数缺失"。skill 一旦重画参数表,就和 MCP docstring 形成两套真相 —— 任一处改动另一处就漂移。同类漂移在 weekly(week→week_number)、task(due_date→end_date / urgent→critical / todo→not_started)、org(user_id→id)系列均出现,呈系统性问题。
|
||||||
|
|
||||||
|
**How to apply**:
|
||||||
|
1. 写 skill 时不画字段表;如非要列字段,必须在文末加"以 MCP docstring 为准"声明
|
||||||
|
2. 给 LLM 的提示是"调 MCP 时直接信任 docstring"而非"按本文档调用"
|
||||||
|
3. MCP 工具签名变更时**不需要**改 skill(只要 skill 没硬编码参数表)
|
||||||
|
|
||||||
|
**See Also**:[[feedback_plugin_dev.md#plugin-validator 和 skill-reviewer 审查之后要对照实际代码修正工具签名]] [[feedback_plugin_dev.md#MCP 后端工具签名变更后必须全量扫描所有 skill]] [[decisions.md#memcore-shared:路径锁定 + 全局常量的单一来源]]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## MCP 后端工具签名变更后必须全量扫描所有 skill
|
||||||
|
|
||||||
|
**规范**:MCP server 的工具签名(参数名、必填项、枚举值、返回字段)变更后,必须对引用该 MCP 的所有 skill 做全量 grep 扫描,找到漂移点逐一对齐。不要依赖单元测试或调用时报错来"被动发现"。
|
||||||
|
|
||||||
|
**Why**:本次扫描发现 huanxi 的 6 个 skill + 7 个 reference 中漂移密度极高:4 类典型模式(字段名错 / 枚举值错 / 缺必填 / 缓存示例与后端返回结构不一致)覆盖所有 huanxi-* 系列。漂移源于后端 docstring 在多次迭代中演进,但 skill 未同步审查。这种漂移在调用时才会被发现("参数缺失"、"字段不存在"),对用户体验是慢性损耗。
|
||||||
|
|
||||||
|
**How to apply**:
|
||||||
|
1. 后端 PR 中涉及 MCP 工具的,PR 描述必须列出签名变更点
|
||||||
|
2. 合并后立即在 marketplace 仓库做对照扫描(grep 漂移关键词,如旧字段名)
|
||||||
|
3. 漂移修正与签名变更在同一 sprint 完成,不留尾巴
|
||||||
|
|
||||||
|
**典型扫描点**(针对 huanxi):参数名 `progress` vs `progress_update`、`due_date` vs `end_date`、`week` vs `week_number`;枚举值 `todo` vs `not_started`、`urgent` vs `critical`;返回字段 `user_id` vs `id`。
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
---
|
||||||
|
name: 记忆健康检查报告
|
||||||
|
description: memory-lint 最新一次执行的检查结果与待处理项
|
||||||
|
type: lint
|
||||||
|
last_updated: 2026-07-10
|
||||||
|
commit: a13898b
|
||||||
|
---
|
||||||
|
|
||||||
|
# 记忆健康检查报告
|
||||||
|
|
||||||
|
> _执行时间: 2026-07-10 | Base commit: `a13898b` | Last synced: 2026-07-10_
|
||||||
|
>
|
||||||
|
> **如何使用**:NEED-HUMAN 条目末尾有 `<!-- id: xxxxxxxx -->` 标记。处理完或决定不处理时,在同段追加 `<!-- resolved: DATE, 简要原因 -->`,下次 lint 该条目自动跳过。
|
||||||
|
|
||||||
|
## 健康概览
|
||||||
|
|
||||||
|
| 检查项 | AUTO-FIX | NEED-HUMAN(含已 resolved 跳过 N 项) |
|
||||||
|
|--------|---------|-----------|
|
||||||
|
| 1 孤儿 / 2 幽灵 / 3A 引用 / 3B 双链 | 0 / 0 / 2 / 0 | — / — / 0 / 1(含已 resolved 跳过 0 项) |
|
||||||
|
| 4 矛盾 / 5 过期 / 6 污染 | — | 0 / 0 / 0 |
|
||||||
|
|
||||||
|
**AUTO-FIX 已执行 2 项 | NEED-HUMAN 新列出 1 项 | 历史已 resolved 跳过 0 项**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## AUTO-FIX 已执行清单
|
||||||
|
|
||||||
|
- [x] 更新断链(Phase 3A,章节标题漂移):`decisions.md` 内 `[[feedback_plugin_dev.md#skill 不要重写 MCP 参数表,引用 docstring]]` → `[[feedback_plugin_dev.md#skill 不要重写 MCP 参数表,引用 docstring 为单一真相]]`
|
||||||
|
- [x] 更新断链(Phase 3A,章节标题漂移):`decisions.md` 内 `[[feedback_plugin_dev.md#签名变更全量扫描]]` → `[[feedback_plugin_dev.md#MCP 后端工具签名变更后必须全量扫描所有 skill]]`
|
||||||
|
- [x] MEMORY.md「引用」列已刷新(按源文件去重重新计数,见下方文件级引用计数表;`decisions.md` 3→2,因 lint_report.md 本身不再含旧版 wikilink)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 条目级高频引用 Top(供 /memory-update 消费)
|
||||||
|
|
||||||
|
跨 ≥`SYNTHESIS_THRESHOLD`(默认 3)个不同源文件被引用的 decisions/feedback 条目。
|
||||||
|
|
||||||
|
| 条目 | 跨文件次数 | 建议 |
|
||||||
|
|------|----------|------|
|
||||||
|
| — | — | 无候选 |
|
||||||
|
|
||||||
|
当前所有 decisions/feedback 条目的**单 section 级**跨文件引用数均 < 3,无 synthesis 升级候选。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## NEED-HUMAN 待处理清单
|
||||||
|
|
||||||
|
### [WARN] 双链非对称 — 3B 目标章节缺少精确反向链接
|
||||||
|
|
||||||
|
- **A→B**:`decisions.md → ## obsidian skill 集对标社区基准的审查 + 优化` → `[[feedback_plugin_dev.md#MCP 后端工具签名变更后必须全量扫描所有 skill]]`
|
||||||
|
- **现状**:`feedback_plugin_dev.md` 全文件对 `decisions.md` 有反向引用(`## skill 不要重写 MCP 参数表...` 一节内的 See Also),但不在本次目标章节 `## MCP 后端工具签名变更后必须全量扫描所有 skill` 内,按边界规则不自动追加,仅记录。
|
||||||
|
- **说明**:非结构性错误(目标文件/章节均存在,链接有效),纯属"是否需要精确双链"的风格判断,不影响可读性,可长期搁置。
|
||||||
|
- **矩阵**:若希望强化双链闭环 → 在该章节末尾追加 `**See Also**:[[decisions.md#obsidian skill 集对标社区基准的审查 + 优化]]`;若认为文件级已有反向引用足够 → 标记 resolved 即可。
|
||||||
|
<!-- id: 3f3d2245 -->
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 文件级引用计数(来自 Phase 3A,按源文件去重)
|
||||||
|
|
||||||
|
| 文件 | 被引用次数(去重源) | 引用来源 |
|
||||||
|
|------|-------|---------|
|
||||||
|
| **decisions.md** | **2** | feedback_plugin_dev.md / project_overview.md |
|
||||||
|
| project_overview.md | 1 | decisions.md(含 2 个 wikilink,同源去重为 1) |
|
||||||
|
| feedback_plugin_dev.md | 1 | decisions.md(含 2 个 wikilink,同源去重为 1) |
|
||||||
|
| lint_report.md | 0 | — |
|
||||||
|
|
||||||
|
**备注**:`decisions.md` 文件级引用数由 3 降为 2(未跌破规则,是 lint_report.md 本身历史上不含 wikilink 却被误计入源——本次按 grep 实测重新计数),暂不满足 `SYNTHESIS_THRESHOLD`(3) 核心枢纽节点条件。
|
||||||
|
|
||||||
|
`synonyms.md` 不存在,矛盾检测使用保守模式(仅检测直接数值/版本冲突)。如项目有领域术语缩写,建议创建 `.claude/memory/synonyms.md`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 过期检测明细(速度分档,本次生效的新逻辑)
|
||||||
|
|
||||||
|
| 文件 | last_updated | days_since | commits_since(全仓库) | velocity(次/天) | 判定 |
|
||||||
|
|------|-------------|-----------|----------------------|------------------|------|
|
||||||
|
| project_overview.md | 2026-06-12 | 28 | 8 | 0.29 | 低于 LOW_VELOCITY(0.3),不判定过期 |
|
||||||
|
| feedback_plugin_dev.md | 2026-06-12 | 28 | 8 | 0.29 | 低于 LOW_VELOCITY(0.3),不判定过期 |
|
||||||
|
| decisions.md | 2026-07-10 | 0 | — | — | 不足 MIN_DAYS(7),跳过 |
|
||||||
|
| lint_report.md | 2026-07-10 | 0 | — | — | 不足 MIN_DAYS(7),跳过 |
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
---
|
||||||
|
name: 项目概述
|
||||||
|
description: yixiong-claude-marketplace 的定位、目录结构、插件规范和发布流程
|
||||||
|
type: project
|
||||||
|
last_updated: 2026-06-12
|
||||||
|
commit: fad7335
|
||||||
|
---
|
||||||
|
|
||||||
|
# 蚁熊内部 Claude Code Marketplace
|
||||||
|
|
||||||
|
## 定位
|
||||||
|
|
||||||
|
蚁熊公司内部 Claude Code Plugin Marketplace(技能市场),统一管理和发布供全员安装的 Claude Code 插件与技能。Marketplace 名称:`yixiong-claude-hub`。
|
||||||
|
|
||||||
|
## 目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
.claude-plugin/
|
||||||
|
└── marketplace.json # 市场索引:声明所有插件
|
||||||
|
|
||||||
|
plugins/
|
||||||
|
└── <plugin-name>/
|
||||||
|
├── .claude-plugin/
|
||||||
|
│ └── plugin.json # 插件元数据
|
||||||
|
└── skills/
|
||||||
|
└── <skill-name>/
|
||||||
|
├── SKILL.md
|
||||||
|
└── references/ # 可选:详细工作流文档
|
||||||
|
```
|
||||||
|
|
||||||
|
## 文件格式规范
|
||||||
|
|
||||||
|
### marketplace.json
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "yixiong-claude-hub",
|
||||||
|
"owner": { "name": "蚁熊团队" },
|
||||||
|
"description": "...",
|
||||||
|
"plugins": [
|
||||||
|
{ "name": "<name>", "source": "./plugins/<name>", "description": "..." }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### plugin.json(关键字段)
|
||||||
|
- **无 `version` 字段**:用 git commit SHA 作为版本基准,每次推送 main 即发布
|
||||||
|
- `userConfig`:用于用户输入敏感配置(token 等),`sensitive: true` 存系统钥匙链
|
||||||
|
- `mcpServers`:声明 MCP 服务器,headers 中可用 `${user_config.KEY}` 替换
|
||||||
|
|
||||||
|
### SKILL.md frontmatter(只需两字段)
|
||||||
|
```yaml
|
||||||
|
---
|
||||||
|
name: skill-name
|
||||||
|
description: "触发描述(用户实际口语,不用内部视角)"
|
||||||
|
---
|
||||||
|
```
|
||||||
|
- **不写 `version`**:version 不是 SKILL.md 规范字段
|
||||||
|
|
||||||
|
## 已发布插件
|
||||||
|
|
||||||
|
| 插件 | 技能 | 特性 |
|
||||||
|
|------|------|------|
|
||||||
|
| `huanxi` | 7 个(report/leader/task/issue/meeting/org/shared) | 个人端;userConfig Bearer Token + MCP Server(URL 走 office 子域,无端口) |
|
||||||
|
| `huanxi-admin` | 4 个(admin-report/admin-module/admin-ops/admin-shared) | 管理端;同上机制,Token 前缀 `hxa_`,与个人端是两条独立信任边界 |
|
||||||
|
| `memcore` | 4 个(memory-sync/lint/update/shared) | 纯技能,无 MCP;memcore-shared 作内部 include(路径锁定 + 阈值常量 + PROJECT_DIR 解析),支持 synonyms.md 等价词表、Phase 3C 即时引用快扫、Phase 0 并发冲突保护、lint_report 稳定 ID + resolved 跳过、Base commit 兜底 |
|
||||||
|
| `obsidian` | 10 个(obsidian/bases/canvas/daily/history/meta/plugins/search/tasks/workflow-pkm) | 纯技能,无 MCP;对标社区基准(kepano/obsidian-skills 31.8k★、AgriciDaniel/claude-obsidian)后扩展 canvas 视觉层;核心 obsidian 含 OFM 语法速查;workflow-pkm 含 Web Clip 子流程 |
|
||||||
|
|
||||||
|
**See Also**:[[decisions.md#huanxi plugin 使用 userConfig 而非环境变量传 Token]]
|
||||||
|
|
||||||
|
## 发布流程
|
||||||
|
|
||||||
|
1. 新增/修改插件内容
|
||||||
|
2. 提交 main 分支(`git push`)
|
||||||
|
3. 已安装用户会话启动时自动检测更新(需用户先手动开启 auto-update 一次:`/plugin` → Marketplaces → Enable auto-update)
|
||||||
|
4. 有更新时提示执行 `/reload-plugins`
|
||||||
|
|
||||||
|
**第三方 marketplace 默认关闭 auto-update**,同事安装后需手动开启一次。
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"Bash(mkdir -p ~/.claude/projects/C--Projects-yixiong-claude-marketplace/memory/)",
|
||||||
|
"Bash(cp -pf \"C:/Projects/yixiong-claude-marketplace/.claude/memory/\"*.md ~/.claude/projects/C--Projects-yixiong-claude-marketplace/memory/)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
<!-- Last updated: 2026-07-10 | Commit: a13898b -->
|
||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## 项目概述
|
||||||
|
|
||||||
|
蚁熊公司内部 Claude Code Plugin Marketplace(技能市场)。开发者在此仓库中维护供全员安装使用的 Claude Code 插件(Plugin)和技能(Skill)。
|
||||||
|
|
||||||
|
## 目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
.claude-plugin/
|
||||||
|
└── marketplace.json # 市场索引:声明本仓库包含哪些插件
|
||||||
|
|
||||||
|
plugins/
|
||||||
|
└── <plugin-name>/ # 每个插件独占一个子目录
|
||||||
|
├── .claude-plugin/
|
||||||
|
│ └── plugin.json # 插件元数据(name, description, version, author)
|
||||||
|
└── skills/
|
||||||
|
└── <skill-name>/
|
||||||
|
└── SKILL.md # 技能实现(frontmatter + Markdown 指令)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 核心文件格式
|
||||||
|
|
||||||
|
### marketplace.json(市场索引)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "yixiong-claude-hub",
|
||||||
|
"owner": { "name": "蚁熊团队" },
|
||||||
|
"description": "...",
|
||||||
|
"plugins": [
|
||||||
|
{ "name": "<plugin-name>", "source": "./plugins/<plugin-name>", "description": "..." }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
每新增一个插件,必须在 `plugins` 数组中追加对应条目。
|
||||||
|
|
||||||
|
### plugin.json(插件元数据)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "plugin-name",
|
||||||
|
"description": "...",
|
||||||
|
"author": { "name": "蚁熊团队" }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**不设 `version` 字段**:Claude Code 自动用 git commit SHA 作为版本基准,每次推送 main 分支即为新版本,已安装用户会话启动时自动检测更新。
|
||||||
|
|
||||||
|
含 MCP Server 的插件额外支持 `userConfig`(用户敏感配置,存系统钥匙链)和 `mcpServers`(服务器声明),可在 headers 中用 `${user_config.KEY}` 引用用户配置。
|
||||||
|
|
||||||
|
### SKILL.md(技能实现)
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
---
|
||||||
|
description: 一句话说明该技能的用途(Claude 用此判断何时触发该技能)
|
||||||
|
---
|
||||||
|
|
||||||
|
技能的具体指令内容…
|
||||||
|
```
|
||||||
|
|
||||||
|
`description` 字段是触发判据,务必精确描述使用场景,避免与其他技能产生歧义。
|
||||||
|
|
||||||
|
## 新增插件流程
|
||||||
|
|
||||||
|
1. 在 `plugins/` 下创建目录 `plugins/<plugin-name>/`
|
||||||
|
2. 创建 `plugins/<plugin-name>/.claude-plugin/plugin.json`
|
||||||
|
3. 在 `plugins/<plugin-name>/skills/<skill-name>/SKILL.md` 编写技能
|
||||||
|
4. 在 `.claude-plugin/marketplace.json` 的 `plugins` 数组中追加该插件条目
|
||||||
|
|
||||||
|
## 已发布插件
|
||||||
|
|
||||||
|
| 插件 | 技能 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| `huanxi` | `/huanxi-shared` `/huanxi-report` `/huanxi-leader` `/huanxi-task` `/huanxi-issue` `/huanxi-meeting` `/huanxi-org` | 寰汐 · **个人端**工作流,自动配置个人端 MCP(`hxp_` Token,员工在个人中心自助生成) |
|
||||||
|
| `huanxi-admin` | `/huanxi-admin-shared` `/huanxi-admin-report` `/huanxi-admin-module` `/huanxi-admin-ops` | 寰汐 · **管理端**工作流,自动配置管理端 MCP(`hxa_` Token,由后台管理员发放)。普通员工无需安装 |
|
||||||
|
| `memcore` | `/memory-sync` `/memory-update` `/memory-lint` `/memcore-shared`(内部 include) | 项目记忆体系核心引擎 |
|
||||||
|
| `obsidian` | `/obsidian` `/obsidian-bases` `/obsidian-canvas` `/obsidian-daily` `/obsidian-history` `/obsidian-meta` `/obsidian-plugins` `/obsidian-search` `/obsidian-tasks` `/obsidian-workflow-pkm` | Obsidian 知识库完整工作流(10 个技能;对标 kepano/obsidian-skills 31.8k★ 与 AgriciDaniel/claude-obsidian) |
|
||||||
|
|
||||||
|
> **两个 huanxi 插件当前只在 `huanxi-v2` 分支上,未合 `main`。**
|
||||||
|
> 它们描述的是寰汐 **v2** 的 MCP 工具,而插件里配置的域名此刻跑的还是 **v1**——合进 main
|
||||||
|
> 会通过自动更新推给已安装用户,他们的技能会去调 v1 上不存在的工具(`dict_get` /
|
||||||
|
> `issue_create` / `meeting_query` 等),表现为一连串「工具不存在」。
|
||||||
|
>
|
||||||
|
> **合并前置条件**:v2 已部署到插件 `mcpServers` 里配置的那个域名。
|
||||||
|
> 源码单一真相在寰汐仓库 `skills/`,同步方式:`python skills/sync_marketplace.py`。
|
||||||
|
|
||||||
|
### memcore 技能调用关系
|
||||||
|
|
||||||
|
```
|
||||||
|
/memcore-shared ← 内部 include(路径锁定 + 全局常量 + PROJECT_DIR 解析),不由用户直接调用
|
||||||
|
↑ Read 引用
|
||||||
|
│
|
||||||
|
/memory-sync ← 总编排(11 phases),调用下面两个技能
|
||||||
|
├── /memory-update ← 增量写入,可独立执行
|
||||||
|
└── /memory-lint ← 健康校验,可独立执行
|
||||||
|
```
|
||||||
|
|
||||||
|
**关键常量统一来源**(修改 memcore-shared 一处即可全局生效):
|
||||||
|
- `SYNTHESIS_THRESHOLD` = 3(synthesis 升级跨文件引用阈值)
|
||||||
|
- `LINT_STALE_MIN_DAYS` = 7(过期检测最低观察窗口,不足则跳过)
|
||||||
|
- `LINT_HIGH_VELOCITY` = 1.0 次/天 / `LINT_LOW_VELOCITY` = 0.3 次/天(过期检测速度分档:全仓库提交速度 ≥ 高值 ERROR,≥ 低值 WARN)
|
||||||
|
- `LINT_STALE_ABSOLUTE_DAYS` = 180(低速仓库的过期绝对兜底天数)
|
||||||
|
- `MULTI_HOST_WARN_DAYS` = 7(多机不同步预警阈值)
|
||||||
|
|
||||||
|
## 记忆体系(会话启动必读)
|
||||||
|
|
||||||
|
> 每次新会话或长会话压缩后,必须先读 `MEMORY.md` 索引再按需加载文件。代码与记忆冲突 → 以代码为准并更新记忆。
|
||||||
|
|
||||||
|
### 读取流程
|
||||||
|
|
||||||
|
1. `cat .claude/memory/MEMORY.md` 获取清单
|
||||||
|
2. **必读**(type=`project`/`feedback`):decisions.md / project_overview.md / feedback_plugin_dev.md
|
||||||
|
3. **按需**(type=`lint`):lint_report.md(仅查看 NEED-HUMAN 待处理项时读)
|
||||||
|
|
||||||
|
### 记忆目录骨架
|
||||||
|
|
||||||
|
```
|
||||||
|
.claude/memory/
|
||||||
|
├── MEMORY.md # 索引(入口)
|
||||||
|
├── decisions.md # 关键架构决策(含 memcore-shared/lint_report 保活/Base commit 兜底/obsidian 社区对标审查/memory-lint 速度分档过期检测等 13 项)
|
||||||
|
├── project_overview.md # 项目定位与结构(huanxi/memcore/obsidian 10 技能 已发布插件)
|
||||||
|
├── feedback_plugin_dev.md # 插件开发协作规范(含 MCP docstring 单一真相、签名变更全量扫描)
|
||||||
|
└── lint_report.md # 记忆健康检查报告(按需)
|
||||||
|
```
|
||||||
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "example-skill",
|
|
||||||
"description": "示例插件",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"author": {
|
|
||||||
"name": "蚁熊团队"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
---
|
|
||||||
description: 示例技能,用于验证 marketplace 安装流程是否正常
|
|
||||||
---
|
|
||||||
|
|
||||||
这是一个示例技能。当你成功安装并调用它时,说明你的公司内部 marketplace 已经配置成功。
|
|
||||||
|
|
||||||
请回复:marketplace 安装验证通过!
|
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"name": "huanxi-admin",
|
||||||
|
"description": "寰汐企业管理系统 · 管理端。全量视角,含汇报盘点、模块与成员配置、运维简报三个工作流技能。需要管理员发放的 hxa_ Token,高危操作(账号启停/提权/删除)不在此端点。",
|
||||||
|
"author": {
|
||||||
|
"name": "姜顺志"
|
||||||
|
},
|
||||||
|
"userConfig": {
|
||||||
|
"token": {
|
||||||
|
"type": "string",
|
||||||
|
"title": "寰汐 Admin Token",
|
||||||
|
"description": "由后台管理员在「系统 → Admin Token」生成,hxa_ 前缀;普通员工无需安装本插件",
|
||||||
|
"sensitive": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mcpServers": {
|
||||||
|
"huanxi-admin": {
|
||||||
|
"type": "http",
|
||||||
|
"url": "https://huanxi.office.yixiong-tech.com/admin-mcp/",
|
||||||
|
"headers": {
|
||||||
|
"Authorization": "Bearer ${user_config.token}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
---
|
||||||
|
name: huanxi-admin-module
|
||||||
|
description: "寰汐管理端模块与任务:全量查模块任务、建模块、改模块状态、整组配置成员、跨模块任务管理。当用户说「建个模块」「把某人加进模块」「全公司任务情况」「关掉这个模块」时使用。"
|
||||||
|
---
|
||||||
|
|
||||||
|
# 寰汐管理端 · 模块与任务
|
||||||
|
|
||||||
|
**前置:先读 `huanxi-admin-shared`。**
|
||||||
|
|
||||||
|
全量视角,不受「我参不参与」过滤。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 查
|
||||||
|
|
||||||
|
```
|
||||||
|
module_query(status_category?, q?) 全量模块,带负责人与成员数
|
||||||
|
module_get(module_ids=[...]) 详情含成员名单与各自角色
|
||||||
|
task_query(module_ids?, assignee_ids?, status_category?, priority?, q?)
|
||||||
|
task_get(task_ids=[...])
|
||||||
|
```
|
||||||
|
|
||||||
|
过滤维度都收列表,一次查多个比循环调用好。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 建模块
|
||||||
|
|
||||||
|
```
|
||||||
|
module_create(name, type_id, leader_user_id, description?)
|
||||||
|
```
|
||||||
|
|
||||||
|
`type_id` 先 `dict_get(kinds=["module_types"])` 取,`leader_user_id` 用 `user_query` 取。
|
||||||
|
创建后会自动生成该模块的「杂记」任务,承载不值得单独建任务的零散工作。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 改模块
|
||||||
|
|
||||||
|
```
|
||||||
|
module_update(module_id, name?, description?, status_option_id?)
|
||||||
|
```
|
||||||
|
|
||||||
|
⏸ **切到「已取消」有副作用**:级联取消该模块下全部未完成任务,并给成员发飞书通知。
|
||||||
|
这不是可撤销的操作,确认清楚再调。
|
||||||
|
|
||||||
|
模块**删除**不在本端点——那是纠错场景(建错了),需要在后台确认。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 成员整组配置
|
||||||
|
|
||||||
|
```
|
||||||
|
module_set_members(module_id, members=[{user_id, role}, ...])
|
||||||
|
```
|
||||||
|
|
||||||
|
⏸ **替换语义**:不在名单里的现有成员**会被移除**。正确做法:
|
||||||
|
|
||||||
|
```
|
||||||
|
1. module_get 拿现有名单
|
||||||
|
2. 在现有名单基础上做改动(加人/改角色/去人)
|
||||||
|
3. 把完整的最终名单整组传回
|
||||||
|
4. 先把「改完会变成谁、谁会被移除」说给用户听,确认后再调
|
||||||
|
```
|
||||||
|
|
||||||
|
返回的 `added` / `role_changed` / `removed` 三组是本次实际发生的变更,
|
||||||
|
用它向用户复述结果。
|
||||||
|
|
||||||
|
一人一模块只能有一个角色(`leader` / `reviewer` / `member`)。新加入的成员会收到飞书通知。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 任务
|
||||||
|
|
||||||
|
```
|
||||||
|
task_create(module_id, tasks=[{title, ...}])
|
||||||
|
task_update(updates=[{id, status_option_id?, progress?, priority?, ...}])
|
||||||
|
task_set_assignees(task_id, user_ids=[...])
|
||||||
|
```
|
||||||
|
|
||||||
|
- 改状态先 `dict_get` 取 task 类型的 `status_option_id`
|
||||||
|
- 状态与进度**有联动,只传一个就够**(进度 100 自动完成;已完成的调低进度自动回落)
|
||||||
|
- 非叶子任务(`progress_readonly` 为 true)不能直接设进度,要改它的子任务
|
||||||
|
- `task_set_assignees` 是**替换**不是追加,同 `module_set_members` 的注意事项
|
||||||
|
|
||||||
|
任务删除与跨模块转移不在本端点。
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
---
|
||||||
|
name: huanxi-admin-ops
|
||||||
|
description: "寰汐管理端运维与内容:提交运维简报、查公告与自动报告、全量查会议与议题。当用户说「提交运维简报」「本周系统周报」「看看有哪些议题」时使用。"
|
||||||
|
---
|
||||||
|
|
||||||
|
# 寰汐管理端 · 运维与内容
|
||||||
|
|
||||||
|
**前置:先读 `huanxi-admin-shared`。**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 运维简报
|
||||||
|
|
||||||
|
```
|
||||||
|
ops_briefing_submit(content, iso_week?)
|
||||||
|
```
|
||||||
|
|
||||||
|
Markdown **原文存档,不经 AI 加工**——这是设计决策,简报的价值在于运维侧的原始记录,
|
||||||
|
加工会丢失细节。你可以帮用户组织语言,但要让他确认最终文本,不要自作主张改写后直接提交。
|
||||||
|
|
||||||
|
**同一 ISO 周重复提交是版本覆盖**:旧版本保留但不再是当前版本,公告表里那条发布记录
|
||||||
|
原地更新指向最新版。不传 `iso_week` 则用今天所在周。
|
||||||
|
|
||||||
|
⏸ 提交前把最终 Markdown 展示给用户确认。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 公告与自动报告
|
||||||
|
|
||||||
|
```
|
||||||
|
announcement_query(ids?, kind?, series_slug?, period_key?)
|
||||||
|
```
|
||||||
|
|
||||||
|
统一入口,覆盖系统周报、周度复盘、版本发布、运维简报、人工公告。
|
||||||
|
|
||||||
|
- 按生命周期分类查 → `kind`
|
||||||
|
- 某条内置报告的历次期次 → `series_slug`
|
||||||
|
- 具体某一期 → 加 `period_key`
|
||||||
|
|
||||||
|
报告按受众分档(全员/管理层/老板/本人),过滤在服务端完成——查不到某条不代表它不存在。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 会议与议题(只读)
|
||||||
|
|
||||||
|
```
|
||||||
|
meeting_query(scope="all", status_category?, series_ids?, module_ids?, tag_ids?)
|
||||||
|
issue_query(scope?, level?, status_category?, module_ids?, tag_ids?, q?)
|
||||||
|
```
|
||||||
|
|
||||||
|
管理身份可见全部议题,含标记为「仅管理层可见」的那些。
|
||||||
|
|
||||||
|
议题的写操作(建、记进展、关闭)**不在管理端**——那些应当由议题的当事人在个人端做,
|
||||||
|
管理端替他记进展会让决策链的「谁说的」失真。会议的写操作同理。
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
---
|
||||||
|
name: huanxi-admin-report
|
||||||
|
description: "寰汐管理端汇报盘点:谁没交日报、跨用户查汇报内容、团队负载看板。当用户说「全公司谁没交」「盘点汇报」「谁比较闲」「看看某人这周报了什么」时使用。"
|
||||||
|
---
|
||||||
|
|
||||||
|
# 寰汐管理端 · 汇报盘点
|
||||||
|
|
||||||
|
**前置:先读 `huanxi-admin-shared`。**
|
||||||
|
|
||||||
|
管理端最高频的场景。个人端只能看自己和自己负责的模块,这里是全量视角。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 谁还没交(最常被问)
|
||||||
|
|
||||||
|
```
|
||||||
|
report_pending(module_ids?, date?)
|
||||||
|
```
|
||||||
|
|
||||||
|
只返回**存在未提交人员**的模块——交齐的模块不占篇幅。不传 `module_ids` 则盘点全部。
|
||||||
|
|
||||||
|
**统计口径含两条容易忽略的规则,不要自己重算**:
|
||||||
|
|
||||||
|
- 模块杂记不计入分母(那是零散工作的承载容器,不代表当天有汇报义务)
|
||||||
|
- 当日免报的人**整体排除**——既不算未提交也不算已提交,不是「视为已提交」。
|
||||||
|
这个区别很重要:算成已提交会污染「已交人数」,算成未提交会一直催不该催的人
|
||||||
|
|
||||||
|
回答用户时直接给名单和模块,不要把原始结构丢回去让他自己数。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 查汇报内容
|
||||||
|
|
||||||
|
```
|
||||||
|
report_query(user_id?, module_id?, date_from?, date_to?) 员工日报条目
|
||||||
|
leader_report_query(user_id?, module_id?, date_from?, date_to?) 负责人日报
|
||||||
|
```
|
||||||
|
|
||||||
|
三个维度可任意组合,都不传即查今天全部。典型用法:
|
||||||
|
|
||||||
|
- 「张三这周报了什么」→ `report_query(user_id=..., date_from=周一, date_to=今天)`
|
||||||
|
- 「智能诊断模块上周的汇报」→ `report_query(module_id=..., date_from=..., date_to=...)`
|
||||||
|
|
||||||
|
**只读**。管理端不能替别人写或提交日报——那会让汇报失去「本人确认」的意义。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 负载看板
|
||||||
|
|
||||||
|
```
|
||||||
|
people_board()
|
||||||
|
```
|
||||||
|
|
||||||
|
按人聚合的跨模块任务负载,**含 0 任务的人**。回答「谁比较闲」「谁扛得太多」时用它,
|
||||||
|
比逐个 `task_query` 快得多。含 0 任务的人是有意的——那正是「谁完全没有负载」的答案。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 组合用法
|
||||||
|
|
||||||
|
「这周谁又没交日报、手上还压着多少活」这类问题,是 `report_pending` + `people_board`
|
||||||
|
两个结果的交叉,不需要额外工具:先拿未提交名单,再从看板里查这些人的任务数。
|
||||||
|
|
||||||
|
⏸ 涉及要不要点名、要不要发提醒时,先把名单给用户确认再说下一步——
|
||||||
|
盘点的产出是信息,催办是另一个决定。
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
---
|
||||||
|
name: huanxi-admin-shared
|
||||||
|
description: "寰汐管理端 MCP 共享基础:管理身份语义、高危操作边界、缓存策略、状态两层模型、人员与组织查询。所有 huanxi-admin-* 技能必须先读本文件。"
|
||||||
|
---
|
||||||
|
|
||||||
|
# 寰汐管理端 · 共享规则
|
||||||
|
|
||||||
|
所有 `huanxi-admin-*` 技能的**必读前置**。本技能族用的是管理端 Token(`hxa_`),
|
||||||
|
与个人端(`hxp_`)是两条独立通道,**工具集不同、视角不同**。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 你是以谁的身份在操作
|
||||||
|
|
||||||
|
管理端 Token 不绑定业务用户,执行时以 **Token 创建人的管理员身份**进行,
|
||||||
|
所有写操作按该身份记入审计。`whoami` 回答「我现在代表谁」。
|
||||||
|
|
||||||
|
创建人若已停用或被撤销后台权限,Token 会一并失效——这不是 bug,是随人事变动收回权限。
|
||||||
|
|
||||||
|
视角是**全量**的:模块、任务、汇报都不受「我参不参与」过滤。这是与个人端最大的差别,
|
||||||
|
也意味着你看到的东西大多不是你自己的,措辞上要注意(说「张三的日报」而不是「你的日报」)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 高危操作不在本端点
|
||||||
|
|
||||||
|
**账号启停、授予/撤销管理员与老板身份、通讯录全量同步、各类删除、状态选项与标签等
|
||||||
|
字典的写操作——全部走网页后台。**
|
||||||
|
|
||||||
|
理由不是「危险所以不给」,而是网页后台有确认弹窗与完整的操作上下文,MCP 通道没有
|
||||||
|
等价的「让人看清楚再点」环节。用户提这类需求时,直接告诉他去后台哪个页面,
|
||||||
|
**不要试图用别的工具绕过去**。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 参数以工具自身的说明为准
|
||||||
|
|
||||||
|
本文档与各技能都不重画参数表。参数名、必填项、取值范围以工具在 MCP 里注册的
|
||||||
|
docstring 为唯一真相;技能只描述调用顺序、ID 如何传递、哪里必须停下来等用户确认。
|
||||||
|
|
||||||
|
工具名在 Claude 客户端里带前缀 `mcp__huanxi-admin__`,其他平台按各自约定;
|
||||||
|
本文档统一写裸名。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 状态是可配置的两层模型
|
||||||
|
|
||||||
|
**不要硬编码状态字面量。** 分两层:
|
||||||
|
|
||||||
|
- `category`:四类固定语义 `not_started` / `in_progress` / `completed` / `cancelled`,用于**判断**
|
||||||
|
- `status_option_id`:具体状态项的 UUID,用于**写入**
|
||||||
|
|
||||||
|
改状态前先 `dict_get` 取对应 `entity_type`(module/task/issue/meeting,必须选对)
|
||||||
|
下的选项。字典本身的增删改不在本端点。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 人员与组织查询
|
||||||
|
|
||||||
|
```
|
||||||
|
user_query(q?, ids?, status?, has_backend_permission?)
|
||||||
|
org_tree()
|
||||||
|
```
|
||||||
|
|
||||||
|
`user_query` 比个人端多两个维度:`status`(active 在职 / observation 交接观察期 /
|
||||||
|
inactive 已停用)与 `has_backend_permission`。用于盘点「谁在观察期」「谁有后台权限」。
|
||||||
|
**只读**——账号启停与权限授予见上文。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 缓存
|
||||||
|
|
||||||
|
缓存根 `~/.claude/huanxi-cache/`,管理端用 `admin/` 子目录,与个人端隔离——
|
||||||
|
两边看到的模块范围不同,混用会把不该展示的内容展示出去。
|
||||||
|
|
||||||
|
| 类别 | 策略 |
|
||||||
|
|---|---|
|
||||||
|
| 身份 `admin/me.json` | 永久 |
|
||||||
|
| 配置字典 `dict/*.json` | **`dict_version` 比对** + 24h 兜底 |
|
||||||
|
| 组织 `admin/org-tree.json` `admin/all-modules.json` | 24h |
|
||||||
|
| 工作日 `dict/workdays.json` | 按日期 key 永久 |
|
||||||
|
| **业务数据**(汇报/任务/会议/议题) | **一律不缓存** |
|
||||||
|
|
||||||
|
字典为什么不能只靠 TTL:状态选项可能被停用,拿过期 ID 去写会**直接报错**——
|
||||||
|
失败方向是「操作失败」而非「看到旧数据」,值得比对一次。`dict_get` 的返回自带
|
||||||
|
`versions` 字段,连内容一起存即可,不要分两次调。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 全局约定
|
||||||
|
|
||||||
|
1. **有副作用的写操作先确认**:`module_set_members`(替换语义,会移除名单外的人)、
|
||||||
|
`module_update` 切「已取消」(级联取消该模块全部未完成任务并通知成员)。
|
||||||
|
2. **盘点类查询直接给结论**:用户问「谁没交」,答案是名单,不是让他自己看原始数据。
|
||||||
|
3. **先解析 ID 再操作**,不要凭名字猜。
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"name": "huanxi",
|
||||||
|
"description": "寰汐企业管理系统 · 个人端。以你本人的身份操作,权限与网页端一致。含日报、负责人日报、任务、议题、会议、组织检索六个工作流技能,并自动配置 MCP 连接。",
|
||||||
|
"author": {
|
||||||
|
"name": "姜顺志"
|
||||||
|
},
|
||||||
|
"userConfig": {
|
||||||
|
"token": {
|
||||||
|
"type": "string",
|
||||||
|
"title": "寰汐 Personal Token",
|
||||||
|
"description": "在寰汐「个人中心 → MCP Token 管理」自助生成,hxp_ 前缀",
|
||||||
|
"sensitive": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mcpServers": {
|
||||||
|
"huanxi": {
|
||||||
|
"type": "http",
|
||||||
|
"url": "https://huanxi.office.yixiong-tech.com/mcp/",
|
||||||
|
"headers": {
|
||||||
|
"Authorization": "Bearer ${user_config.token}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
---
|
||||||
|
name: huanxi-issue
|
||||||
|
description: "寰汐议题:提出议题、记录进展与决策链、调整分级、关闭。当用户说「提个议题」「这事记一下」「议题进展」「关掉这个议题」时使用。"
|
||||||
|
---
|
||||||
|
|
||||||
|
# 寰汐议题
|
||||||
|
|
||||||
|
**前置:先读 `huanxi-shared`。**
|
||||||
|
|
||||||
|
议题是「需要被讨论和跟进的事」,与任务的区别:任务有明确执行人和完成标准,
|
||||||
|
议题是待决策或待澄清的问题。**议题不需要审批**,任何非观察期用户直接建。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 决策链是核心
|
||||||
|
|
||||||
|
议题的价值不在「现在什么状态」,而在 `progress_logs` 记录的**怎么走到这一步的**。
|
||||||
|
`issue_get` 会带出完整决策链——起草结论、回顾判断时都应基于它,而不是只看当前状态。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 常用流程
|
||||||
|
|
||||||
|
```
|
||||||
|
提出 issue_create(issues=[{title, description?, level?, is_management_only?,
|
||||||
|
participant_ids?, module_ids?, tag_ids?}])
|
||||||
|
|
||||||
|
查 issue_query(scope="library"|"created"|"participating", level?, q?, ...)
|
||||||
|
issue_get(issue_ids=[...]) ← 含决策链
|
||||||
|
|
||||||
|
记进展 issue_record_progress(issue_id, content, meeting_id?)
|
||||||
|
↓ meeting_id 填了 = 这条结论是某次会上定的,会议与议题因此建立关联
|
||||||
|
↓ 不填 = 独立记录的一条进展
|
||||||
|
|
||||||
|
调分级 issue_update(updates=[{id, level}]) ← 变更会记入决策链
|
||||||
|
|
||||||
|
关闭 ⏸ 先与用户确认结论文字
|
||||||
|
issue_close(issue_id, conclusion) ← 结论必填
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 分级
|
||||||
|
|
||||||
|
`critical`(必须讨论)/ `watch`(需关注)/ `info`(信息同步)。这是**议题**的分级,
|
||||||
|
与任务的 `priority` 是两套取值,别混。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 几条容易踩的
|
||||||
|
|
||||||
|
- **关闭必须带结论,且要走 `issue_close`**。用 `issue_update` 改状态到「已完成」是另一条
|
||||||
|
路径,服务端会拒——「关了但没说为什么」不允许存在。
|
||||||
|
- **`is_management_only` 的议题只对管理层/创建人/参与人可见**,其余人在列表和详情里
|
||||||
|
都看不到(不是置灰,是不存在)。你查不到某条议题时,可能就是这个原因,不要断言它不存在。
|
||||||
|
- 编辑/关闭/重开/删除需要是**创建人或后台管理员**;记进展的范围更宽(创建人、参与人、
|
||||||
|
或该条挂在某会议下时该会议的主持人)。
|
||||||
|
- 默认隐藏已完成/已取消,要看全部传 `include_closed=true`。
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
---
|
||||||
|
name: huanxi-leader
|
||||||
|
description: "寰汐负责人日报:查看下属汇报情况、起草模块汇总、批量提交。当用户说「写负责人日报」「模块汇总」「我下属今天报了什么」「谁还没交」时使用。"
|
||||||
|
---
|
||||||
|
|
||||||
|
# 寰汐负责人日报
|
||||||
|
|
||||||
|
**前置:先读 `huanxi-shared`。**
|
||||||
|
|
||||||
|
与员工日报是两件事:员工日报是「我做了什么」的条目列表,负责人日报是「我这个模块
|
||||||
|
整体怎么样」的一段整体内容,**结构不同、接口不同,不要混用**。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 标准流程
|
||||||
|
|
||||||
|
```
|
||||||
|
Step 1 leader_report_get(date?, module_ids?)
|
||||||
|
↓ 一次拿全每个模块的:进度、我这条汇总的现状、**未提交成员名单**、
|
||||||
|
以及成员们当天各自报了什么(member_reports)
|
||||||
|
↓ 起草素材全在这里,不需要再调别的工具取
|
||||||
|
|
||||||
|
Step 2 基于 member_reports 归纳,为每个模块起草一段汇总
|
||||||
|
↓ 归纳而非罗列——把「三个人各自做了什么」写成「这个模块本周推进到哪」
|
||||||
|
↓ 有 pending_members 时提醒用户:这几位还没交,汇总可能不完整
|
||||||
|
|
||||||
|
Step 3 leader_report_save(entries=[{module_id, content}, ...])
|
||||||
|
|
||||||
|
Step 4 ⏸ 展示全部草稿,等待用户明确确认
|
||||||
|
|
||||||
|
Step 5 leader_report_submit(module_ids=[...])
|
||||||
|
↓ 不传 module_ids 则提交我负责的全部(自动跳过已提交与内容为空的)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 「谁还没交」
|
||||||
|
|
||||||
|
这是最高频的单点问题,`leader_report_get` 的 `pending_members` 直接回答,
|
||||||
|
不需要遍历成员逐个查。
|
||||||
|
|
||||||
|
想看全公司范围而不只是我负责的模块,那是管理端的 `report_pending`(见
|
||||||
|
`huanxi-admin`),个人端拿不到。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 撤回
|
||||||
|
|
||||||
|
```
|
||||||
|
leader_report_withdraw(module_ids=[...]) → 变回草稿,仅当天可撤
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 几条容易踩的
|
||||||
|
|
||||||
|
- **一个模块一条**:`module_id` 是主键的一部分,同一模块当天只有一条汇总,
|
||||||
|
重复保存是覆盖不是新增。
|
||||||
|
- **内容为空不能提交**:批量提交会静默跳过空内容的模块并在返回里说明,
|
||||||
|
不要以为「提交成功」就等于每个模块都交了——看返回的 `skipped_empty_count`。
|
||||||
|
- **不要前置校验下属是否交齐**:负责人日报不依赖员工日报的提交状态,
|
||||||
|
下属没交也能交自己的汇总(这是有意设计,避免一个人拖住整条链)。
|
||||||
|
- 只有 `leader` 角色的模块才会出现在这里;`reviewer` 不写负责人日报。
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
---
|
||||||
|
name: huanxi-meeting
|
||||||
|
description: "寰汐会议:查会议与议程、发起临时会议、维护议程条目、写会议纪要。当用户说「今天有什么会」「加个议程」「记会议纪要」「开个会」时使用。"
|
||||||
|
---
|
||||||
|
|
||||||
|
# 寰汐会议
|
||||||
|
|
||||||
|
**前置:先读 `huanxi-shared`。**
|
||||||
|
|
||||||
|
系统里「会议」是通用概念,晨会只是一条周期会议系列。周期会议的每一期由系统自动生成,
|
||||||
|
**不要用 `meeting_create` 去建周期会议的某一期**——那个工具只发起临时会议。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 常用流程
|
||||||
|
|
||||||
|
```
|
||||||
|
查 meeting_query(scope="participating"|"created"|"hosting"|"all")
|
||||||
|
↓ 与任务相反,**不隐藏已结束的会议**——翻历史记录是常见需求
|
||||||
|
meeting_get(meeting_ids=[...]) ← 含参会人、纪要、完整议程
|
||||||
|
|
||||||
|
发起临时会 meeting_create(title, scheduled_at?, attendee_ids?, room_id?)
|
||||||
|
↓ 发起人自动成为主持人与参会人
|
||||||
|
↓ room_id 先 dict_get 取 meeting_rooms
|
||||||
|
|
||||||
|
维护议程 agenda_write(meeting_id, create?, update?, delete_ids?, reorder_ids?)
|
||||||
|
↓ 一次调用可同时增、改、删、重排,返回操作后的完整议程
|
||||||
|
|
||||||
|
写纪要 meeting_minutes_save(meeting_id, content)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 权限看下发的布尔,不要自己推算
|
||||||
|
|
||||||
|
`meeting_query` / `meeting_get` 返回里带 `can_edit`、`can_claim`。**直接用它们**——
|
||||||
|
主持人、创建人、后台管理员的组合规则比看上去复杂(比如当前主持人不能自行改派给别人),
|
||||||
|
自己按规则推算必然与服务端不一致,表现为「按钮该显示却没显示」或「显示了点了报错」。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 会议结束后是只读的
|
||||||
|
|
||||||
|
`ended` 为 true 的会议,议程与纪要都不能再改,任何写入都会被拒。这是归档语义,
|
||||||
|
不是 bug——需要补记请让管理员在网页端「重新打开」该会议(有显式操作留痕)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 不在工具里的操作
|
||||||
|
|
||||||
|
认领/撤回/指定主持人、结束/重新打开会议**不在 MCP**。这些是一次点击的 UI 动作,
|
||||||
|
AI 代劳收益低而误操作代价高,请引导用户去网页端。
|
||||||
|
|
||||||
|
`agenda_write` 的 `reorder_ids` 要传**完整**的条目顺序列表,不是只传要移动的那几个。
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
---
|
||||||
|
name: huanxi-org
|
||||||
|
description: "寰汐组织与检索:查人、查部门、全局搜索、按标签反查、团队任务看板。当用户说「XX是谁」「这个部门有哪些人」「搜一下」「团队在忙什么」时使用。"
|
||||||
|
---
|
||||||
|
|
||||||
|
# 寰汐组织与检索
|
||||||
|
|
||||||
|
**前置:先读 `huanxi-shared`。**
|
||||||
|
|
||||||
|
本技能主要有两个职责:**把名字解析成 ID** 供其他技能使用,以及**维护缓存**。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 解析 ID
|
||||||
|
|
||||||
|
几乎所有写操作都要 ID。顺序是:先读缓存,未命中再调工具,拿到后写回缓存。
|
||||||
|
|
||||||
|
```
|
||||||
|
user_search(q="冯普") 姓名模糊搜 → 拿 id
|
||||||
|
user_search(ids=[...]) 已知 id 批量取详情
|
||||||
|
module_query(role?) 我参与的模块(带 my_role)
|
||||||
|
org_tree() 组织架构树,含各部门成员姓名
|
||||||
|
```
|
||||||
|
|
||||||
|
`user_search` 结果里标注了 `offboarding`(离职观察期,不宜再派新活)与 `inactive`
|
||||||
|
(已停用)——把人派给这两类之前先提醒用户。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 全局检索
|
||||||
|
|
||||||
|
```
|
||||||
|
search(q="关键词") 一次返回六组:任务/模块/用户/标签/会议/议题,各组带总数
|
||||||
|
```
|
||||||
|
|
||||||
|
不确定某个东西叫什么、在哪个模块时先用它定位,拿到 id 再调对应的 `*_get`。
|
||||||
|
比逐个域去 query 快得多。
|
||||||
|
|
||||||
|
```
|
||||||
|
tag_related(tag_id) 按标签反查五个域的关联内容
|
||||||
|
```
|
||||||
|
|
||||||
|
标签是**平级横切索引**,同一个标签可以贴在用户/模块/任务/会议/议题任何一种上。
|
||||||
|
这个工具回答「打了这个标签的所有东西都有哪些」。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 公告与报告
|
||||||
|
|
||||||
|
```
|
||||||
|
announcement_query(kind?, series_slug?, period_key?, ids?)
|
||||||
|
```
|
||||||
|
|
||||||
|
统一入口,覆盖系统周报、周度复盘、版本发布、运维简报、人工公告。
|
||||||
|
**只返回你有权看的**——报告按受众分档(全员/管理层/老板/本人),过滤在服务端完成,
|
||||||
|
查不到某条不代表它不存在。
|
||||||
|
|
||||||
|
想看某条内置报告的历次期次,传 `series_slug`;想要具体某期,加 `period_key`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 团队看板
|
||||||
|
|
||||||
|
```
|
||||||
|
people_board() 按人聚合的跨模块任务负载,**含 0 任务的人**
|
||||||
|
```
|
||||||
|
|
||||||
|
「我团队现在都在忙什么」「谁比较闲」用它,比逐个 `task_query` 高效得多。
|
||||||
|
含 0 任务的人是有意的——那正是「谁完全没有负载」这个问题的答案。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 缓存维护
|
||||||
|
|
||||||
|
本技能负责的三份缓存(详见 `huanxi-shared`):
|
||||||
|
|
||||||
|
| 文件 | 来源 | TTL |
|
||||||
|
|---|---|---|
|
||||||
|
| `personal/me.json` | `whoami` | 永久 |
|
||||||
|
| `personal/users.json` | `user_search` | 24h |
|
||||||
|
| `personal/my-modules.json` | `module_query` | 24h |
|
||||||
|
| `admin/org-tree.json` | `org_tree` | 24h |
|
||||||
|
|
||||||
|
用户说「刷新一下」「组织变了」时,删掉对应文件重新拉取即可。
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
---
|
||||||
|
name: huanxi-report
|
||||||
|
description: "寰汐员工日报:查看今日状态、填写并提交日报、撤回修改。当用户说「帮我写日报」「填日报」「提交日报」「今天要报什么」时使用。"
|
||||||
|
---
|
||||||
|
|
||||||
|
# 寰汐员工日报
|
||||||
|
|
||||||
|
**前置:先读 `huanxi-shared`(缓存策略、状态模型、确认约定)。**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 标准流程
|
||||||
|
|
||||||
|
```
|
||||||
|
Step 1 report_get_context(date?)
|
||||||
|
↓ 一次拿全:是否工作日、是否免报、整体状态、按模块分组的待汇报条目
|
||||||
|
↓ 非工作日 → 告知并询问是否仍要填(不中断)
|
||||||
|
↓ 已全部提交 → 转「修改已提交内容」分支
|
||||||
|
↓ 免报日 → 告知无需提交,询问是否仍要记录
|
||||||
|
|
||||||
|
Step 2 展示待汇报任务,引导用户逐条说今天做了什么
|
||||||
|
↓ 每条记住 task_id(后续提交要用)
|
||||||
|
↓ 用户说不清的任务,可用 task_get 补上下文,不要替他编
|
||||||
|
|
||||||
|
Step 3 (可选)润色
|
||||||
|
↓ 你自己润色即可,**不要找工具**——你就是那个语言模型
|
||||||
|
↓ 展示润色前后,让用户选
|
||||||
|
|
||||||
|
Step 4 report_save_draft(items=[...])
|
||||||
|
↓ 存草稿,此时还没提交
|
||||||
|
↓ 今天不报某条 → 该项加 dismissed=true;恢复 → restore=true
|
||||||
|
|
||||||
|
Step 5 ⏸ 展示完整初稿,等待用户明确确认
|
||||||
|
|
||||||
|
Step 6 report_submit(task_ids=[...])
|
||||||
|
↓ 只提交确认过的那些;不传 task_ids 则提交全部草稿
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 5 不可省略。** 写日报和交日报是两个决定,用户可能只想先存着。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 修改已提交内容
|
||||||
|
|
||||||
|
```
|
||||||
|
report_withdraw(task_ids=[...]) → 变回草稿
|
||||||
|
↓ 修改
|
||||||
|
report_save_draft(...)
|
||||||
|
↓ ⏸ 确认
|
||||||
|
report_submit(task_ids=[...])
|
||||||
|
```
|
||||||
|
|
||||||
|
**仅当天可撤回。** 隔天的日报已进入统计口径,撤回会被拒绝——这时应告诉用户去找管理员,
|
||||||
|
而不是反复重试。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 查历史
|
||||||
|
|
||||||
|
```
|
||||||
|
report_history(scope="module", module_id=...) 某模块某天全体成员报了什么
|
||||||
|
report_history(scope="task", task_id=..., date_from=..., date_to=...)
|
||||||
|
某个任务被谁在哪天报过什么
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 几条容易踩的
|
||||||
|
|
||||||
|
- **条目用 `task_id` 定位**,不是条目自身的 id。`report_get_context` 返回里的
|
||||||
|
`task_id` 就是后续 save/submit/withdraw 都要传的那个。
|
||||||
|
- **空内容不能提交**:服务端会拒。要么写点内容,要么标 `dismissed`。
|
||||||
|
- **模块杂记**(`is_module_misc`)承载零散工作,可以报也可以不报,但它**不计入
|
||||||
|
「未提交」统计**——用户只写了杂记不算完成当天汇报,提醒他还有别的任务没写。
|
||||||
|
- **`progress_update` 是任务进度**(0-100),不是完成度描述。填了它会真的改任务进度。
|
||||||
|
- 免报日(`is_exempt`)不产生未提交统计,也不必催。
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
---
|
||||||
|
name: huanxi-shared
|
||||||
|
description: "寰汐 MCP 共享基础:工具命名约定、本地缓存策略与过期检查、状态两层模型、全局确认约定。所有 huanxi-* 技能必须先读本文件。"
|
||||||
|
---
|
||||||
|
|
||||||
|
# 寰汐 MCP 共享规则
|
||||||
|
|
||||||
|
所有 `huanxi-*` 技能的**必读前置**。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一条最重要的约定:参数以工具自身的说明为准
|
||||||
|
|
||||||
|
**本文件与各技能文档都不重画参数表。** 每个工具的参数名、必填项、取值范围以它在 MCP
|
||||||
|
里注册的 docstring 为唯一真相;技能只描述**调用顺序、ID 如何传递、哪里必须停下来等用户
|
||||||
|
确认**。
|
||||||
|
|
||||||
|
> 这条不是洁癖。上一代技能包重画过参数表,结果字段名、枚举值、必填项四类漂移覆盖了
|
||||||
|
> 全部六个技能——用户侧表现为频繁的「参数缺失」报错。工具签名变了而文档没跟上,
|
||||||
|
> 是必然发生而非可能发生的事。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 工具命名
|
||||||
|
|
||||||
|
Claude Code / Claude Desktop 里工具名带前缀:`mcp__huanxi__task_query`(个人端)、
|
||||||
|
`mcp__huanxi-admin__report_pending`(管理端)。其他平台通常是裸名 `task_query`。
|
||||||
|
本文档统一写**裸名**,实际调用时按你所在平台的约定加前缀。
|
||||||
|
|
||||||
|
两个端点信任边界不同:
|
||||||
|
|
||||||
|
| | 个人端 | 管理端 |
|
||||||
|
|---|---|---|
|
||||||
|
| Token | `hxp_` 开头 | `hxa_` 开头 |
|
||||||
|
| 身份 | 你本人,权限与网页端一致 | Token 创建人的管理员身份 |
|
||||||
|
| 视角 | 我参与的 | 全量,不受角色过滤 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 状态是可配置的两层模型(v2 起)
|
||||||
|
|
||||||
|
**不要硬编码 `"in_progress"`、`"done"` 这类字面量。** 状态由后台配置,分两层:
|
||||||
|
|
||||||
|
- `category`:四类固定语义 `not_started` / `in_progress` / `completed` / `cancelled`,
|
||||||
|
用于**判断**(这条算不算完成)
|
||||||
|
- `status_option_id`:具体状态项的 UUID,用于**写入**
|
||||||
|
|
||||||
|
改任何实体状态前,先 `dict_get` 取该 `entity_type`(module/task/issue/meeting,**必须选对**)
|
||||||
|
下的选项,再传对应的 `status_option_id`。传旧值或错的 entity_type 会被直接拒绝。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 本地缓存
|
||||||
|
|
||||||
|
缓存根目录 `~/.claude/huanxi-cache/`,**按通道隔离**:
|
||||||
|
|
||||||
|
```
|
||||||
|
~/.claude/huanxi-cache/
|
||||||
|
├── personal/ hxp_ 视角:me.json / my-modules.json / users.json
|
||||||
|
├── admin/ hxa_ 视角:org-tree.json / all-modules.json
|
||||||
|
└── dict/ 与身份无关的配置字典(两个通道共享)
|
||||||
|
```
|
||||||
|
|
||||||
|
隔离是必须的:管理端看到的是全量模块,个人端只有我参与的——混用会让你把不该展示的
|
||||||
|
东西展示给用户。
|
||||||
|
|
||||||
|
### 分层 TTL
|
||||||
|
|
||||||
|
| 类别 | 文件 | 策略 |
|
||||||
|
|---|---|---|
|
||||||
|
| 身份 | `personal/me.json` | 永久(身份不变) |
|
||||||
|
| **配置字典** | `dict/*.json` | **版本戳比对** + 24h 兜底 |
|
||||||
|
| 组织 | `users.json` / `org-tree.json` / `my-modules.json` | 24h |
|
||||||
|
| 日历 | `dict/workdays.json` | 按日期 key 永久(查过的不再查) |
|
||||||
|
| **业务数据** | 任务 / 日报 / 会议 / 议题 / 公告 | **一律不缓存** |
|
||||||
|
|
||||||
|
最后一行是硬规则。业务数据随时在变,缓存它只会让你把过期状态当成现状汇报给用户。
|
||||||
|
|
||||||
|
### 字典为什么要版本戳而不是只靠 TTL
|
||||||
|
|
||||||
|
其余缓存过期了最多是显示旧数据;字典不一样——状态选项可能被后台停用,你拿 24 小时前
|
||||||
|
的 ID 去改状态会**直接报错**。失败方向从「看到旧数据」变成「操作失败」,值得比对一次。
|
||||||
|
|
||||||
|
```
|
||||||
|
用字典前:
|
||||||
|
1. 调 dict_version() ← 极轻
|
||||||
|
2. 与 dict/versions.json 比对
|
||||||
|
3. 一致 → 用缓存;不一致 → 调 dict_get() 重取该类并更新缓存
|
||||||
|
```
|
||||||
|
|
||||||
|
`dict_get` 的返回里**自带 versions 字段**,直接连内容一起存下来即可——不要分两次调用,
|
||||||
|
那中间字典若被改动,你会把新内容配上旧版本戳缓存起来,之后再也不会刷新。
|
||||||
|
|
||||||
|
### 读缓存伪代码
|
||||||
|
|
||||||
|
```
|
||||||
|
read(file, ttl):
|
||||||
|
1. 读 ~/.claude/huanxi-cache/{file}
|
||||||
|
2. 文件不存在 → miss
|
||||||
|
3. age = now - cached_at
|
||||||
|
4. ttl 为永久 或 age < ttl → 返回 data
|
||||||
|
5. 否则 → miss
|
||||||
|
|
||||||
|
on_miss(tool, params):
|
||||||
|
1. 调用工具
|
||||||
|
2. 写入 { "cached_at": <ISO8601>, "data": <返回值> }
|
||||||
|
3. 返回 data
|
||||||
|
```
|
||||||
|
|
||||||
|
`workdays.json` 特殊:按日期 key 存 `{ "2026-08-06": true }`,已查过的日期不再查。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 全局约定
|
||||||
|
|
||||||
|
1. **提交类操作必须先确认**:`report_submit` / `leader_report_submit` / `issue_close` 等,
|
||||||
|
执行前把最终内容展示给用户、等到明确确认(「确认」「提交」「好的」)再调。
|
||||||
|
不要因为用户说了「帮我写日报」就把提交也一并做了——写和交是两个决定。
|
||||||
|
2. **删除与指派同样需要确认**:`task_set_assignees` 是**替换**语义(传空即清空),
|
||||||
|
不是追加;覆盖别人的名单前先说清楚会变成什么样。
|
||||||
|
3. **非工作日不强行中断**:`workday_check` 显示非工作日时告知用户并询问是否仍要填写,
|
||||||
|
不要直接拒绝——补填、调休上班都是真实场景。
|
||||||
|
4. **先解析 ID 再操作**:需要 module_id / user_id 的操作,先查缓存,未命中再调
|
||||||
|
`module_query` / `user_search`。不要凭名字猜 ID。
|
||||||
|
5. **批量优先**:工具的过滤维度基本都收列表,一次查多个比循环调用快得多,也更省上下文。
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
---
|
||||||
|
name: huanxi-task
|
||||||
|
description: "寰汐任务管理:查任务、建任务、改状态与进度、分配执行人、认领。当用户说「我有什么任务」「建个任务」「把这个标成完成」「派给谁」时使用。"
|
||||||
|
---
|
||||||
|
|
||||||
|
# 寰汐任务管理
|
||||||
|
|
||||||
|
**前置:先读 `huanxi-shared`(尤其「状态是可配置的两层模型」一节)。**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ID 传递链
|
||||||
|
|
||||||
|
任务操作几乎都是这条链,**中间结果要展示给用户**,不要一路闷头做到底:
|
||||||
|
|
||||||
|
```
|
||||||
|
module_query() → module_id
|
||||||
|
↓
|
||||||
|
task_query(module_ids=[...]) → task_id[] ← 展示给用户看
|
||||||
|
↓ ⏸ 用户指明改哪些
|
||||||
|
task_update(updates=[{id, ...}])
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 查
|
||||||
|
|
||||||
|
```
|
||||||
|
task_query(scope="mine") 我负责执行的(默认)
|
||||||
|
task_query(scope="all", module_ids=[...]) 某几个模块的全部任务
|
||||||
|
task_query(q="关键词") 标题模糊搜
|
||||||
|
task_get(task_ids=[...]) 详情:描述 + 层级路径
|
||||||
|
```
|
||||||
|
|
||||||
|
过滤维度都收列表,一次查多个模块比循环调用好。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 改状态与进度
|
||||||
|
|
||||||
|
**先 `dict_get` 取 task 类型的状态选项**,拿到 `status_option_id` 再传:
|
||||||
|
|
||||||
|
```
|
||||||
|
dict_get(kinds=["status_options"])
|
||||||
|
→ 筛 entity_type == "task"
|
||||||
|
→ 按 category 找到目标状态(not_started/in_progress/completed/cancelled)
|
||||||
|
→ 取它的 id
|
||||||
|
task_update(updates=[{id: 任务id, status_option_id: 状态id}])
|
||||||
|
```
|
||||||
|
|
||||||
|
状态与进度**有联动,只传一个就够**:进度设到 100 会自动转完成;已完成的任务把进度
|
||||||
|
调低会自动回落进行中。两个都传等于重复表达同一个意思。
|
||||||
|
|
||||||
|
**非叶子任务不能直接设进度**——返回里 `progress_readonly` 为 true 的那些,进度是子任务
|
||||||
|
聚合出来的,硬设会被拒绝。要推进它,去改它的子任务。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 建任务
|
||||||
|
|
||||||
|
```
|
||||||
|
task_create(module_id=..., tasks=[{title, description?, priority?, end_date?,
|
||||||
|
parent_id?, milestone_id?, assignee_ids?}])
|
||||||
|
```
|
||||||
|
|
||||||
|
- 建子任务传 `parent_id`,**最多三级**(任务 / 子任务 / 孙任务)
|
||||||
|
- 需要是该模块的成员或负责人
|
||||||
|
- `priority` 的取值以工具说明为准——**不要凭直觉写**,这个字段有 DB 级约束,写错直接报错
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 执行人
|
||||||
|
|
||||||
|
```
|
||||||
|
task_set_assignees(task_id=..., user_ids=[...]) 整组覆盖,传空即清空
|
||||||
|
task_claim(task_ids=[...], claim=true/false) 认领 / 取消认领(只动自己)
|
||||||
|
```
|
||||||
|
|
||||||
|
**`task_set_assignees` 是替换不是追加。** 想加一个人,要先 `task_get` 拿到现有名单,
|
||||||
|
把新人拼进去再整组传回——直接传一个人会把其余执行人全部踢掉。这是最容易出错的地方,
|
||||||
|
覆盖前把「改完会变成谁」说给用户听。
|
||||||
|
|
||||||
|
被指派的人若不是模块成员,会自动加入该模块;新增执行人会收到飞书通知。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 不在工具里的操作
|
||||||
|
|
||||||
|
删除任务、跨模块转移任务**不在 MCP**,请引导用户去网页端——这两个动作作用于整棵子树
|
||||||
|
且不可逆,需要看清楚影响范围再点。
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"name": "memcore",
|
||||||
|
"description": "Claude Code 记忆体系核心引擎。提供三层技能:memory-sync(全量同步编排)、memory-update(增量写入)、memory-lint(健康校验)。让项目记忆跨会话、跨机器保持一致。",
|
||||||
|
"author": {
|
||||||
|
"name": "姜顺志"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
---
|
||||||
|
name: memcore-shared
|
||||||
|
description: "memcore 内部共享约定:路径锁定、PROJECT_DIR 解析、synthesis 阈值常量。本技能仅供 /memory-sync、/memory-update、/memory-lint 内部 Read 引用,**不要由用户直接调用**。"
|
||||||
|
---
|
||||||
|
|
||||||
|
# memcore 共享约定
|
||||||
|
|
||||||
|
本文件是 `/memory-sync`、`/memory-update`、`/memory-lint` 三个技能的内部共享 include,**用户不会直接调用本技能**。三个主技能在 Phase 0 必须 Read 本文件载入约束。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚠ 路径锁定(强制约束)
|
||||||
|
|
||||||
|
### 唯一允许写入的路径
|
||||||
|
|
||||||
|
```
|
||||||
|
$PROJECT_DIR/.claude/memory/
|
||||||
|
```
|
||||||
|
|
||||||
|
即「会话当前工作目录下的 `.claude/memory/`」。
|
||||||
|
|
||||||
|
### 严禁写入的路径
|
||||||
|
|
||||||
|
| 路径 | 原因 |
|
||||||
|
|------|------|
|
||||||
|
| `~/.claude/projects/*/memory/` | 系统 auto memory 路径,仅 `/memory-sync` 的 Phase 10 统一同步 |
|
||||||
|
| `~/.claude/` 下任何其他目录 | 全局配置目录,禁止 memcore 触碰 |
|
||||||
|
| `$PROJECT_DIR` 之外任何路径 | 跨项目污染 |
|
||||||
|
|
||||||
|
### 不触发 auto memory 系统
|
||||||
|
|
||||||
|
memcore 子技能产生的所有写入**严禁**进入 auto memory 系统(`~/.claude/projects/{PROJECT_KEY}/memory/`)。该路径仅由 `/memory-sync` 的 Phase 10 一次性推送。
|
||||||
|
|
||||||
|
### 执行前断言(每个子技能必须执行)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
TARGET="$PROJECT_DIR/.claude/memory"
|
||||||
|
echo "目标路径:$TARGET"
|
||||||
|
case "$TARGET" in *"/.claude/projects/"*)
|
||||||
|
echo "ERROR: 路径含系统自动记忆目录,中止" && exit 1 ;;
|
||||||
|
esac
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## PROJECT_DIR 解析(跨平台统一)
|
||||||
|
|
||||||
|
`$PROJECT_DIR` 必须等于「shell 当前工作目录的 native 形式」:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Windows Git Bash / MSYS 优先取 -W(输出 C:/... 形式,便于 git -C 跨工具使用)
|
||||||
|
PROJECT_DIR="$(pwd -W 2>/dev/null || pwd)"
|
||||||
|
echo "PROJECT_DIR=$PROJECT_DIR"
|
||||||
|
```
|
||||||
|
|
||||||
|
理由:
|
||||||
|
- macOS / Linux:`pwd -W` 不存在,会 fallback 到 `pwd`,输出 `/Users/x/proj`
|
||||||
|
- Windows Git Bash:`pwd` 输出 `/c/Projects/x`,但 `git -C`、`cp` 跨 native 工具时更稳定的形式是 `C:/Projects/x`,正是 `pwd -W` 的输出
|
||||||
|
|
||||||
|
子技能内所有 `git -C "$PROJECT_DIR"`、`cp -p`、`stat` 等命令统一使用此 `$PROJECT_DIR`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 全局常量
|
||||||
|
|
||||||
|
| 常量 | 值 | 含义 | 使用位置 |
|
||||||
|
|------|----|------|---------|
|
||||||
|
| `SYNTHESIS_THRESHOLD` | `3` | 跨文件引用数 ≥ 此值即为 synthesis 升级候选 | `/memory-update` Phase 3C、`/memory-lint` Phase 3A & Phase 8 |
|
||||||
|
| `LINT_STALE_MIN_DAYS` | `7` | last_updated 不足此天数 → 跳过过期检测 | `/memory-lint` Phase 5 |
|
||||||
|
| `LINT_HIGH_VELOCITY` | `1.0`(次/天) | 全仓库提交速度 ≥ 此值 → 高频迭代区 → ERROR | `/memory-lint` Phase 5 |
|
||||||
|
| `LINT_LOW_VELOCITY` | `0.3`(次/天) | 全仓库提交速度 ≥ 此值 → 中频迭代区 → WARN | `/memory-lint` Phase 5 |
|
||||||
|
| `LINT_STALE_ABSOLUTE_DAYS` | `180` | 速度低于 `LINT_LOW_VELOCITY` 时的绝对兜底天数 → WARN | `/memory-lint` Phase 5 |
|
||||||
|
| `MULTI_HOST_WARN_DAYS` | `7` | 远程 vs 本地 mtime 差 ≥ 此天数 → 多机不同步警告 | `/memory-sync` Phase 3 |
|
||||||
|
|
||||||
|
子技能引用常量时使用上述名称,调整阈值只需修改本文件单一来源。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## REMOTE_MEMORY 路径推导
|
||||||
|
|
||||||
|
```bash
|
||||||
|
PROJECT_KEY="$(echo "$PROJECT_DIR" | sed 's#[:\\/]#-#g')"
|
||||||
|
REMOTE_MEMORY="$HOME/.claude/projects/$PROJECT_KEY/memory"
|
||||||
|
```
|
||||||
|
|
||||||
|
例:`C:\Projects\yixiong-claude-marketplace` → `C--Projects-yixiong-claude-marketplace`。
|
||||||
|
|
||||||
|
**该路径只允许 `/memory-sync` 的 Phase 3(读)和 Phase 10(写)触碰**,其他子技能不允许直接读写。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 引用约定
|
||||||
|
|
||||||
|
子技能开头标准引用句:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
**前置约束:先 Read `../memcore-shared/SKILL.md`(路径锁定 + 常量 + PROJECT_DIR 解析)**
|
||||||
|
```
|
||||||
|
|
||||||
|
读取后,子技能内所有出现的:
|
||||||
|
- `$PROJECT_DIR` → 按本文件「PROJECT_DIR 解析」一节获取
|
||||||
|
- `SYNTHESIS_THRESHOLD` 等常量 → 按本文件「全局常量」表
|
||||||
|
- 路径断言 → 按本文件「执行前断言」执行
|
||||||
@@ -0,0 +1,372 @@
|
|||||||
|
---
|
||||||
|
name: memory-lint
|
||||||
|
description: 检查本地记忆文件的健康状况。AUTO-FIX类问题直接修改本地文件,NEED-HUMAN类问题写入lint_report.md。唯一操作路径为 $PROJECT_DIR/.claude/memory/,严禁读写 ~/.claude/projects/*/memory/ 等项目目录外的任何路径,也不触发 auto memory 系统写入。可独立执行,也作为/memory-sync流程的一部分。调用命令: /memory-lint
|
||||||
|
---
|
||||||
|
|
||||||
|
# memory-lint
|
||||||
|
|
||||||
|
健康检查 `.claude/memory/`:AUTO-FIX 直修,NEED-HUMAN 写入 `lint_report.md`。
|
||||||
|
|
||||||
|
**前置约束:先 Read `../memcore-shared/SKILL.md`**(路径锁定 + 常量 + PROJECT_DIR 解析),其约束在本技能全程生效。
|
||||||
|
|
||||||
|
红线速记(详细见 memcore-shared):
|
||||||
|
- **唯一读写路径**:`$PROJECT_DIR/.claude/memory/`
|
||||||
|
- **严禁读写**:`~/.claude/projects/*/memory/`、`~/.claude/` 其他目录、项目外路径
|
||||||
|
- **执行前断言**:必须运行 memcore-shared 中的路径断言脚本
|
||||||
|
|
||||||
|
目录不存在 → 输出 `⚠ 未找到 .claude/memory/,建议先执行 /memory-sync` 并终止。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 0 — 读取状态
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cat "$PROJECT_DIR/.claude/memory/MEMORY.md"
|
||||||
|
ls "$PROJECT_DIR/.claude/memory/"*.md
|
||||||
|
```
|
||||||
|
|
||||||
|
提取 `$INDEX_FILES`(索引中的 `[filename.md]`)/ `$DISK_FILES`(磁盘文件)/ `$ANCHOR_COMMIT` / `$LAST_SYNCED`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 1-2 — 孤儿与幽灵检测
|
||||||
|
|
||||||
|
| Phase | 定义 | 级别 | AUTO-FIX |
|
||||||
|
|-------|------|------|---------|
|
||||||
|
| 1 孤儿 | 索引有 → 磁盘无 | ERROR | 从 MEMORY.md 删该条目 |
|
||||||
|
| 2 幽灵 | 磁盘有 → 索引无(仅排除 MEMORY.md / lint_report.md) | WARN | 补入索引(类型推断见下) |
|
||||||
|
|
||||||
|
幽灵类型推断(按优先级匹配):
|
||||||
|
- `synonyms.md`(精确匹配) → reference ← 新增:用户首次创建 synonyms.md 后会被自动登记,不再"隐形"
|
||||||
|
- `user_*` → user
|
||||||
|
- `project_*` 或 `decisions.md` → project
|
||||||
|
- `feedback*` → feedback
|
||||||
|
- `reference*` → reference
|
||||||
|
- `synthesis_*` → synthesis
|
||||||
|
- 其他默认 project
|
||||||
|
|
||||||
|
> **synonyms.md 自动登记说明**:用户在 `.claude/memory/` 中创建 `synonyms.md` 后,Phase 2 会自动将其登记入 MEMORY.md 索引(type=reference)。该文件由 Phase 4-pre 加载用于矛盾检测等价表。不要再把它从幽灵检测中排除。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 3 — 交叉引用完整性
|
||||||
|
|
||||||
|
### 3A 存在性检测 + 引用计数构建
|
||||||
|
|
||||||
|
扫描所有 `[[filename.md#section]]`,构建:
|
||||||
|
- **引用表** `源文件#源章节 → 目标文件#目标章节`
|
||||||
|
- **`$REF_COUNT`**:文件级被引用计数(按源文件去重,不含自引用)→ Phase 7 写入 MEMORY.md「引用」列
|
||||||
|
- **`$ITEM_REF_COUNT`**:`decisions.md` / `feedback*.md` 中每个 `## 条目`的被引用计数(按源文件去重)→ Phase 8 写入 lint_report.md,供 `/memory-update` 反向触发消费
|
||||||
|
|
||||||
|
| 情况 | 级别 | 动作 |
|
||||||
|
|------|------|-----|
|
||||||
|
| 目标文件不存在 | ERROR | NEED-HUMAN |
|
||||||
|
| 章节缺失 + 高相似度匹配(疑似重命名) | WARN | AUTO-FIX 更新引用 |
|
||||||
|
| 章节缺失 + 无相似项 | WARN | NEED-HUMAN |
|
||||||
|
|
||||||
|
### 3B 对称性检测(双链闭环)
|
||||||
|
|
||||||
|
复用 3A 引用表,对每条 `A#α → B#β` 检查 B 的 `## β` 是否含任意 `[[A` 引用(不要求精确章节)。
|
||||||
|
|
||||||
|
- 级别:WARN
|
||||||
|
- AUTO-FIX:B 的目标章节末尾追加 `**See Also:** [[A#α]]`
|
||||||
|
- 边界:`lint_report.md` 不参与;B 整文件无对 A 任何引用 → AUTO-FIX;B 有引用但不在目标章节 → 仅 WARN 不自动修改
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 4-6 — NEED-HUMAN 检测族
|
||||||
|
|
||||||
|
三类全部为 NEED-HUMAN,写入 lint_report.md 时**必须附带 3 问 yes/no checklist + 决策矩阵**(Phase 8 模板)。
|
||||||
|
|
||||||
|
### Phase 4-pre — 等价表述加载
|
||||||
|
|
||||||
|
矛盾检测前先加载 `$PROJECT_DIR/.claude/memory/synonyms.md`(可选文件)。
|
||||||
|
|
||||||
|
**加载方式**:
|
||||||
|
```bash
|
||||||
|
[ -f "$PROJECT_DIR/.claude/memory/synonyms.md" ] && \
|
||||||
|
grep -v "^#\|^---\|^$\|^name:\|^description:\|^type:" \
|
||||||
|
"$PROJECT_DIR/.claude/memory/synonyms.md"
|
||||||
|
# 输出每行一个等价组(逗号分隔),大小写不敏感,存入 $SYNONYMS_GROUPS
|
||||||
|
```
|
||||||
|
|
||||||
|
**synonyms.md 格式**(用户自行在项目内创建和维护):
|
||||||
|
```markdown
|
||||||
|
---
|
||||||
|
name: 等价表述清单
|
||||||
|
description: 矛盾检测等价词表,同组词视为相同概念
|
||||||
|
type: reference
|
||||||
|
---
|
||||||
|
|
||||||
|
# 等价表述清单
|
||||||
|
> 每行一组,逗号分隔,大小写不敏感
|
||||||
|
|
||||||
|
PostgreSQL, PG, Postgres, postgresql
|
||||||
|
JWT, JSON Web Token
|
||||||
|
Vue3, Vue 3, Vue 3.x
|
||||||
|
```
|
||||||
|
|
||||||
|
**判定规则**:检查两处描述中出现的技术术语是否属于同一等价组。若属同组 → 跳过,不纳入矛盾候选。
|
||||||
|
|
||||||
|
**无 synonyms.md 时**:仅检测直接数值/版本冲突(如 PostgreSQL 14 vs PostgreSQL 16),对措辞差异不报告。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Phase 4 内容矛盾
|
||||||
|
|
||||||
|
| 维度 | 检查 |
|
||||||
|
|------|------|
|
||||||
|
| decisions vs feedback | 决策与规范逻辑冲突 |
|
||||||
|
| decisions vs 架构文件 | 与 pom.xml / package.json / requirements.txt 实际依赖不一致 |
|
||||||
|
| 多 feedback 文件 | feedback.md 与 feedback_{topic}.md 重复或矛盾 |
|
||||||
|
| synthesis vs decisions | synthesis 结论与决策抵触 |
|
||||||
|
| 合并残留标记 | 文件含 `<!-- merge-conflict -->` 或 `<!-- remote-diverge -->` → WARN,NEED-HUMAN |
|
||||||
|
|
||||||
|
```bash
|
||||||
|
grep -rn "<!-- merge-conflict\|<!-- remote-diverge" "$PROJECT_DIR/.claude/memory/" --include="*.md"
|
||||||
|
```
|
||||||
|
|
||||||
|
合并标记的 NEED-HUMAN 条目模板:
|
||||||
|
- **位置**:`decisions.md → ## [合并待审] JWT 密钥安全`(`<!-- merge-conflict: 2026-05-10 -->`)
|
||||||
|
- **Checklist**:Q1 本地版本是否正确?Q2 远端版本是否有本地没有的有效信息?Q3 是否可合并为单一表述?
|
||||||
|
- **矩阵**:Q2 否 → 删除 `## [合并待审]` 段落和标记;Q2 是 + Q3 是 → 合并后删标记;Q3 否 → 保留两段但清除 HTML 注释
|
||||||
|
|
||||||
|
矛盾判定门槛(过 synonyms.md 等价检查后):
|
||||||
|
|
||||||
|
| 情况 | 处理 |
|
||||||
|
|------|------|
|
||||||
|
| 同主题,等价组内术语不同 | 跳过,不报告 |
|
||||||
|
| 同主题,结论相反(推荐 A vs 推荐 B) | WARN → NEED-HUMAN |
|
||||||
|
| 同主题,数值/版本直接冲突 | ERROR → NEED-HUMAN |
|
||||||
|
| 措辞不同,无直接逻辑冲突 | 跳过(宁漏报不误报) |
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cat "$PROJECT_DIR/pom.xml" || cat "$PROJECT_DIR/package.json" || cat "$PROJECT_DIR/requirements.txt"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 5 过期检测(速度分档)
|
||||||
|
|
||||||
|
不再用固定天数二级阈值,而是用「自 last_updated 以来的全仓库提交速度」判断过期风险的严重程度:高频迭代项目下 7 天未同步就可能已经漂移,低活跃项目下 30 天未动也可能仍然准确。阈值常量由 memcore-shared 定义。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# days_since: last_updated 距今天数
|
||||||
|
days_since=$(( ($(date +%s) - $(date -d "$last_updated" +%s)) / 86400 ))
|
||||||
|
|
||||||
|
# 不足 LINT_STALE_MIN_DAYS(默认 7 天)→ 跳过本文件的过期检测
|
||||||
|
if [ "$days_since" -lt 7 ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# commits_since: 全仓库自 last_updated 以来的提交数
|
||||||
|
commits_since=$(git -C "$PROJECT_DIR" log --oneline --since="$last_updated" -- . | wc -l)
|
||||||
|
|
||||||
|
# velocity: 提交速度(次/天)
|
||||||
|
velocity=$(echo "scale=2; $commits_since / $days_since" | bc)
|
||||||
|
```
|
||||||
|
|
||||||
|
分级(可由 MEMORY.md 头部 `<!-- lint-stale-warn: N -->` 覆盖 `LINT_STALE_MIN_DAYS`):
|
||||||
|
|
||||||
|
| 条件 | 级别 | 语义 |
|
||||||
|
|------|------|------|
|
||||||
|
| `velocity ≥ LINT_HIGH_VELOCITY`(默认 1.0) | ERROR | 高频迭代区,未同步几乎必然漂移 |
|
||||||
|
| `LINT_LOW_VELOCITY ≤ velocity < LINT_HIGH_VELOCITY`(默认 0.3~1.0) | WARN | 中频迭代,需人工确认是否漂移 |
|
||||||
|
| `velocity < LINT_LOW_VELOCITY` 且 `days_since < LINT_STALE_ABSOLUTE_DAYS`(默认 180) | — | 低活跃期,不判定过期 |
|
||||||
|
| `velocity < LINT_LOW_VELOCITY` 且 `days_since ≥ LINT_STALE_ABSOLUTE_DAYS` | WARN | 绝对兜底,防止彻底沉寂的记忆永不复查 |
|
||||||
|
|
||||||
|
### Phase 6 可推断内容污染
|
||||||
|
|
||||||
|
污染特征:大量文件路径、git 流水账、方法签名/SQL、可从依赖文件直读的版本号列表。
|
||||||
|
|
||||||
|
**边界(关键)**:架构层级("认证模块在 auth/,提供 JWT + OAuth2 双协议")**保留**;具体类名/方法/路径列表(`AuthFilter.java`)**删除**。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 7 — 执行 AUTO-FIX
|
||||||
|
|
||||||
|
按顺序修改本地文件:
|
||||||
|
1. MEMORY.md 移除孤儿(Phase 1)
|
||||||
|
2. MEMORY.md 补入幽灵(Phase 2)
|
||||||
|
3. 更新断链引用(Phase 3A 重命名匹配)
|
||||||
|
4. 追加反向链接(Phase 3B)
|
||||||
|
5. **刷新 MEMORY.md 索引「引用」列**(基于 `$REF_COUNT`):
|
||||||
|
- 表格统一 5 列:`| 文件 | 描述 | 类型 | 引用 | Commit |`
|
||||||
|
- 「引用」值 ≥3 加 `*`(如 `5*`)、<3 显示数字(如 `2`、`0`)
|
||||||
|
- **按引用次数倒序排列**(同次数按类型序:user → project → feedback → reference → synthesis → lint)
|
||||||
|
- 旧版 `## 核心枢纽节点` 段落自动删除(已合并到主表)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 8 — 生成 lint_report.md
|
||||||
|
|
||||||
|
### Phase 8-pre — NEED-HUMAN 稳定 ID 与已 resolved 保活
|
||||||
|
|
||||||
|
**目的**:用户在 lint_report.md 中给某个 NEED-HUMAN 条目添加 `<!-- resolved -->` 标记后,下次 lint 不再重复列出该条目(即使问题尚未真正修复,用户已表达"不处理"意图)。
|
||||||
|
|
||||||
|
**ID 生成规则**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 每个 NEED-HUMAN 条目计算稳定 ID(与执行时间无关,仅与"问题本体"有关)
|
||||||
|
# 输入:phase 编号 + 目标文件 + 目标章节 + 问题关键事实
|
||||||
|
# 输出:sha1 前 8 位
|
||||||
|
gen_id() {
|
||||||
|
printf '%s|%s|%s|%s' "$1" "$2" "$3" "$4" | sha1sum | cut -c1-8
|
||||||
|
}
|
||||||
|
|
||||||
|
# 示例:
|
||||||
|
# Phase 3A 断链:gen_id "3A" "decisions.md" "## 数据库选型" "[[synthesis_arch_xxx.md]]"
|
||||||
|
# Phase 4 矛盾:gen_id "4" "decisions.md+project_overview.md" "数据库选型" "PostgreSQL vs MySQL"
|
||||||
|
# Phase 5 过期:gen_id "5" "project_progress.md" "" "stale-86d"
|
||||||
|
# Phase 6 污染:gen_id "6" "project_overview.md" "" "line-N"
|
||||||
|
```
|
||||||
|
|
||||||
|
**已 resolved ID 提取**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
RESOLVED_IDS=$(grep -B1 "<!-- resolved" "$PROJECT_DIR/.claude/memory/lint_report.md" 2>/dev/null \
|
||||||
|
| grep -oE '<!-- id: [a-f0-9]{8}' | awk '{print $3}')
|
||||||
|
```
|
||||||
|
|
||||||
|
**生成新 NEED-HUMAN 时的过滤**:
|
||||||
|
|
||||||
|
```
|
||||||
|
对每个新检测出的 NEED-HUMAN 条目:
|
||||||
|
id = gen_id(phase, file, section, fact)
|
||||||
|
if id ∈ RESOLVED_IDS:
|
||||||
|
skip(用户已标记 resolved,本次不再列出)
|
||||||
|
else:
|
||||||
|
写入 lint_report.md,并在条目末尾附 `<!-- id: {id} -->`
|
||||||
|
```
|
||||||
|
|
||||||
|
**用户如何使用**:在 lint_report.md 中某个 NEED-HUMAN 条目末尾、`<!-- id: ... -->` 同段内,追加 `<!-- resolved -->`:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
### [WARN] 内容矛盾 — PostgreSQL vs MySQL
|
||||||
|
...
|
||||||
|
<!-- id: a1b2c3d4 -->
|
||||||
|
<!-- resolved: 2026-06-12, 决定保留两者作为历史对比 -->
|
||||||
|
```
|
||||||
|
|
||||||
|
下次 lint 跑到时,发现 id=a1b2c3d4 在 RESOLVED_IDS 中 → 整条跳过,不再骚扰。
|
||||||
|
|
||||||
|
### 报告模板
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
---
|
||||||
|
name: 记忆健康检查报告
|
||||||
|
description: memory-lint 最新一次执行的检查结果与待处理项
|
||||||
|
type: lint
|
||||||
|
last_updated: YYYY-MM-DD
|
||||||
|
---
|
||||||
|
|
||||||
|
# 记忆健康检查报告
|
||||||
|
|
||||||
|
> _执行时间: YYYY-MM-DD | Base commit: `HASH` | Last synced: DATE_
|
||||||
|
>
|
||||||
|
> **如何使用**:NEED-HUMAN 条目末尾有 `<!-- id: xxxxxxxx -->` 标记。处理完或决定不处理时,在同段追加 `<!-- resolved: DATE, 简要原因 -->`,下次 lint 该条目自动跳过。
|
||||||
|
|
||||||
|
## 健康概览
|
||||||
|
|
||||||
|
| 检查项 | AUTO-FIX | NEED-HUMAN(含已 resolved 跳过 N 项) |
|
||||||
|
|--------|---------|-----------|
|
||||||
|
| 1 孤儿 / 2 幽灵 / 3A 引用 / 3B 双链 | N / N / N / N | — / — / N / N |
|
||||||
|
| 4 矛盾 / 5 过期 / 6 污染 | — | N / N / N |
|
||||||
|
|
||||||
|
**AUTO-FIX 已执行 N 项 | NEED-HUMAN 新列出 N 项 | 历史已 resolved 跳过 M 项**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## AUTO-FIX 已执行清单
|
||||||
|
|
||||||
|
- [x] 移除孤儿:`synthesis_xxx.md`
|
||||||
|
- [x] 补入幽灵:`feedback_api.md`(feedback)
|
||||||
|
- [x] 自动登记 synonyms:`synonyms.md`(reference)
|
||||||
|
- [x] 更新断链:`[[feedback.md#API 认证规范]]` → `[[feedback.md#API 鉴权约束]]`
|
||||||
|
- [x] MEMORY.md「引用」列已刷新(22 文件,倒序)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 条目级高频引用 Top(供 /memory-update 消费)
|
||||||
|
|
||||||
|
跨 ≥`SYNTHESIS_THRESHOLD` 个不同源文件被引用的 decisions/feedback 条目(阈值见 memcore-shared,默认 3)。无候选时保留标题 + "无候选"。
|
||||||
|
|
||||||
|
| 条目 | 跨文件次数 | 建议 |
|
||||||
|
|------|----------|------|
|
||||||
|
| `architecture_decisions.md#动态API normalizeParams 类型转型` | 4 | 升级为 synthesis_arch_dynamic_api.md |
|
||||||
|
| `feedback_code_quality.md#JWT 密钥安全` | 3 | 升级为 synthesis_security_jwt.md |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## NEED-HUMAN 待处理清单
|
||||||
|
|
||||||
|
每项附 3 问 yes/no checklist + 决策矩阵,避免模糊判断。
|
||||||
|
|
||||||
|
### [ERROR] 引用断链 — 目标文件不存在
|
||||||
|
|
||||||
|
- **位置**:`decisions.md → ## 数据库选型` → `[[synthesis_arch_xxx.md]]`
|
||||||
|
- **Checklist**:
|
||||||
|
- Q1:内容是否真实归档过?
|
||||||
|
- Q2:git history 能否找到删除/重命名证据?
|
||||||
|
- Q3:该引用是「锦上添花」还是「核心支撑」?
|
||||||
|
- **矩阵**:Q1+Q2 = 是 → 恢复文件;Q1 是 + Q2 否 → 重新归档;Q1 否 → 删引用;Q3 核心 → 必须二选一不允许保留断链
|
||||||
|
<!-- id: a1b2c3d4 -->
|
||||||
|
|
||||||
|
### [WARN] 内容矛盾 — 跨文件表述冲突
|
||||||
|
|
||||||
|
- **A**:`decisions.md → ## 数据库选型` PostgreSQL(last_updated: 2026-04-22)
|
||||||
|
- **B**:`project_overview.md → ## 技术栈` MySQL 8.0(last_updated: 2026-02-10)
|
||||||
|
- **Checklist**:
|
||||||
|
- Q1:当前代码/配置(pom.xml / docker-compose)实际指向?
|
||||||
|
- Q2:另一方是「计划未实施」还是「过时记录」?
|
||||||
|
- Q3:近 30 天 git log 有迁移提交?
|
||||||
|
- **矩阵**:Q1 答案 = 当前权威;Q2 过时 → 直接更新另一方;Q2 计划 → 末尾标 `**Status:** planned, target HASH`;Q3 有迁移 → 用迁移时间反推
|
||||||
|
<!-- id: e5f6a7b8 -->
|
||||||
|
|
||||||
|
### [WARN] 过期记忆 — 提交速度分级超阈值
|
||||||
|
|
||||||
|
- **文件**:`project_progress.md`(last_updated: 2026-01-15,过期 86 天,同期 62 次提交,速度 0.72/天 → 中频区 WARN)
|
||||||
|
- **Checklist**:
|
||||||
|
- Q1:覆盖领域在此期间是否有里程碑变更?(速度越高,越可能有)
|
||||||
|
- Q2:现有内容是否仍可指导决策?
|
||||||
|
- Q3:是否有继任 synthesis_* 已分担其职责?
|
||||||
|
- **矩阵**:Q1 是 + Q2 否 → 触发 `/memory-update`;Q2 是(仅日期老、速度低)→ 仅刷新 `last_updated`;Q3 是 → 归档/删除,索引指向继任者
|
||||||
|
<!-- id: c9d0e1f2 -->
|
||||||
|
|
||||||
|
### [WARN] 可推断内容污染 — 疑似从代码可 grep 的明细
|
||||||
|
|
||||||
|
- **文件**:`project_overview.md` 第 N 行(疑似具体类/路径列表)
|
||||||
|
- **Checklist**:
|
||||||
|
- Q1:能否通过 grep / find / git log 直接还原?
|
||||||
|
- Q2:删除后剩余内容是否仍清晰描述「为什么/约束/边界」?
|
||||||
|
- Q3:是否承载 git history 抓不到的语义?(如「曾选 A 后改 B 因 X」)
|
||||||
|
- **矩阵**:Q1+Q2 = 是 + Q3 否 → 安全删除;Q3 是 → 改写为决策格式迁到 decisions.md(保留 Why);Q2 否 → 保留架构层级描述但删具体路径
|
||||||
|
<!-- id: 3a4b5c6d -->
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 9 — 输出摘要
|
||||||
|
|
||||||
|
被 `/memory-sync` 调用:
|
||||||
|
```
|
||||||
|
🔍 memory-lint:AUTO-FIX N 项,NEED-HUMAN N 项(详见 lint_report.md)
|
||||||
|
```
|
||||||
|
|
||||||
|
独立调用:扩展输出已修复 / 待处理清单 + 报告路径;全通过则 `✅ 记忆体系健康,已更新执行时间`。
|
||||||
|
|
||||||
|
发现矛盾候选且 `synonyms.md` 不存在时,额外输出:
|
||||||
|
```
|
||||||
|
💡 创建 .claude/memory/synonyms.md 可将等价术语(如 "PostgreSQL, PG")预先排除出矛盾检测,降低误报率。
|
||||||
|
```
|
||||||
|
|
||||||
|
每次执行必须更新 lint_report.md(即使全通过也刷新执行时间)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 执行约束
|
||||||
|
|
||||||
|
1. **AUTO-FIX 边界严格** — 只修结构性错误(孤儿、幽灵、断链、双链),不改业务内容
|
||||||
|
2. **NEED-HUMAN 完整记录** — 每项含 checklist + 决策矩阵 + 末尾 `<!-- id: xxxxxxxx -->` 稳定 ID
|
||||||
|
3. **resolved 保活** — Phase 8-pre 提取旧 lint_report.md 中带 `<!-- resolved -->` 的 ID 集合,新报告中同 ID 条目跳过;用户标记 resolved 即长效免打扰
|
||||||
|
4. **矛盾检测先过等价表** — 先加载 `synonyms.md` 再判矛盾;措辞不一致 ≠ 矛盾,宁漏报不误报;项目可在 `.claude/memory/synonyms.md` 维护等价组降低误报率(synonyms.md 由 Phase 2 自动登记入 MEMORY.md)
|
||||||
|
5. **污染检测边界**(重申)— 架构层级保留 / 具体类名路径删除
|
||||||
|
6. **被调用静默返回** — `/memory-sync` 内 Phase 9 不输出收尾
|
||||||
@@ -0,0 +1,262 @@
|
|||||||
|
---
|
||||||
|
name: memory-sync
|
||||||
|
description: 项目记忆体系完整同步。Git检查→远程补充本地→增量更新记忆文件→lint收敛→CLAUDE.md注入→本地权威推送远程。以本地.claude/memory/为唯一权威基准。调用命令: /memory-sync
|
||||||
|
---
|
||||||
|
|
||||||
|
# memory-sync
|
||||||
|
|
||||||
|
记忆体系完整同步周期。**本地 `.claude/memory/` 是唯一权威**,远程为镜像。
|
||||||
|
|
||||||
|
**前置约束:先 Read `../memcore-shared/SKILL.md`**(路径锁定 + 常量定义 + PROJECT_DIR 解析 + REMOTE_MEMORY 推导),其约束在本技能全程生效。本技能的 Phase 3(读远程)与 Phase 10(写远程)是**全 memcore 中唯二**允许触碰 `$REMOTE_MEMORY` 的环节。
|
||||||
|
|
||||||
|
```
|
||||||
|
Phase 0 Git 准备(冲突解决优先 → 普通变更提交)
|
||||||
|
Phase 1-4 前置(锚点 + 远程→本地补充 + 多机/并发检测 + diff)
|
||||||
|
Phase 5 /memory-update(本地写入)
|
||||||
|
Phase 6 /memory-lint(收敛)
|
||||||
|
Phase 7-9 CLAUDE.md 维护与记忆引导区块注入
|
||||||
|
Phase 10 本地 → 远程权威推送
|
||||||
|
Phase 11 完成报告
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 0 — Git 准备(冲突解决 → 变更提交)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git -C "$PROJECT_DIR" status --short
|
||||||
|
```
|
||||||
|
|
||||||
|
非 git 仓库 → 跳过 Phase 0,commit 字段填 `N/A`。
|
||||||
|
|
||||||
|
### Step 1 — 冲突优先检测(必须先于 commit)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git -C "$PROJECT_DIR" diff --name-only --diff-filter=U -- .claude/memory/
|
||||||
|
```
|
||||||
|
|
||||||
|
有冲突文件(输出非空)→ 执行**语义合并**(见规则表)→ `git add .claude/memory/ && git commit -m "chore: resolve memory merge conflicts"` → 更新 `$HEAD_HASH` → 跳至 Phase 1。
|
||||||
|
|
||||||
|
无冲突 → 继续 Step 2。
|
||||||
|
|
||||||
|
**语义合并规则**(冲突文件逐个处理):
|
||||||
|
|
||||||
|
| 冲突类型 | 处理方式 |
|
||||||
|
|---------|---------|
|
||||||
|
| frontmatter `last_updated` | 取两者较新日期 |
|
||||||
|
| frontmatter `commit` | 取 HEAD 侧(本地权威) |
|
||||||
|
| `## Section` 块 — 两边内容相同 | 保留一份 |
|
||||||
|
| `## Section` 块 — 仅本地有 | 保留 |
|
||||||
|
| `## Section` 块 — 仅远端有 | 追加到文件末尾 |
|
||||||
|
| `## Section` 块 — 两边均有且不同 | 本地原位保留,远端追加为 `## [合并待审] Section`,标注 `<!-- merge-conflict: YYYY-MM-DD -->` |
|
||||||
|
| `MEMORY.md` 索引 | 取本地版本,不尝试合并;Phase 6 lint 重建 |
|
||||||
|
| `user_profile.md` / `synthesis_*.md` | 整文件不自动合并,在文件头追加 `<!-- merge-conflict: YYYY-MM-DD, NEED-HUMAN -->` |
|
||||||
|
|
||||||
|
合并前备份:
|
||||||
|
```bash
|
||||||
|
cp "$conflicted_file" "${conflicted_file%.md}.conflict_backup_$(git rev-parse --short HEAD).md"
|
||||||
|
```
|
||||||
|
备份文件加入 `.gitignore`(`*.conflict_backup_*.md`),不提交。
|
||||||
|
|
||||||
|
### Step 2 — 普通变更提交
|
||||||
|
|
||||||
|
有未提交变更(非冲突)→ 展示文件、询问 commit message(默认 `chore: sync before memory update`)→ `git add .claude/memory/ && git commit -m "<msg>"` → 记新 hash。
|
||||||
|
|
||||||
|
干净工作区 → `git rev-parse --short HEAD` → `$HEAD_HASH`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 1 — 远程路径
|
||||||
|
|
||||||
|
```
|
||||||
|
$REMOTE_MEMORY = ~/.claude/projects/{PROJECT_KEY}/memory/
|
||||||
|
PROJECT_KEY = $PROJECT_DIR 中所有 `:` `\` `/` 替换为 `-`
|
||||||
|
例:C:\Users\skyji\work\api → C--Users-skyji-work-api
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 2 — 本地目录初始化
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ls "$PROJECT_DIR/.claude/memory/" 2>/dev/null
|
||||||
|
```
|
||||||
|
|
||||||
|
- 不存在 → `mkdir -p` 后跳到 Phase 3(全量从远程拉,跳过差量)
|
||||||
|
- 存在 → 提取 `MEMORY.md` 头部 `Base commit: \`HASH\`` → `$ANCHOR_COMMIT`(无则空 = 全量)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 3 — 远程 → 本地(只补不覆)
|
||||||
|
|
||||||
|
> **方向锁定**:本 Phase 唯一操作是从 `~/.claude/projects/{PROJECT_KEY}/memory/` 补充到 `$PROJECT_DIR/.claude/memory/`(缺失文件单向复制)。Phase 5(memory-update)和 Phase 6(memory-lint)严禁反向写入远程路径,所有远程同步只由 Phase 10 统一执行。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
for f in ~/.claude/projects/{PROJECT_KEY}/memory/*.md; do
|
||||||
|
fn=$(basename "$f"); local="$PROJECT_DIR/.claude/memory/$fn"
|
||||||
|
[ ! -f "$local" ] && cp -p "$f" "$local"
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
### 多机不同步检测
|
||||||
|
|
||||||
|
两边都存在的文件,对比 mtime。阈值:`MULTI_HOST_WARN_DAYS`(见 memcore-shared,默认 7)。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
MULTI_HOST_WARN_DAYS=7 # 与 memcore-shared 全局常量保持一致
|
||||||
|
|
||||||
|
for f in ~/.claude/projects/{PROJECT_KEY}/memory/*.md; do
|
||||||
|
local="$PROJECT_DIR/.claude/memory/$(basename "$f")"
|
||||||
|
[ ! -f "$local" ] && continue
|
||||||
|
rm=$(stat -c %Y "$f" 2>/dev/null || stat -f %m "$f")
|
||||||
|
lm=$(stat -c %Y "$local" 2>/dev/null || stat -f %m "$local")
|
||||||
|
diff_days=$(( (rm - lm) / 86400 ))
|
||||||
|
[ $diff_days -ge "$MULTI_HOST_WARN_DAYS" ] && echo "⚠ $(basename "$f") 远程比本地新 $diff_days 天"
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
≥1 个警告 → 提示 `检测到 N 个文件远程比本地新 ≥MULTI_HOST_WARN_DAYS 天,可能多机不同步。继续?(y/n)`。
|
||||||
|
- `n` → 终止整个 sync 流程
|
||||||
|
- `y` → 继续(Phase 10 仍按本地权威覆盖远程)
|
||||||
|
|
||||||
|
### 并发分歧检测(mtime 差 < `MULTI_HOST_WARN_DAYS` 天的冲突预警)
|
||||||
|
|
||||||
|
对「两边都存在且 mtime 差 < `MULTI_HOST_WARN_DAYS`(默认 7)天」的文件,进一步做内容比对:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
for f in ~/.claude/projects/{PROJECT_KEY}/memory/*.md; do
|
||||||
|
local="$PROJECT_DIR/.claude/memory/$(basename "$f")"
|
||||||
|
[ ! -f "$local" ] && continue
|
||||||
|
diff_days_abs=$(...) # 绝对值 < 7
|
||||||
|
if [ "$diff_days_abs" -lt 7 ] && ! diff -q "$f" "$local" > /dev/null 2>&1; then
|
||||||
|
echo "⚡ $(basename "$f") 双边近期均有改动,内容不同"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
发现 ≥1 个双边分歧文件 → 执行**轻量节段合并**(不等 git 冲突):
|
||||||
|
|
||||||
|
1. 提取远端文件中所有 `## Section` 块
|
||||||
|
2. 检查本地文件是否含同名 `## Section`:
|
||||||
|
- **不含** → 将整个远端 Section 追加到本地文件末尾(自动合并)
|
||||||
|
- **含且内容相同** → 跳过
|
||||||
|
- **含且内容不同** → 在本地文件该 Section 末尾追加注释:
|
||||||
|
`<!-- remote-diverge: YYYY-MM-DD, 请手动核对 -->`,并将远端版本追加为 `## [远端版本] Section`
|
||||||
|
3. 不修改 `MEMORY.md`(由 Phase 6 lint 重建)
|
||||||
|
4. 完成后输出合并摘要,提示用户审查 `<!-- remote-diverge -->` 标记
|
||||||
|
|
||||||
|
**此步骤的保护边界**:仅处理 decisions.md / feedback*.md / project*.md;`user_profile.md` 和 `synthesis_*.md` 不自动合并(内容主观性强,直接标 NEED-HUMAN)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 4 — diff 范围
|
||||||
|
|
||||||
|
```bash
|
||||||
|
[ -n "$ANCHOR_COMMIT" ] && git diff --name-only $ANCHOR_COMMIT..HEAD # → $CHANGED_FILES
|
||||||
|
```
|
||||||
|
|
||||||
|
空锚点 → `$CHANGED_FILES = 全量`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 5 — 执行 /memory-update
|
||||||
|
|
||||||
|
按 git diff 增量更新记忆文件 + MEMORY.md 索引。**完成立即继续 Phase 6,不暂停不收尾**。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 6 — 执行 /memory-lint
|
||||||
|
|
||||||
|
全量健康检查:AUTO-FIX 直修,NEED-HUMAN 写 `lint_report.md`。**完成立即继续 Phase 7,不暂停不收尾**。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 7 — CLAUDE.md 新建(若不存在)
|
||||||
|
|
||||||
|
执行 `/init` → 文件顶部加 `<!-- Last updated: YYYY-MM-DD | Commit: HASH -->` → 跳到 Phase 9。**简体中文,仅命令/代码保留原文**。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 8 — CLAUDE.md 增量更新(若已存在)
|
||||||
|
|
||||||
|
1. 提取顶部 `<!-- Last updated: ... | Commit: HASH -->` 的 HASH → `$CLAUDE_MD_COMMIT`
|
||||||
|
2. `git diff $CLAUDE_MD_COMMIT..HEAD -- .`
|
||||||
|
3. 按 diff 内容针对性修改章节(技术栈/模块/命令变化等),不重写全文
|
||||||
|
4. 更新顶部元数据日期与 commit
|
||||||
|
|
||||||
|
**简体中文,仅命令/代码保留原文**。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 9 — 记忆引导区块注入
|
||||||
|
|
||||||
|
读 `MEMORY.md` 索引,按以下骨架生成区块(动态填充清单);CLAUDE.md 已含 `## 记忆体系(会话启动必读)` → 整块替换,否则追加末尾。
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## 记忆体系(会话启动必读)
|
||||||
|
|
||||||
|
> 每次新会话或长会话压缩后,必须先读 `MEMORY.md` 索引再按需加载文件。代码与记忆冲突 → 以代码为准并更新记忆。
|
||||||
|
|
||||||
|
### 读取流程
|
||||||
|
1. `cat .claude/memory/MEMORY.md` 获取清单
|
||||||
|
2. **必读**(type=`project`/`feedback`):decisions.md / feedback.md / project_progress.md(按 MEMORY.md 实际动态生成)
|
||||||
|
3. **按需**(type=`user`/`reference`/`synthesis`/`lint`):架构讨论时读 project_overview.md / 个性化时读 user_profile.md / 外部集成读 reference.md / 特定主题读 feedback_{topic}.md / 技术决策读 synthesis_*.md
|
||||||
|
|
||||||
|
### 记忆目录骨架
|
||||||
|
.claude/memory/
|
||||||
|
├── MEMORY.md / decisions.md / feedback*.md / project_*.md / reference.md
|
||||||
|
├── user_profile.md
|
||||||
|
├── synthesis_*.md(按需)
|
||||||
|
└── lint_report.md(按需)
|
||||||
|
```
|
||||||
|
|
||||||
|
**动态调整**:从 MEMORY.md 表格筛 `project`/`feedback` → 必读;`user`/`reference`/`synthesis`/`lint` → 按需。区块清单必须与索引严格一致。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 10 — 本地 → 远程推送(权威覆盖)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p ~/.claude/projects/{PROJECT_KEY}/memory/
|
||||||
|
cp -pf "$PROJECT_DIR/.claude/memory/"*.md ~/.claude/projects/{PROJECT_KEY}/memory/
|
||||||
|
```
|
||||||
|
|
||||||
|
统一推送 update + lint 的全部本地结果。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 11 — 完成报告
|
||||||
|
|
||||||
|
```
|
||||||
|
✓ memory-sync 完成
|
||||||
|
|
||||||
|
⚡ 并发冲突处理:git冲突 N 个文件 / 双边分歧 M 个文件(均为 0 则省略本行)
|
||||||
|
含 <!-- merge-conflict --> / <!-- remote-diverge --> 标记的条目请通过 /memory-lint 审查
|
||||||
|
|
||||||
|
📋 CLAUDE.md [已更新 / 已新建 / 无变更]
|
||||||
|
📖 记忆引导区块 [已注入 / 已刷新 / 无变更]
|
||||||
|
|
||||||
|
🧠 memory-update:N 个文件已更新(commit HASH)
|
||||||
|
🔍 memory-lint:AUTO-FIX N 项 / NEED-HUMAN N 项(详见 lint_report.md)
|
||||||
|
|
||||||
|
🌟 核心枢纽节点(被引用 ≥3 次的 Top3,源:MEMORY.md「引用」列):
|
||||||
|
- architecture_decisions.md (5*)
|
||||||
|
- dev_workflow.md (4*)
|
||||||
|
|
||||||
|
📊 高频引用条目候选 synthesis 升级(源:lint_report.md「条目级高频引用 Top」;本段是聚合):
|
||||||
|
- architecture_decisions.md#动态API normalizeParams 类型转型 (跨 4 文件)
|
||||||
|
|
||||||
|
📤 已同步 N 个文件到远程
|
||||||
|
🔗 Base commit: HASH
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 执行约束
|
||||||
|
|
||||||
|
1. **Phase 0 最先** — 冲突检测(Step 1)必须先于普通变更提交(Step 2);有未解决冲突不允许跳过语义合并直接进入 Phase 1
|
||||||
|
2. **方向严格区分** — Phase 3 只补充 / Phase 10 才覆盖
|
||||||
|
3. **顺序固定** — Phase 5(update)→ Phase 6(lint);lint 在 update 写入完毕后检查
|
||||||
|
4. **统一推送** — update + lint 修改全部本地完成后由 Phase 10 一次推
|
||||||
|
5. **记忆引导区块强制存在** — 每次 sync 后 CLAUDE.md 必须含最新区块,文件清单与 MEMORY.md 严格一致
|
||||||
|
6. **并发冲突处理顺序** — git 冲突(Phase 0 Step 1)→ mtime 分歧合并(Phase 3)→ 两者均完成后才进 Phase 5;`<!-- merge-conflict -->` / `<!-- remote-diverge -->` 标记由 lint 扫描、用户事后审查
|
||||||
@@ -0,0 +1,213 @@
|
|||||||
|
---
|
||||||
|
name: memory-update
|
||||||
|
description: 根据git diff增量范围,更新本地记忆文件和MEMORY.md索引。唯一操作路径为 $PROJECT_DIR/.claude/memory/,严禁写入 ~/.claude/projects/*/memory/ 等项目目录外的任何路径,也不触发 auto memory 系统写入。可独立执行,也作为/memory-sync流程的一部分。调用命令: /memory-update
|
||||||
|
---
|
||||||
|
|
||||||
|
# memory-update
|
||||||
|
|
||||||
|
按 git diff 增量更新本地 `.claude/memory/`。
|
||||||
|
|
||||||
|
**前置约束:先 Read `../memcore-shared/SKILL.md`**(路径锁定 + 常量 + PROJECT_DIR 解析),其约束在本技能全程生效。
|
||||||
|
|
||||||
|
红线速记(详细见 memcore-shared):
|
||||||
|
- **唯一写入路径**:`$PROJECT_DIR/.claude/memory/`
|
||||||
|
- **严禁写入**:`~/.claude/projects/*/memory/`、`~/.claude/` 其他目录、项目外路径
|
||||||
|
- **执行前断言**:必须运行 memcore-shared 中的路径断言脚本,确认目标路径不含 `/.claude/projects/`
|
||||||
|
|
||||||
|
目录不存在则 `mkdir -p`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 1 — 读取增量锚点
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 主锚点:MEMORY.md 头部 _Last synced: DATE | Base commit: `HASH`_ → $ANCHOR_COMMIT
|
||||||
|
ANCHOR_COMMIT=$(grep -oE 'Base commit: `[^`]+`' "$PROJECT_DIR/.claude/memory/MEMORY.md" 2>/dev/null \
|
||||||
|
| head -1 | sed 's/Base commit: `//; s/`$//')
|
||||||
|
|
||||||
|
# 兜底锚点:若 MEMORY.md 头部锚点丢失,取各文件 frontmatter commit 字段的最旧值
|
||||||
|
# 防止"误删 MEMORY.md 头部 → 雪崩全量重写"
|
||||||
|
if [ -z "$ANCHOR_COMMIT" ] || [ "$ANCHOR_COMMIT" = "N/A" ]; then
|
||||||
|
FALLBACK=$(grep -h "^commit:" "$PROJECT_DIR/.claude/memory/"*.md 2>/dev/null \
|
||||||
|
| awk '{print $2}' | sort -u)
|
||||||
|
if [ -n "$FALLBACK" ]; then
|
||||||
|
# 取所有 commit 中按 git 拓扑序最旧的(保守锚点,确保覆盖所有改动)
|
||||||
|
ANCHOR_COMMIT=$(git -C "$PROJECT_DIR" rev-list --topo-order $FALLBACK 2>/dev/null | tail -1)
|
||||||
|
echo "⚠ MEMORY.md 头部锚点丢失,使用兜底锚点:$ANCHOR_COMMIT(来自各文件 frontmatter 最旧 commit)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
git -C "$PROJECT_DIR" rev-parse --short HEAD # → $HEAD_HASH(非 git 仓库填 N/A)
|
||||||
|
```
|
||||||
|
|
||||||
|
**为什么需要兜底**:MEMORY.md 头部的 `Base commit: HASH` 是单一来源,一旦用户手动编辑误删此行,整个 diff 范围退化为全量 → 触发 update 重写所有文件。兜底机制从各文件 frontmatter 的 `commit:` 字段取**最旧值**,确保覆盖所有真实改动而不退化为无差别全量。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 2 — 计算变更范围
|
||||||
|
|
||||||
|
```bash
|
||||||
|
[ -n "$ANCHOR_COMMIT" ] && git diff --name-only $ANCHOR_COMMIT..HEAD # → $CHANGED_FILES
|
||||||
|
```
|
||||||
|
|
||||||
|
空锚点 → 全量审查。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 3 — 更新记忆文件
|
||||||
|
|
||||||
|
### 维度路由($CHANGED_FILES → 目标文件)
|
||||||
|
|
||||||
|
| 变更内容 | 写入到 |
|
||||||
|
|---------|-------|
|
||||||
|
| 业务代码(`*.java/py/ts/vue`) | `project_overview.md` `decisions.md` |
|
||||||
|
| 依赖文件(pom.xml / requirements.txt / package.json) | `project_overview.md` |
|
||||||
|
| 进度信号(功能完成、Issue 关闭) | `project_progress.md` |
|
||||||
|
| 协作反馈(用户纠正、规范变更) | `feedback.md` 或 `feedback_{topic}.md` |
|
||||||
|
| 外部 URL | `reference.md` |
|
||||||
|
| 用户偏好/风格 | `user_profile.md` |
|
||||||
|
|
||||||
|
### 文件职责边界
|
||||||
|
|
||||||
|
| 文件 | 类型 | 写 | 不写 |
|
||||||
|
|------|------|---|------|
|
||||||
|
| `user_profile.md` | user | 角色、背景、偏好 | 任务进度 |
|
||||||
|
| `project_overview.md` | project | 技术栈、架构、目录、约定 | 可推断细节 |
|
||||||
|
| `project_progress.md` | project | 阶段、待办、里程碑 | git 历史 |
|
||||||
|
| `decisions.md` | project | Why 格式决策 | 实现细节 |
|
||||||
|
| `feedback*.md` | feedback | 协作规范(含 Why + How to apply) | 一次性修复 |
|
||||||
|
| `reference.md` | reference | 外部 URL/用途 | 本地路径 |
|
||||||
|
| `synthesis_*.md` | synthesis | 高价值分析归档 | 对话逐字记录 |
|
||||||
|
|
||||||
|
### 统一 frontmatter
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
---
|
||||||
|
name: 文件标题
|
||||||
|
description: 一句话描述(影响未来加载判断)
|
||||||
|
type: user | project | feedback | reference | synthesis
|
||||||
|
last_updated: YYYY-MM-DD
|
||||||
|
commit: HASH
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
||||||
|
### 条目格式(decisions / feedback 通用骨架)
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## 标题
|
||||||
|
|
||||||
|
**结论**(feedback 改为规范描述):xxx
|
||||||
|
**Why:** 背景、约束、历史教训
|
||||||
|
**How to apply:** 何时适用、边界
|
||||||
|
**See Also:** [[file.md#标题]]
|
||||||
|
```
|
||||||
|
|
||||||
|
`synthesis_*.md` 是完整文件而非条目,含 4 段:`## 背景` / `## 分析过程`(提炼,非逐字记录)/ `## 结论`(含 Why + How to apply)/ `## See Also`。
|
||||||
|
|
||||||
|
### 交叉引用(双向)
|
||||||
|
|
||||||
|
新增 decisions / feedback 条目时:
|
||||||
|
1. 扫描其他记忆文件标题
|
||||||
|
2. 主题相关 → 新条目末尾追加 `[[file.md#标题]]`
|
||||||
|
3. **反向也补**:被引用的旧条目末尾补充对新条目的引用
|
||||||
|
|
||||||
|
### synthesis 触发模式(三路)
|
||||||
|
|
||||||
|
**A. 会话内主动**:会话出现技术选型对比 / Bug 根因 / 架构演进 / 性能安全分析时,主动提议归档为 `synthesis_{type}_{topic}.md`。
|
||||||
|
|
||||||
|
**B. 反向引用触发**:
|
||||||
|
1. 读 `lint_report.md`「条目级高频引用 Top」段(≥3 跨文件 = 候选)
|
||||||
|
2. 检查候选是否已有对应 `synthesis_*`(前缀匹配 + 标题语义)
|
||||||
|
3. 未升级候选 → 提议:
|
||||||
|
```
|
||||||
|
📊 高频引用候选升级 synthesis:
|
||||||
|
[条目](被 N 文件引用)→ 建议归档为 synthesis_xxx.md
|
||||||
|
是否归档?(y/n/skip-all)
|
||||||
|
```
|
||||||
|
4. `y` → 创建文件 + 在原条目末尾加 `**Synthesized:** [[xxx.md]]`
|
||||||
|
5. `n` → 原条目末尾加 `<!-- synthesis-decline: YYYY-MM-DD -->`,30 天免打扰
|
||||||
|
6. `skip-all` → 本次不再提议
|
||||||
|
|
||||||
|
### 3C — 即时引用计数快扫(不依赖 lint)
|
||||||
|
|
||||||
|
每次执行 Phase 3 末尾**强制运行**。目的:在短会话或任务型对话中,不依赖 lint 的延迟触发,直接检测 synthesis 升级候选。
|
||||||
|
|
||||||
|
阈值:`SYNTHESIS_THRESHOLD`(见 memcore-shared,当前 = 3)。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 阈值从 memcore-shared 读取
|
||||||
|
SYNTHESIS_THRESHOLD=3 # 与 memcore-shared 全局常量保持一致
|
||||||
|
|
||||||
|
# 对 decisions.md / feedback*.md 的每个 ## 条目,统计被多少不同源文件引用
|
||||||
|
for entry_file in "$PROJECT_DIR/.claude/memory/decisions.md" \
|
||||||
|
"$PROJECT_DIR/.claude/memory/feedback"*.md; do
|
||||||
|
[ -f "$entry_file" ] || continue
|
||||||
|
fn=$(basename "$entry_file")
|
||||||
|
while IFS= read -r title; do
|
||||||
|
# 使用 printf %q 转义 title 中的特殊字符(空格 / 中文标点 / 引号等)
|
||||||
|
# 同时去除 grep 模式中的方括号歧义([[..]] 是字面量)
|
||||||
|
pat=$(printf '%s' "[[${fn}#${title}]]" | sed 's/[][\\.*^$/]/\\&/g')
|
||||||
|
count=$(grep -rlF -- "[[${fn}#${title}]]" \
|
||||||
|
"$PROJECT_DIR/.claude/memory/" --include="*.md" 2>/dev/null \
|
||||||
|
| grep -v "^${entry_file}$" | wc -l)
|
||||||
|
[ "$count" -ge "$SYNTHESIS_THRESHOLD" ] && echo "$count|$fn#$title"
|
||||||
|
done < <(grep "^## " "$entry_file" | sed 's/^## //')
|
||||||
|
done | sort -t'|' -k1 -rn
|
||||||
|
```
|
||||||
|
|
||||||
|
**脚本健壮性说明**:
|
||||||
|
- 使用 `grep -F`(fixed string)避免 `[[` `]]` 在正则中的歧义
|
||||||
|
- title 含中文 / 空格 / 标点时不会破坏匹配
|
||||||
|
- `--` 防止 title 以 `-` 开头被误解为 grep 选项
|
||||||
|
- 单文件中同标题多次引用按 `-l` 仅记一次(按文件去重)
|
||||||
|
|
||||||
|
对每条输出候选(`count|file#title`):
|
||||||
|
1. 读原条目内是否含 `**Synthesized:**` → 已升级,跳过
|
||||||
|
2. 读原条目内是否含 `<!-- synthesis-decline: YYYY-MM-DD -->` → 30 天内,跳过
|
||||||
|
3. 以上均无 → 触发提议(同 B 模式 step 3-6)
|
||||||
|
|
||||||
|
**与 lint 的分工**:
|
||||||
|
- Phase 3C(快扫):每次 memory-update 必跑,判据为「存在引用行数」,适合即时触发
|
||||||
|
- lint Phase 3A(精扫):按源文件去重的精确计数,月度健康检查时运行
|
||||||
|
- 两者以 `**Synthesized:**` 标记为唯一判重依据,不重复创建文件
|
||||||
|
- 阈值唯一来源为 memcore-shared 的 `SYNTHESIS_THRESHOLD`,调整请改 memcore-shared
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 写入要点
|
||||||
|
|
||||||
|
- 仅更新有变化维度,不重写无关文件
|
||||||
|
- frontmatter 的 `last_updated` 改今日,`commit` 改 `$HEAD_HASH`
|
||||||
|
- 追加为主,不删已有内容(除非过时/冲突)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 4 — 更新 MEMORY.md 索引
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# Memory Index
|
||||||
|
> _Last synced: YYYY-MM-DD | Base commit: `HASH`_
|
||||||
|
|
||||||
|
| 文件 | 描述 | 类型 | 引用 | Commit |
|
||||||
|
|------|------|------|------|--------|
|
||||||
|
```
|
||||||
|
|
||||||
|
更新规则:
|
||||||
|
- 改过的文件 → 同步「Commit」列
|
||||||
|
- 头部 `Last synced` / `Base commit` 改为今日 / `$HEAD_HASH`
|
||||||
|
- 新增文件 → 「引用」列占位 `0`(实际值由 `/memory-lint` Phase 7 刷新)
|
||||||
|
- 「引用」列语义:≥3 加 `*`(如 `5*`)、<3 显示数字
|
||||||
|
- 表格排序由 lint 重排,本 Phase 不强制
|
||||||
|
|
||||||
|
被 `/memory-sync` 调用 → 不输出收尾;独立调用 → 输出完整摘要。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 执行约束
|
||||||
|
|
||||||
|
1. **最小化更新** — 不写无变化维度
|
||||||
|
2. **不记录可推断内容** — 实现细节、文件路径、git 历史不入库
|
||||||
|
3. **feedback 拆分** — 同主题 >5 条规则 → 拆出 `feedback_{topic}.md`
|
||||||
|
4. **See Also 双向同步** — 新增时扫关联并双向补
|
||||||
|
5. **synthesis 三触发** — 会话主动 + Phase 3C 即时快扫 + lint Top 反向;`**Synthesized:**` 标记不可覆盖;`<!-- synthesis-decline -->` 标记 30 天免打扰
|
||||||
|
6. **被调用静默返回** — `/memory-sync` 内执行不输出收尾
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"name": "obsidian",
|
||||||
|
"description": "Obsidian 知识库 AI 协作插件族。检测到 .obsidian/ 目录时自动激活全套技能:vault 管理(obsidian,含 OFM 语法速查)、全文搜索与图谱(obsidian-search)、frontmatter 元数据(obsidian-meta)、Markdown 任务与 GTD(obsidian-tasks)、每日笔记(obsidian-daily)、Bases 数据库视图(obsidian-bases)、Canvas 视觉层(obsidian-canvas,JSON Canvas 1.0)、版本历史与恢复(obsidian-history)、插件与环境配置(obsidian-plugins)、PKM 编排工作流(obsidian-workflow-pkm,含 Web Clip 子流程)。",
|
||||||
|
"author": {
|
||||||
|
"name": "姜顺志"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,266 @@
|
|||||||
|
---
|
||||||
|
name: obsidian-bases
|
||||||
|
description: Obsidian 1.9+ 原生数据库视图(Bases):查询 .base 文件中的结构化视图(JSON/CSV/MD 输出)、在 base 中创建新条目。触发词:Bases、base 视图、数据库视图、结构化查询笔记、base query。不用于 Dataview(社区插件,用其原生 DQL 语法)。依赖 YAML frontmatter 属性,与 obsidian-meta 配合使用;需 Obsidian ≥ 1.9。
|
||||||
|
---
|
||||||
|
|
||||||
|
# Obsidian Bases · 原生数据库视图
|
||||||
|
|
||||||
|
> **Obsidian 1.9+ 的杀手级特性**:把 vault 当成数据库,把每篇笔记当成一条记录,把 frontmatter 当成字段。用 `.base` 文件定义视图和筛选,不用写一行 JS(对比 Dataview)。
|
||||||
|
|
||||||
|
> **为什么 Bases 对 AI agent 意义重大**:它把"非结构化笔记 + frontmatter 属性"变成了"可查询的结构化数据",agent 可以直接 `base:query` 拿到 JSON,不需要先全文搜索再解析。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 何时使用
|
||||||
|
|
||||||
|
- 列出 vault 中所有 `.base` 数据库视图文件
|
||||||
|
- **查询某个 base** 的结果(支持多种输出格式)
|
||||||
|
- 在 base 中**创建新条目**(自动写入符合 base 视图规则的 frontmatter)
|
||||||
|
- 列出某 base 的所有**视图**(views)
|
||||||
|
- 把"项目管理面板"、"阅读清单"、"文章管理"等做成可视化看板
|
||||||
|
|
||||||
|
## 不用于
|
||||||
|
|
||||||
|
- **Dataview** 查询(社区插件,用 DQL 语法,不是 Bases)
|
||||||
|
- 简单的属性读写 → **obsidian-meta**
|
||||||
|
- 全文搜索 → **obsidian-search**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 前置条件
|
||||||
|
|
||||||
|
- **Obsidian ≥ 1.9**(检查:`obsidian version`)
|
||||||
|
- 知识库中存在至少一个 `.base` 文件(通过 Obsidian UI 创建,或从社区模板复制)
|
||||||
|
- 参与 base 的笔记必须使用 **YAML frontmatter**(不是 Dataview inline 字段,Bases 不认)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 命令速查
|
||||||
|
|
||||||
|
### Base 文件与视图管理
|
||||||
|
|
||||||
|
```bash
|
||||||
|
obsidian bases # 列出 vault 所有 .base 文件
|
||||||
|
obsidian base:views # 列出当前 base 的所有视图
|
||||||
|
obsidian base:views file="项目管理" # 列出某 base 的视图
|
||||||
|
```
|
||||||
|
|
||||||
|
### 查询 Base
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 基础查询(默认 JSON)
|
||||||
|
obsidian base:query file="项目管理"
|
||||||
|
obsidian base:query path="20-Areas/项目管理.base"
|
||||||
|
|
||||||
|
# 指定视图
|
||||||
|
obsidian base:query file="项目管理" view="进行中"
|
||||||
|
obsidian base:query file="项目管理" view="按截止日" format=csv
|
||||||
|
obsidian base:query file="项目管理" view="逾期" format=md # Markdown 表格
|
||||||
|
obsidian base:query file="项目管理" view="全部" format=paths # 只返回路径列表
|
||||||
|
obsidian base:query file="项目管理" view="全部" format=tsv
|
||||||
|
```
|
||||||
|
|
||||||
|
**输出格式**:
|
||||||
|
- `json`(默认):最完整,含所有字段
|
||||||
|
- `csv`:表格,适合导出到 Excel
|
||||||
|
- `tsv`:表格,Bash 处理友好
|
||||||
|
- `md`:Markdown 表格,直接粘贴到笔记
|
||||||
|
- `paths`:只返回文件路径列表
|
||||||
|
|
||||||
|
### 在 Base 中创建新条目
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 在某视图下创建新笔记(自动套用该视图的默认字段)
|
||||||
|
obsidian base:create file="项目管理" view="进行中" name="新项目Alpha" \
|
||||||
|
content="# 新项目 Alpha" open
|
||||||
|
|
||||||
|
# 完整参数
|
||||||
|
obsidian base:create \
|
||||||
|
file="项目管理" \
|
||||||
|
view="进行中" \
|
||||||
|
name="新项目" \
|
||||||
|
content="初始内容" \
|
||||||
|
open \
|
||||||
|
newtab
|
||||||
|
```
|
||||||
|
|
||||||
|
> 💡 `base:create` 的威力:它会按视图规则**自动填充 frontmatter**(例如 "进行中" 视图可能强制 `status: active`),省去手动 `property:set`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Bases vs Dataview 选型表
|
||||||
|
|
||||||
|
| 维度 | Bases(官方 1.9+) | Dataview(社区插件) |
|
||||||
|
|-----|-------------------|---------------------|
|
||||||
|
| 语法 | YAML 配置(声明式) | JS/DQL(命令式) |
|
||||||
|
| 数据源 | 仅 YAML frontmatter | frontmatter + inline `Key::` |
|
||||||
|
| 写入 | ✅ 支持 `base:create` | ❌ 只读 |
|
||||||
|
| 性能 | ✅ 原生 C++,极快 | ⚠ JS 运行时,大 vault 卡 |
|
||||||
|
| 多视图 | ✅ 一个 base 多视图 | 每个查询一段代码 |
|
||||||
|
| AI agent 友好 | ✅ CLI 直接 query JSON | ⚠ 需要模拟 Dataview JS 运行 |
|
||||||
|
| 社区模板 | 🟡 起步阶段 | ✅ 海量模板 |
|
||||||
|
| 版本要求 | Obsidian ≥ 1.9 | 任意版本 |
|
||||||
|
|
||||||
|
**选型建议**:
|
||||||
|
- **新项目 / AI agent 驱动** → 首选 Bases
|
||||||
|
- **已有 Dataview 资产** → 继续用,或逐步迁移
|
||||||
|
- **需要复杂计算** → Dataview(Bases 未来会支持公式字段)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## AI Agent 最佳实践
|
||||||
|
|
||||||
|
### 场景 1 · 项目面板作为 AI 决策依据
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Agent 问:"今天我该优先处理哪个项目?"
|
||||||
|
# Step 1: 查询"进行中"项目,按 due 排序
|
||||||
|
obsidian base:query file="项目管理" view="按截止日" format=json
|
||||||
|
|
||||||
|
# Step 2: Agent 分析返回的 JSON,找出:
|
||||||
|
# - due 最近的 3 个
|
||||||
|
# - priority 最高的 3 个
|
||||||
|
# - blocked 状态已解除的
|
||||||
|
|
||||||
|
# Step 3: 生成建议写入每日笔记
|
||||||
|
obsidian daily:append content="\n## 📌 AI 建议优先级\n..."
|
||||||
|
```
|
||||||
|
|
||||||
|
### 场景 2 · 阅读清单 Base 设计
|
||||||
|
|
||||||
|
创建 `30-Resources/reading-list.base`(通过 Obsidian UI),字段规划:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# frontmatter 规范(每本书/文章一个笔记)
|
||||||
|
---
|
||||||
|
type: book | article | paper | video
|
||||||
|
title:
|
||||||
|
author:
|
||||||
|
url:
|
||||||
|
status: to-read | reading | done | abandoned
|
||||||
|
priority: 1-5
|
||||||
|
started: 2026-03-15
|
||||||
|
finished:
|
||||||
|
rating: 1-5
|
||||||
|
tags: [topic1, topic2]
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
||||||
|
视图设计:
|
||||||
|
- **待读**: `status == "to-read"`, 按 `priority desc`
|
||||||
|
- **在读**: `status == "reading"`
|
||||||
|
- **已读高分**: `status == "done" AND rating >= 4`
|
||||||
|
- **按主题**: group by `tags`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Agent 查询:我的待读列表前 5
|
||||||
|
obsidian base:query file="reading-list" view="待读" format=md | head -20
|
||||||
|
```
|
||||||
|
|
||||||
|
### 场景 3 · 用 Base 做 AI 工作日志
|
||||||
|
|
||||||
|
创建 `99-Log/ai-actions.base`,每次 agent 写入操作创建一条记录:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 不手动建笔记,直接通过 base:create
|
||||||
|
obsidian base:create \
|
||||||
|
file="ai-actions" \
|
||||||
|
view="今日" \
|
||||||
|
name="$(date +%Y%m%d%H%M%S)-property-set" \
|
||||||
|
content="---
|
||||||
|
action: property:set
|
||||||
|
target: 项目Alpha
|
||||||
|
field: status
|
||||||
|
value: done
|
||||||
|
agent: claude-sonnet-4-6
|
||||||
|
reason: 用户确认项目完成
|
||||||
|
---"
|
||||||
|
```
|
||||||
|
|
||||||
|
之后查询:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
obsidian base:query file="ai-actions" view="今日" format=md
|
||||||
|
obsidian base:query file="ai-actions" view="本周 action 统计" format=csv
|
||||||
|
```
|
||||||
|
|
||||||
|
### 场景 4 · Base 作为 RAG 检索的结构化索引
|
||||||
|
|
||||||
|
传统 RAG:全文搜索 → 召回 → 喂模型。
|
||||||
|
Bases 增强:**先用 base 做结构化筛选,缩小召回范围,再做全文搜索**。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 问题:"最近 3 个月我写的关于虚拟线程的读书笔记"
|
||||||
|
# Step 1: 用 base 筛出结构化候选
|
||||||
|
obsidian base:query file="reading-list" view="近 3 个月" format=paths > /tmp/candidates.txt
|
||||||
|
|
||||||
|
# Step 2: 在候选范围内全文搜索
|
||||||
|
obsidian search query="虚拟线程" path="$(xargs -a /tmp/candidates.txt)" format=json
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Base 文件结构(了解即可,通常由 UI 生成)
|
||||||
|
|
||||||
|
`.base` 文件是 YAML 格式:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# 20-Areas/项目管理.base
|
||||||
|
filters:
|
||||||
|
and:
|
||||||
|
- file.inFolder: "10-Projects"
|
||||||
|
- status: ["active", "paused"]
|
||||||
|
|
||||||
|
views:
|
||||||
|
- name: 进行中
|
||||||
|
type: table
|
||||||
|
filters:
|
||||||
|
- status: active
|
||||||
|
order:
|
||||||
|
- due ASC
|
||||||
|
columns:
|
||||||
|
- file.name
|
||||||
|
- status
|
||||||
|
- due
|
||||||
|
- priority
|
||||||
|
- owner
|
||||||
|
|
||||||
|
- name: 按截止日
|
||||||
|
type: table
|
||||||
|
order:
|
||||||
|
- due ASC
|
||||||
|
|
||||||
|
- name: 逾期
|
||||||
|
type: list
|
||||||
|
filters:
|
||||||
|
- due < today()
|
||||||
|
- status: active
|
||||||
|
```
|
||||||
|
|
||||||
|
> 💡 推荐通过 Obsidian UI 创建 `.base` 文件,再用 CLI 查询。直接手写 `.base` 容易语法错。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 与其他技能的协作
|
||||||
|
|
||||||
|
| 场景 | 链路 |
|
||||||
|
|-----|------|
|
||||||
|
| 属性设计 → 视图落地 | **obsidian-meta**(frontmatter 规范)→ obsidian-bases(查询) |
|
||||||
|
| 结构化召回 + 全文精读 | obsidian-bases → **obsidian-search** |
|
||||||
|
| 决策支持 | obsidian-bases → **obsidian-daily**(写建议) |
|
||||||
|
| 项目看板自动化 | obsidian-bases + **obsidian-tasks**(进度) |
|
||||||
|
| AI 日志归档 | 所有技能写操作 → obsidian-bases(`base:create` 到 ai-actions.base) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 常见陷阱
|
||||||
|
|
||||||
|
| 现象 | 原因 | 对策 |
|
||||||
|
|------|------|------|
|
||||||
|
| `bases` 命令返回空 | Obsidian 版本 < 1.9 | 升级到 1.9+ |
|
||||||
|
| `base:query` 字段缺失 | 笔记用了 Dataview inline 字段 | 改写到 YAML frontmatter |
|
||||||
|
| `base:create` 报错 | view 名称拼写错 | 先 `base:views` 列出 |
|
||||||
|
| 视图不更新 | 缓存 | `obsidian reload` |
|
||||||
|
| 日期排序错 | frontmatter 日期是 text 类型 | `property:set type=date` |
|
||||||
|
| 查询慢 | base filter 过于宽松 | 增加 `file.inFolder` 限定 |
|
||||||
|
| agent 写的 base 条目违反 schema | 没先读 base 规则 | `base:views` + 手动验证字段 |
|
||||||
@@ -0,0 +1,228 @@
|
|||||||
|
---
|
||||||
|
name: obsidian-canvas
|
||||||
|
description: Obsidian 视觉层操作——读写 .canvas 文件(JSON Canvas 1.0 开放格式):思维导图、项目看板、视觉知识图、AI 生成节点布局。支持 4 种 node 类型(text/file/link/group)+ edges 连线(fromNode/toNode/fromSide/toSide)。触发词:canvas、画布、思维导图、视觉知识图、项目看板、白板、可视化笔记、mind map、白板视图、节点图。不用于 Markdown 笔记 CRUD(obsidian 核心)、不用于 Bases 数据库视图(obsidian-bases,那是表格不是画布)。社区共识:obsidian-cli 不原生支持 .canvas 写入,本技能走直接 JSON 文件 Read/Write 路线。
|
||||||
|
---
|
||||||
|
|
||||||
|
# Obsidian Canvas · JSON Canvas 视觉层
|
||||||
|
|
||||||
|
> **为什么独立成技能**:Canvas 是 Obsidian 的开放格式(`.canvas` = JSON),社区标杆(kepano/obsidian-skills、AgriciDaniel/claude-obsidian)都把它作为独立 skill 维护,因为它的 schema 完全独立于 Markdown 笔记体系——AI 不能用一句 wikilink 替代一张画布。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 何时使用
|
||||||
|
|
||||||
|
- 用户说"把这些笔记画成一张图/思维导图/项目看板"
|
||||||
|
- 用户给一个 `.canvas` 文件让 AI 读取/修改
|
||||||
|
- 大主题展开时,AI 主动建议"做成 canvas 更清晰"
|
||||||
|
- 项目启动时,用 canvas 做"模块 - 任务 - 负责人"鸟瞰图
|
||||||
|
- 把研究网络(多篇笔记 + 几张图片 + 几个外链)摆到一张画布上
|
||||||
|
|
||||||
|
## 不用于
|
||||||
|
|
||||||
|
- Markdown 笔记本身的 CRUD → `obsidian` 核心技能
|
||||||
|
- 结构化数据库视图(表格、列表、卡片) → `obsidian-bases`
|
||||||
|
- 笔记间的双向链接图(Obsidian 自带 Graph View) → `obsidian-search` 的 graph 子集
|
||||||
|
- 单纯画流程图/时序图(Mermaid 块) → 写在 Markdown 笔记里即可
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. JSON Canvas 1.0 Schema 速查
|
||||||
|
|
||||||
|
`.canvas` 文件结构:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"nodes": [ /* 数组顺序 = z-index(先画的在底层) */ ],
|
||||||
|
"edges": [ /* 连线,order 不影响 z-index */ ]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1.1 Node 公共字段
|
||||||
|
|
||||||
|
| 字段 | 类型 | 必填 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| `id` | string | ✅ | **16 字符小写 hex**(Obsidian 约定,64-bit 随机) |
|
||||||
|
| `type` | enum | ✅ | `text` / `file` / `link` / `group` |
|
||||||
|
| `x`, `y` | number | ✅ | 画布坐标(左上原点,向右/下为正,无单位) |
|
||||||
|
| `width`, `height` | number | ✅ | 节点尺寸(像素) |
|
||||||
|
| `color` | string | ❌ | `"1"`-`"6"`(预设色)或 `"#RRGGBB"`(自定义) |
|
||||||
|
|
||||||
|
预设色:`1`=红, `2`=橙, `3`=黄, `4`=绿, `5`=青, `6`=紫。
|
||||||
|
|
||||||
|
### 1.2 四种 Node 专属字段
|
||||||
|
|
||||||
|
| `type` | 专属字段 | 用途 |
|
||||||
|
|--------|---------|------|
|
||||||
|
| `text` | `text`: string(Markdown 内容,**换行用 `\n`,不要字面量 `\\n`**) | 在画布上写笔记片段 |
|
||||||
|
| `file` | `file`: string(vault 内相对路径,如 `"50-Zettel/abc.md"`);可选 `subpath`: 跳转锚点(`#标题` 或 `#^blockid`) | 嵌入一篇笔记/图片/PDF |
|
||||||
|
| `link` | `url`: string | 嵌入外部网页 |
|
||||||
|
| `group` | `label`: string(分组标题);通常配 `color` 区分 | 视觉容器(不是真包含,只是覆盖矩形) |
|
||||||
|
|
||||||
|
### 1.3 Edge 字段
|
||||||
|
|
||||||
|
| 字段 | 类型 | 必填 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| `id` | string | ✅ | 同 16 字符 hex |
|
||||||
|
| `fromNode` / `toNode` | string | ✅ | 引用 node 的 `id` |
|
||||||
|
| `fromSide` / `toSide` | enum | ❌ | `top` / `right` / `bottom` / `left`(默认自动选最近边) |
|
||||||
|
| `fromEnd` / `toEnd` | enum | ❌ | `none` / `arrow`(默认 `toEnd=arrow`,`fromEnd=none`) |
|
||||||
|
| `color` | string | ❌ | 同 node color |
|
||||||
|
| `label` | string | ❌ | 连线上的文字 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 16 字符 hex ID 生成
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Bash(Git Bash 可用)
|
||||||
|
openssl rand -hex 8 # 推荐
|
||||||
|
# 或
|
||||||
|
head -c 8 /dev/urandom | xxd -p # POSIX 兼容
|
||||||
|
|
||||||
|
# Python
|
||||||
|
python -c "import secrets; print(secrets.token_hex(8))"
|
||||||
|
|
||||||
|
# 节点和边的 ID 不要复用;同一 canvas 内全局唯一
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 标准操作模式
|
||||||
|
|
||||||
|
> **社区共识**:obsidian-cli **不**原生支持 `.canvas` 写入。本技能走 `Read` + `Write` 工具直接编辑 JSON。
|
||||||
|
|
||||||
|
### 3.1 读取一张 canvas
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 列 vault 中所有 canvas
|
||||||
|
obsidian files ext=canvas format=json
|
||||||
|
|
||||||
|
# 直接读(用 Read 工具或 cat)
|
||||||
|
cat "MyVault/项目鸟瞰.canvas" | jq .
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2 新建一张空 canvas
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo '{"nodes":[],"edges":[]}' > "MyVault/项目鸟瞰.canvas"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.3 添加节点(Python helper 比 bash 安全)
|
||||||
|
|
||||||
|
```python
|
||||||
|
# add_node.py
|
||||||
|
import json, secrets, sys
|
||||||
|
|
||||||
|
path = sys.argv[1]
|
||||||
|
with open(path, 'r', encoding='utf-8') as f:
|
||||||
|
data = json.load(f)
|
||||||
|
|
||||||
|
data['nodes'].append({
|
||||||
|
"id": secrets.token_hex(8),
|
||||||
|
"type": "text",
|
||||||
|
"x": 0, "y": 0, "width": 250, "height": 60,
|
||||||
|
"text": "新节点"
|
||||||
|
})
|
||||||
|
|
||||||
|
with open(path, 'w', encoding='utf-8') as f:
|
||||||
|
json.dump(data, f, ensure_ascii=False, indent=2)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.4 布局建议
|
||||||
|
|
||||||
|
- **网格起步**:节点 250×60,间隔 80px,AI 先排成网格再让用户手动调
|
||||||
|
- **文本节点行高**:每行约 22px,预估 `height = 行数 × 22 + 16`(padding)
|
||||||
|
- **group 覆盖范围**:先算所有子节点的 bounding box,再 `x -= 20, y -= 40, width += 40, height += 60`
|
||||||
|
- **文件节点**:默认 400×400(带预览渲染),单行文本节点 250×60
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 与 Markdown 笔记的协作模式
|
||||||
|
|
||||||
|
最强用法:**canvas 当成"鸟瞰图 + 入口",节点 = 笔记 file 引用**。
|
||||||
|
不要在 canvas 里写大段正文——那是 Markdown 的活;canvas 只承担**空间关系**。
|
||||||
|
|
||||||
|
| 模式 | 怎么做 |
|
||||||
|
|------|--------|
|
||||||
|
| 项目板 | 4 个 group(Backlog/Doing/Done/Archive),每个任务一个 file 节点 |
|
||||||
|
| 主题鸟瞰 | 中心 group = 主题名,周围环绕 file 节点(每篇相关 zettel) |
|
||||||
|
| 研究地图 | text 节点写问题,file 节点放参考资料,edge 标关系("支持/反驳/引用") |
|
||||||
|
| AI 生成 | AI 读多篇笔记后生成 canvas:自动布局 + 用 edge.label 标"先验/同源/对立" |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 安全 SOP(AI 大批量写入的回滚策略)
|
||||||
|
|
||||||
|
> ⚠ **决策待定**:以下 4 选项需要团队定调。在写入前防止半写状态导致 canvas 损坏。
|
||||||
|
|
||||||
|
| 选项 | 操作 | 依赖 | 失败回退 | 适用边界 |
|
||||||
|
|------|------|------|---------|---------|
|
||||||
|
| **A · git stash** | 写前 `git stash`;失败 `git stash pop` | vault 是 git repo | stash 仍在 stash 栈 | vault 用 git 托管 |
|
||||||
|
| **B · .bak 备份** | 写前 `cp x.canvas x.canvas.bak`;失败手动 `mv` 回滚 | 无 | 半人工 | 任何 vault |
|
||||||
|
| **C · 原子写** | 写 `x.canvas.tmp` → `mv .tmp .canvas`(rename 原子操作) | 无 | tmp 残留可清理 | 任何 vault |
|
||||||
|
| **D · 依赖 File Recovery** | 不做额外保护,靠 Obsidian 内置 File Recovery(默认 7 天)回滚 | Obsidian 内置 | 需手动进入 obsidian-history 找版本 | vault 用户启用 File Recovery 且能及时发现失败 |
|
||||||
|
|
||||||
|
<!-- TODO(user): 由你最终拍板。建议复用 memcore 的并发冲突保护哲学保持一致性。
|
||||||
|
请用 5-10 行写入下方"决策"段落,包含:
|
||||||
|
1. 选哪个(A/B/C/D 或组合)
|
||||||
|
2. 为什么这个最适合本团队的 vault 使用场景
|
||||||
|
3. 失败时具体怎么回退(命令级)
|
||||||
|
4. 不适用边界(什么情况下不要这么做)
|
||||||
|
-->
|
||||||
|
|
||||||
|
### 决策(团队规范)
|
||||||
|
|
||||||
|
> **当前**:[ 留待填入 ]
|
||||||
|
>
|
||||||
|
> 在确认前,AI agent **默认采用选项 C(原子写)+ 选项 D(File Recovery 兜底)**——成本最低、不依赖 git、对 vault 无侵入。但这不是最终决策,请团队确认。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 选项 C 默认实现(在团队决策前生效的兜底)
|
||||||
|
canvas_atomic_write() {
|
||||||
|
local path="$1"
|
||||||
|
local new_content="$2"
|
||||||
|
local tmp="${path}.tmp.$$"
|
||||||
|
echo "$new_content" > "$tmp" && \
|
||||||
|
python -c "import json,sys; json.load(open('$tmp'))" && \
|
||||||
|
mv "$tmp" "$path"
|
||||||
|
# JSON 校验失败时不 mv,原文件不受影响,tmp 残留待清理
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 常见陷阱
|
||||||
|
|
||||||
|
| 现象 | 原因 | 对策 |
|
||||||
|
|------|------|------|
|
||||||
|
| Canvas 打开后空白 | JSON 不合法(缺逗号、注释) | JSON Canvas 不支持注释;用 `jq .` 先校验 |
|
||||||
|
| 节点位置错乱 | x/y 用了字符串 | 必须是 number,不要 `"x": "100"` |
|
||||||
|
| 中文字符乱码 | 编码不是 UTF-8 | Python 打开/保存必须 `encoding='utf-8'`,`ensure_ascii=False` |
|
||||||
|
| `\n` 显示为字面量 | 用了 `\\n`(双反斜杠) | JSON 字符串里换行就是单 `\n` |
|
||||||
|
| Edge 不显示 | `fromNode`/`toNode` 引用的 ID 不存在 | 写 edge 前先确认两端 node 已写入 |
|
||||||
|
| 文件节点没预览 | `file` 路径错误(不是 vault 内相对路径) | 用 `obsidian files` 获取的标准路径 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 与社区 schema 兼容性
|
||||||
|
|
||||||
|
本技能严格遵循 [JSON Canvas Spec 1.0](https://jsoncanvas.org/)(Obsidian、Logseq、Anytype 等多家共用)。
|
||||||
|
即便用户离开 Obsidian,`.canvas` 文件依然可被其他兼容工具读取——这是 Obsidian 开放格式承诺的核心价值。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. 与其他 obsidian-* 技能的关系
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
canvas["obsidian-canvas<br/>(视觉层)"]
|
||||||
|
core["obsidian<br/>(Markdown CRUD)"]
|
||||||
|
search["obsidian-search<br/>(找节点要的笔记)"]
|
||||||
|
meta["obsidian-meta<br/>(节点的 frontmatter)"]
|
||||||
|
workflow["obsidian-workflow-pkm<br/>(MOC 编排时调用)"]
|
||||||
|
|
||||||
|
workflow -- "MOC Builder 可输出 canvas" --> canvas
|
||||||
|
canvas -- "file 节点引用" --> core
|
||||||
|
canvas -- "新建 file 节点前查重" --> search
|
||||||
|
canvas -- "节点字段约定" --> meta
|
||||||
|
```
|
||||||
@@ -0,0 +1,248 @@
|
|||||||
|
---
|
||||||
|
name: obsidian-daily
|
||||||
|
description: Obsidian 每日笔记工作流:读取/追加今日笔记内容、晨间规划注入、晚间回顾、AI 操作审计日志写入、快速灵感捕获。触发词:每日笔记、daily note、今天的笔记、晨间笔记、晚间回顾、写日志、快速捕获、quick capture。周报/月报汇总请用 obsidian-workflow-pkm,跨日搜索请用 obsidian-search。需 Obsidian Daily Notes 核心插件已启用。
|
||||||
|
---
|
||||||
|
|
||||||
|
# Obsidian Daily · 每日笔记工作流
|
||||||
|
|
||||||
|
> 每日笔记是 Obsidian 最重要的 AI 接入点——它是**时间轴的锚点**,是日常捕获、AI 操作日志、GTD 收集篮的统一载体。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 何时使用
|
||||||
|
|
||||||
|
- 打开/读取**今天**的每日笔记
|
||||||
|
- 向今天的每日笔记**追加/前置**内容(AI 日志、完成任务、灵感片段)
|
||||||
|
- 实现**晨间模板**(计划、天气、任务列表)
|
||||||
|
- 实现**晚间回顾**(成就、反思、明日计划)
|
||||||
|
- 把 **AI agent 操作日志**写入当天笔记(可追溯)
|
||||||
|
|
||||||
|
## 不用于
|
||||||
|
|
||||||
|
- 跨日搜索/汇总 → **obsidian-search** + **obsidian-workflow-pkm**
|
||||||
|
- 周报/月报 → **obsidian-workflow-pkm**
|
||||||
|
- 任务列表管理 → **obsidian-tasks**
|
||||||
|
- 每日笔记的模板文件管理 → **obsidian-plugins**(Templates 插件)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 命令速查
|
||||||
|
|
||||||
|
```bash
|
||||||
|
obsidian daily # 打开今天的每日笔记(UI 中)
|
||||||
|
obsidian daily paneType=split # 在分屏中打开
|
||||||
|
obsidian daily paneType=tab # 在新标签打开
|
||||||
|
obsidian daily paneType=window # 在新窗口打开
|
||||||
|
|
||||||
|
obsidian daily:read # 读取今日每日笔记内容(CLI 输出)
|
||||||
|
obsidian daily:path # 获取今日每日笔记的路径
|
||||||
|
|
||||||
|
obsidian daily:append content="- 一条日志" # 追加(自动换行)
|
||||||
|
obsidian daily:append content="## 新章节\n\n正文" open # 追加并打开
|
||||||
|
obsidian daily:append content="inline 内容" inline # 追加不换行
|
||||||
|
|
||||||
|
obsidian daily:prepend content="⚠ 顶部置顶" # 前置(自动换行)
|
||||||
|
obsidian daily:prepend content="紧急" inline # 前置不换行
|
||||||
|
```
|
||||||
|
|
||||||
|
> 💡 **前置依赖**:必须启用 Obsidian 内置的 **Daily Notes** 核心插件(Settings → Core plugins → Daily notes)。可在 **obsidian-plugins** 技能中操作。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## AI Agent 最佳实践
|
||||||
|
|
||||||
|
### 场景 1 · 晨间仪式(Morning Ritual)
|
||||||
|
|
||||||
|
每天早晨第一件事,agent 帮用户生成今日起点:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
TODAY=$(date +%Y-%m-%d)
|
||||||
|
WEEKDAY=$(date +%A)
|
||||||
|
|
||||||
|
# 1. 创建今天的每日笔记(如果还没有)
|
||||||
|
obsidian daily
|
||||||
|
|
||||||
|
# 2. 注入晨间模板
|
||||||
|
obsidian daily:append content="# ${TODAY} · ${WEEKDAY}
|
||||||
|
|
||||||
|
## 🌤 今日概览
|
||||||
|
- 天气:<agent 从 API 拉>
|
||||||
|
- 日程:<agent 从 Calendar 拉>
|
||||||
|
- 优先级:
|
||||||
|
|
||||||
|
## ✅ 今日任务(迁移自昨日未完成)
|
||||||
|
$(obsidian tasks todo verbose format=json | head -20)
|
||||||
|
|
||||||
|
## 📥 灵感捕获
|
||||||
|
-
|
||||||
|
|
||||||
|
## 🧠 深度工作
|
||||||
|
-
|
||||||
|
|
||||||
|
## 📝 AI 操作日志
|
||||||
|
"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 场景 2 · 晚间回顾(Evening Review)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
obsidian daily:append content="
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🌙 晚间回顾 · $(date +%H:%M)
|
||||||
|
|
||||||
|
### 今日成就
|
||||||
|
$(obsidian tasks done verbose format=json | jq -r '.[] | "- ✅ \(.text)"')
|
||||||
|
|
||||||
|
### 未完成(需迁移)
|
||||||
|
$(obsidian tasks todo verbose format=json | jq -r '.[] | "- [ ] \(.text) @\(.file):\(.line)"')
|
||||||
|
|
||||||
|
### 反思
|
||||||
|
> (agent 生成的一段总结:今天做了什么、遇到什么阻塞、明天关注什么)
|
||||||
|
|
||||||
|
### 明日计划
|
||||||
|
- [ ] <从反思推导出的第一优先级>
|
||||||
|
"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 场景 3 · AI 操作审计日志
|
||||||
|
|
||||||
|
**每次 AI agent 对 vault 做写入操作**,在今日笔记留一条记录:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 包装成一个 bash 函数
|
||||||
|
log_agent_action() {
|
||||||
|
local action="$1"
|
||||||
|
local target="$2"
|
||||||
|
local reason="$3"
|
||||||
|
local ts=$(date +%H:%M)
|
||||||
|
|
||||||
|
obsidian daily:append inline content="
|
||||||
|
- \`${ts}\` **${action}** \`${target}\` — ${reason}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 使用示例
|
||||||
|
obsidian property:set name=status value=done file="项目A"
|
||||||
|
log_agent_action "property:set" "项目A" "用户确认项目完成"
|
||||||
|
|
||||||
|
obsidian move path="10-Projects/alpha/README.md" to="40-Archive/alpha/README.md"
|
||||||
|
log_agent_action "move" "alpha → Archive" "项目 Alpha 归档"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 场景 4 · 从每日笔记反向提取事件
|
||||||
|
|
||||||
|
每日笔记是**时间机器**。可以从中提取:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 读取今天所有任务
|
||||||
|
obsidian tasks daily
|
||||||
|
|
||||||
|
# 读取今天的所有内容(agent 做今日总结)
|
||||||
|
obsidian daily:read
|
||||||
|
|
||||||
|
# 获取路径做高级处理
|
||||||
|
DAILY_PATH=$(obsidian daily:path)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 场景 5 · 快速捕获(Quick Capture)
|
||||||
|
|
||||||
|
CLI + daily:append 是**最轻量的知识库捕获入口**,甚至可以做成全局快捷键:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 一行命令捕获想法(可配置系统快捷键调用)
|
||||||
|
obsidian daily:append content="- 💡 $(date +%H:%M) $*"
|
||||||
|
|
||||||
|
# 使用
|
||||||
|
obsidian daily:append content="- 💡 $(date +%H:%M) 虚拟线程配合 jOOQ 可能有死锁风险,待研究"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 场景 6 · 会议记录一键入口
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 会议开始时
|
||||||
|
obsidian daily:append content="
|
||||||
|
|
||||||
|
## 🤝 会议 · $(date +%H:%M) · <会议主题>
|
||||||
|
|
||||||
|
**参会**:@张三 @李四
|
||||||
|
**议程**:
|
||||||
|
-
|
||||||
|
|
||||||
|
**要点**:
|
||||||
|
-
|
||||||
|
|
||||||
|
**行动项**:
|
||||||
|
- [ ]
|
||||||
|
"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 晨间模板示例(可直接复制)
|
||||||
|
|
||||||
|
创建 `70-Templates/daily.md`(由 Obsidian Templates 插件自动填充 `{{date}}` 等变量):
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
---
|
||||||
|
date: {{date:YYYY-MM-DD}}
|
||||||
|
weekday: {{date:dddd}}
|
||||||
|
tags: [daily]
|
||||||
|
weather:
|
||||||
|
mood:
|
||||||
|
---
|
||||||
|
|
||||||
|
# {{date:YYYY-MM-DD}} · {{date:dddd}}
|
||||||
|
|
||||||
|
## 🌅 晨间规划
|
||||||
|
- **今日 Top 3**:
|
||||||
|
1.
|
||||||
|
2.
|
||||||
|
3.
|
||||||
|
- **时间预算**:
|
||||||
|
- 深度工作:
|
||||||
|
- 会议:
|
||||||
|
- 学习:
|
||||||
|
|
||||||
|
## ✅ 任务清单
|
||||||
|
- [ ]
|
||||||
|
|
||||||
|
## 📥 灵感捕获
|
||||||
|
|
||||||
|
## 📝 AI 操作日志
|
||||||
|
|
||||||
|
## 🌙 晚间回顾
|
||||||
|
### 成就
|
||||||
|
### 反思
|
||||||
|
### 明日准备
|
||||||
|
```
|
||||||
|
|
||||||
|
配置方式:Settings → Daily Notes → Template file location → `70-Templates/daily.md`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 与其他技能的协作
|
||||||
|
|
||||||
|
| 场景 | 链路 |
|
||||||
|
|-----|------|
|
||||||
|
| 晨间任务收集 | **obsidian-tasks** → obsidian-daily(append) |
|
||||||
|
| AI 审计日志 | **所有写操作技能** → obsidian-daily(append) |
|
||||||
|
| 周报汇总 | obsidian-daily(read × 7)→ **obsidian-workflow-pkm** |
|
||||||
|
| 模板注入 | **obsidian-plugins**(Templates)+ obsidian-daily |
|
||||||
|
| 会议纪要回链 | **lark-minutes** / **lark-vc** → obsidian-daily |
|
||||||
|
| 日报生成 | obsidian-daily → **huanxi**(report_submit) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 常见陷阱
|
||||||
|
|
||||||
|
| 现象 | 原因 | 对策 |
|
||||||
|
|------|------|------|
|
||||||
|
| `daily` 命令报错 | Daily Notes 插件未启用 | `obsidian plugin:enable id=daily-notes` |
|
||||||
|
| 每日笔记格式不对 | Daily 插件的文件名格式配置错 | Settings → Daily Notes → Date format |
|
||||||
|
| `daily:append` 没有换行 | 默认行为就是追加 | 不需要手动加 `\n` |
|
||||||
|
| 一天的笔记被覆盖 | 误用了 `create` 而非 `append` | 永远用 `daily:append` 或 `daily:prepend` |
|
||||||
|
| 时区错误 | 系统时区与 Obsidian 不一致 | 检查 `date +%Z` 与 Obsidian 设置 |
|
||||||
|
| AI 日志把笔记撑爆 | 无限追加 | 月末归档到 `40-Archive/Daily/YYYY-MM/` |
|
||||||
|
| Template 变量不解析 | 未配置 Templates 核心插件 | 启用 Templates 插件并设置路径 |
|
||||||
@@ -0,0 +1,236 @@
|
|||||||
|
---
|
||||||
|
name: obsidian-history
|
||||||
|
description: Obsidian 版本历史与同步管理:查看/恢复/对比 File Recovery 本地快照(`history:*`)、管理 Obsidian Sync 的暂停与恢复(`sync:*`)、从云端回收站恢复误删文件。触发词:误删、恢复笔记、文件历史、版本恢复、版本对比、diff 笔记、Obsidian Sync、同步暂停。不用于 git 版本控制(直接 Bash git 命令)。Sync 相关命令需付费 Obsidian Sync 订阅。
|
||||||
|
---
|
||||||
|
|
||||||
|
# Obsidian History · 版本历史与同步
|
||||||
|
|
||||||
|
> Obsidian 的**时间旅行层**:File Recovery(本地版本快照)+ Obsidian Sync(云端版本历史)。AI agent 的大规模写入操作需要这一层作为"后悔药"。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 何时使用
|
||||||
|
|
||||||
|
- 查看某文件的**历史版本列表**
|
||||||
|
- **恢复**某文件的某个版本(误删/误改的救命稻草)
|
||||||
|
- **对比**两个版本的差异(diff)
|
||||||
|
- 查看 **Obsidian Sync 状态**(是否同步完成、积压多少)
|
||||||
|
- **暂停/恢复** Obsidian Sync(批量操作前关掉,避免抖动)
|
||||||
|
- 查看**已删除**的文件(云端回收站)
|
||||||
|
|
||||||
|
## 不用于
|
||||||
|
|
||||||
|
- Git 版本控制 → 普通 Bash git 命令
|
||||||
|
- Obsidian 自带回收站(已删除文件) → `obsidian delete` + 手动恢复
|
||||||
|
- 云盘历史版本(iCloud / Dropbox) → 云盘客户端
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 命令速查
|
||||||
|
|
||||||
|
### File Recovery(本地快照,核心插件)
|
||||||
|
|
||||||
|
> Obsidian 内置 "File Recovery" 核心插件自动快照本地版本(默认每 5 分钟,保留 7 天)。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
obsidian history file="重要笔记" # 列出文件的历史版本
|
||||||
|
obsidian history path="10-Projects/alpha/README.md"
|
||||||
|
obsidian history:list # 列出所有有历史的文件
|
||||||
|
|
||||||
|
obsidian history:open file="重要笔记" # 在 Obsidian UI 中打开恢复界面
|
||||||
|
obsidian history:read file="重要笔记" version=1 # 读取第 1 个历史版本
|
||||||
|
obsidian history:read file="重要笔记" version=5 # 读取更早的版本
|
||||||
|
obsidian history:restore file="重要笔记" version=3 # ⚠ 恢复到第 3 个版本(覆盖当前)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Diff 对比
|
||||||
|
|
||||||
|
```bash
|
||||||
|
obsidian diff file="重要笔记" # 列出所有可 diff 的版本
|
||||||
|
obsidian diff file="重要笔记" from=3 to=1 # 版本 3 到版本 1 的差异
|
||||||
|
obsidian diff file="重要笔记" filter=local # 只看本地版本
|
||||||
|
obsidian diff file="重要笔记" filter=sync # 只看 Sync 版本
|
||||||
|
```
|
||||||
|
|
||||||
|
### Obsidian Sync(付费功能)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
obsidian sync:status # 当前同步状态
|
||||||
|
obsidian sync on # 恢复同步
|
||||||
|
obsidian sync off # 暂停同步(批量操作前)
|
||||||
|
|
||||||
|
obsidian sync:deleted # 列出已删除的文件(云端回收站)
|
||||||
|
obsidian sync:deleted total # 数量
|
||||||
|
|
||||||
|
obsidian sync:history file=<name> # 某文件的 Sync 版本历史
|
||||||
|
obsidian sync:history file=<name> total # 版本数
|
||||||
|
obsidian sync:open file=<name> # 在 Obsidian 中打开同步历史界面
|
||||||
|
obsidian sync:read file=<name> version=3 # 读取某 Sync 版本的内容
|
||||||
|
obsidian sync:restore file=<name> version=3 # ⚠ 恢复到某 Sync 版本
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## AI Agent 最佳实践
|
||||||
|
|
||||||
|
### 场景 1 · 危险操作的"后悔药"流程
|
||||||
|
|
||||||
|
AI agent 做批量写入前,先做快照检查点:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
# 批量操作前的保险
|
||||||
|
|
||||||
|
OP_NAME="refactor-project-alpha"
|
||||||
|
BEFORE=$(date +%Y%m%d-%H%M%S)
|
||||||
|
|
||||||
|
# 1. 暂停 Sync(如果启用),避免抖动
|
||||||
|
obsidian sync off 2>/dev/null
|
||||||
|
|
||||||
|
# 2. 记录受影响的文件列表
|
||||||
|
obsidian files folder="10-Projects/alpha" format=json > /tmp/${OP_NAME}-${BEFORE}.json
|
||||||
|
|
||||||
|
# 3. 提交一个 git 检查点(vault 是 git 仓库的话)
|
||||||
|
cd "$(obsidian vault info=path)"
|
||||||
|
git add -A && git commit -m "checkpoint before ${OP_NAME}"
|
||||||
|
|
||||||
|
# 4. 执行批量操作
|
||||||
|
# ... obsidian move / property:set / delete ...
|
||||||
|
|
||||||
|
# 5. 恢复 Sync
|
||||||
|
obsidian sync on
|
||||||
|
|
||||||
|
# 6. 如果出错,用 history 或 git 回退
|
||||||
|
```
|
||||||
|
|
||||||
|
### 场景 2 · 恢复误删的笔记
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. 列出所有有历史的文件
|
||||||
|
obsidian history:list
|
||||||
|
|
||||||
|
# 2. 如果误删了"项目 Alpha",先查是否还能找到历史
|
||||||
|
obsidian history file="项目Alpha"
|
||||||
|
|
||||||
|
# 3. 读取最近的版本内容
|
||||||
|
obsidian history:read file="项目Alpha" version=1
|
||||||
|
|
||||||
|
# 4. 确认无误后恢复
|
||||||
|
obsidian history:restore file="项目Alpha" version=1
|
||||||
|
```
|
||||||
|
|
||||||
|
### 场景 3 · AI 改写对比
|
||||||
|
|
||||||
|
AI agent 改完文章后,和上一版对比看变化:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# AI 修改完一篇文章
|
||||||
|
obsidian create path="drafts/article.md" content="新版本..."
|
||||||
|
|
||||||
|
# 对比与上一版的差异
|
||||||
|
obsidian diff file="article" from=2 to=1
|
||||||
|
```
|
||||||
|
|
||||||
|
### 场景 4 · Sync 状态监控
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 在脚本中检查同步是否完成再继续
|
||||||
|
while true; do
|
||||||
|
STATUS=$(obsidian sync:status)
|
||||||
|
if echo "$STATUS" | grep -q "synced"; then
|
||||||
|
echo "Sync 完成"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
### 场景 5 · 从云端回收站恢复
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 查看云端已删除文件
|
||||||
|
obsidian sync:deleted
|
||||||
|
|
||||||
|
# 对某个误删的文件恢复到某版本
|
||||||
|
obsidian sync:history file="重要笔记"
|
||||||
|
obsidian sync:read file="重要笔记" version=1 # 先确认内容
|
||||||
|
obsidian sync:restore file="重要笔记" version=1
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## File Recovery vs Obsidian Sync 版本历史
|
||||||
|
|
||||||
|
| 特性 | File Recovery(本地) | Obsidian Sync(云端) |
|
||||||
|
|-----|---------------------|---------------------|
|
||||||
|
| 成本 | 免费(核心插件) | 付费订阅 |
|
||||||
|
| 触发 | 每 5 分钟自动(可配置) | 每次修改实时 |
|
||||||
|
| 保留 | 默认 7 天 | 默认 1 年 |
|
||||||
|
| 位置 | 本地 `.obsidian/` 内 | 云端服务器 |
|
||||||
|
| 跨设备 | ❌ | ✅ |
|
||||||
|
| 命令前缀 | `history:*` / `diff filter=local` | `sync:*` / `diff filter=sync` |
|
||||||
|
| 已删除文件恢复 | ❌ | ✅ `sync:deleted` |
|
||||||
|
|
||||||
|
**策略建议**:
|
||||||
|
- 个人单设备 → File Recovery 已够用
|
||||||
|
- 多设备 / 重度 AI 写入 → 强烈推荐 Sync(订阅值回票价)
|
||||||
|
- 强烈推荐同时把 vault 纳入 **git 仓库**,作为第三道保险
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 与 Git 协作的混合策略
|
||||||
|
|
||||||
|
Obsidian 的 history/sync 对**误操作**友好(分钟级粒度),git 对**语义变更**友好(按 commit message 回溯)。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# .gitignore(放在 vault 根目录)
|
||||||
|
.obsidian/workspace*
|
||||||
|
.obsidian/cache
|
||||||
|
.trash/
|
||||||
|
.DS_Store
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 批量 AI 操作的 git 惯例
|
||||||
|
cd $(obsidian vault info=path)
|
||||||
|
|
||||||
|
# 操作前:干净状态
|
||||||
|
git status --porcelain # 应为空
|
||||||
|
git commit --allow-empty -m "checkpoint: before AI refactor"
|
||||||
|
|
||||||
|
# 操作:agent 执行
|
||||||
|
# ...
|
||||||
|
|
||||||
|
# 操作后:按语义提交
|
||||||
|
git add -A
|
||||||
|
git commit -m "ai: refactor zettel links in 50-Zettel/
|
||||||
|
|
||||||
|
- 更新了 42 篇笔记的反链
|
||||||
|
- 重命名了 3 个文件
|
||||||
|
- 自动添加 created 字段到 15 篇旧笔记"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 与其他技能的协作
|
||||||
|
|
||||||
|
| 场景 | 链路 |
|
||||||
|
|-----|------|
|
||||||
|
| 大批量写入前 | **obsidian-history**(checkpoint)→ 其他写入技能 |
|
||||||
|
| Agent 审计回溯 | **obsidian-daily**(审计日志)+ obsidian-history(版本对比) |
|
||||||
|
| 项目归档前 | obsidian-history(sync:status 确认)→ **obsidian**(move) |
|
||||||
|
| 回滚 AI 改写 | **obsidian-search** 找出受影响文件 → obsidian-history:restore |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 常见陷阱
|
||||||
|
|
||||||
|
| 现象 | 原因 | 对策 |
|
||||||
|
|------|------|------|
|
||||||
|
| `history` 命令返回空 | File Recovery 未启用 | `plugin:enable id=file-recovery` |
|
||||||
|
| `sync:*` 命令全部失败 | 未订阅 Obsidian Sync | 用 File Recovery + git 替代 |
|
||||||
|
| `history:restore` 后新改动丢失 | restore 是覆盖 | restore 前先 `read` 保存当前 |
|
||||||
|
| Sync 卡住不同步 | 网络或冲突 | `sync:status` 查看;必要时 `sync off; sync on` |
|
||||||
|
| 批量操作中途失败 | 没做检查点 | 永远先 git commit 或 sync off |
|
||||||
|
| version 编号混乱 | 不同来源混用 | 用 `diff filter=local` 或 `filter=sync` 区分 |
|
||||||
|
| AI 反复 restore 导致循环 | 无终止条件 | agent 写入前记录 baseline,只允许恢复一次 |
|
||||||
@@ -0,0 +1,247 @@
|
|||||||
|
---
|
||||||
|
name: obsidian-meta
|
||||||
|
description: 管理 Obsidian 笔记元数据:YAML frontmatter 属性(status/tags/created/due 等)读写、tag 统计与体系治理、aliases 别名、bookmarks 书签、为 Dataview/Bases 设计字段规范。触发词:frontmatter、设置属性、tag、标签、别名、书签、属性读写。不用于全文搜索(obsidian-search)或 Bases 视图查询(obsidian-bases)。
|
||||||
|
---
|
||||||
|
|
||||||
|
# Obsidian Meta · 元数据管理
|
||||||
|
|
||||||
|
> Frontmatter 属性、标签、别名、书签——Obsidian 的四大元数据系统。这是让 AI agent 结构化理解笔记的关键。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 何时使用
|
||||||
|
|
||||||
|
- 给一篇笔记**设置或读取** frontmatter 属性(`status: draft` / `tags: [tech, arch]` / `due: 2026-05-01`)
|
||||||
|
- **批量维护** YAML 头(比如给所有 `50-Zettel/` 笔记补 `created` 字段)
|
||||||
|
- 统计 vault 中有哪些 tag、每个 tag 下有多少笔记
|
||||||
|
- 管理笔记的 **aliases**(别名,影响 wikilink 解析)
|
||||||
|
- 管理 **bookmarks**(收藏夹,快速跳转)
|
||||||
|
- 为 **Dataview** 或 **Obsidian Bases** 做字段规划
|
||||||
|
|
||||||
|
## 不用于
|
||||||
|
|
||||||
|
- 全文搜索 / 图谱分析 → **obsidian-search**
|
||||||
|
- Bases 视图的结构化查询 → **obsidian-bases**
|
||||||
|
- 任务状态管理(`- [ ]`/`- [x]`)→ **obsidian-tasks**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 命令速查
|
||||||
|
|
||||||
|
### Tags 标签
|
||||||
|
|
||||||
|
```bash
|
||||||
|
obsidian tags # 列出 vault 所有 tag
|
||||||
|
obsidian tags counts # 含出现次数
|
||||||
|
obsidian tags sort=count # 按次数降序
|
||||||
|
obsidian tags format=json # JSON 输出
|
||||||
|
obsidian tags file=<name> # 某文件的 tags
|
||||||
|
obsidian tags active # 当前激活文件的 tags
|
||||||
|
obsidian tags total # 仅返回 tag 数量
|
||||||
|
|
||||||
|
obsidian tag name="tech" # 某 tag 详情
|
||||||
|
obsidian tag name="tech" verbose # 含使用该 tag 的文件列表
|
||||||
|
obsidian tag name="tech" total # 仅返回出现次数
|
||||||
|
```
|
||||||
|
|
||||||
|
### Properties(Frontmatter YAML)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
obsidian properties # 列出 vault 所有属性名(YAML 默认)
|
||||||
|
obsidian properties counts # 含占用文件数
|
||||||
|
obsidian properties sort=count # 按出现次数排序
|
||||||
|
obsidian properties format=json # JSON 输出
|
||||||
|
obsidian properties file=<name> # 某文件的所有属性
|
||||||
|
obsidian properties name="status" # 查看某属性的使用情况
|
||||||
|
|
||||||
|
obsidian property:read name="status" file="项目A"
|
||||||
|
obsidian property:set name="status" value="done" file="项目A"
|
||||||
|
obsidian property:set name="tags" value="tech,arch,java" type=list file="技术笔记"
|
||||||
|
obsidian property:set name="due" value="2026-05-01" type=date file="项目A"
|
||||||
|
obsidian property:set name="priority" value=5 type=number file="项目A"
|
||||||
|
obsidian property:set name="published" value=true type=checkbox file="文章"
|
||||||
|
obsidian property:remove name="old_field" file="项目A"
|
||||||
|
```
|
||||||
|
|
||||||
|
**属性类型**:`text | list | number | checkbox | date | datetime`
|
||||||
|
|
||||||
|
### Aliases 别名
|
||||||
|
|
||||||
|
```bash
|
||||||
|
obsidian aliases # 列出 vault 所有别名
|
||||||
|
obsidian aliases verbose # 含文件路径
|
||||||
|
obsidian aliases total # 仅返回数量
|
||||||
|
obsidian aliases file=<name> # 某文件的别名
|
||||||
|
obsidian aliases active # 当前激活文件的别名
|
||||||
|
```
|
||||||
|
|
||||||
|
> 💡 Aliases 通过 frontmatter `aliases: [...]` 设置,影响 wikilink 解析——`[[别名]]` 会解析到原笔记。
|
||||||
|
|
||||||
|
### Bookmarks 书签
|
||||||
|
|
||||||
|
```bash
|
||||||
|
obsidian bookmarks # 列出所有书签(tsv 默认)
|
||||||
|
obsidian bookmarks verbose # 含类型(file/folder/search/url)
|
||||||
|
obsidian bookmarks format=json
|
||||||
|
|
||||||
|
obsidian bookmark file="重要笔记" # 添加文件书签
|
||||||
|
obsidian bookmark file="重要笔记" subpath="## 章节" # 指定标题/块
|
||||||
|
obsidian bookmark folder="10-Projects" # 文件夹书签
|
||||||
|
obsidian bookmark search="TODO" # 搜索书签
|
||||||
|
obsidian bookmark url="https://..." title="官方文档" # URL 书签
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## AI Agent 最佳实践
|
||||||
|
|
||||||
|
### 场景 1 · Frontmatter 规范模板(写在 SCHEMA.md)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
---
|
||||||
|
# 身份
|
||||||
|
title: 笔记标题
|
||||||
|
aliases: [] # 别名列表
|
||||||
|
|
||||||
|
# 时间
|
||||||
|
created: 2026-04-09
|
||||||
|
updated: 2026-04-09
|
||||||
|
|
||||||
|
# 分类
|
||||||
|
type: note | project | area | resource | zettel | literature | moc
|
||||||
|
status: draft | active | done | archived
|
||||||
|
tags: [domain, subdomain]
|
||||||
|
|
||||||
|
# 项目专属
|
||||||
|
due: 2026-05-01
|
||||||
|
priority: 1-5
|
||||||
|
owner: name
|
||||||
|
|
||||||
|
# 永久笔记专属(Zettelkasten)
|
||||||
|
zettel_id: 202604091530
|
||||||
|
refs: [[[相关笔记1]], [[相关笔记2]]]
|
||||||
|
source: book | paper | url
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
||||||
|
**字段选型原则**:
|
||||||
|
- **通用字段**(所有笔记都有):`title / created / updated / status / tags`
|
||||||
|
- **可选字段**(按 type 触发):`due / priority / owner / zettel_id / source`
|
||||||
|
- **机器字段**(agent 写入):`last_ai_touched / ai_summary / review_count`
|
||||||
|
|
||||||
|
### 场景 2 · 批量补全 created/updated 字段
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 找出所有缺 created 字段的笔记
|
||||||
|
obsidian files folder="50-Zettel" format=json | \
|
||||||
|
# 由 agent 逐个 property:read name=created file=...
|
||||||
|
# 如果返回空,则从文件 mtime 推断
|
||||||
|
# obsidian property:set name=created value="2024-01-15" type=date file=...
|
||||||
|
```
|
||||||
|
|
||||||
|
### 场景 3 · 状态机流转
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 项目从 active → done
|
||||||
|
obsidian property:read name=status file="项目Alpha" # 先读现状
|
||||||
|
obsidian property:set name=status value=done file="项目Alpha"
|
||||||
|
obsidian property:set name=updated value=$(date +%Y-%m-%d) type=date file="项目Alpha"
|
||||||
|
|
||||||
|
# 可配合 obsidian-workflow-pkm 做 PARA 归档:
|
||||||
|
# done → 2 周无动作 → 移到 40-Archive/
|
||||||
|
```
|
||||||
|
|
||||||
|
### 场景 4 · Tag 体系治理
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. 扫描所有 tag 统计
|
||||||
|
obsidian tags counts sort=count format=json > /tmp/tags.json
|
||||||
|
|
||||||
|
# 2. 由 agent 分析:
|
||||||
|
# - 低频 tag(< 3 次)是否可合并
|
||||||
|
# - 命名不一致(#Tech vs #tech)的归一化
|
||||||
|
# - 层级化(#area/tech、#area/design)
|
||||||
|
|
||||||
|
# 3. 找出含某 tag 的所有文件,批量替换
|
||||||
|
obsidian tag name="Tech" verbose # 拿到文件列表
|
||||||
|
# 对每个文件: property:set name=tags value="..." type=list
|
||||||
|
```
|
||||||
|
|
||||||
|
**tag 层级推荐**(结合 Obsidian 原生层级 tag 支持):
|
||||||
|
|
||||||
|
```
|
||||||
|
#area/tech #status/draft
|
||||||
|
#area/design #status/active
|
||||||
|
#area/ops #status/done
|
||||||
|
#status/archived
|
||||||
|
#project/alpha
|
||||||
|
#project/beta #type/zettel
|
||||||
|
#type/moc
|
||||||
|
#type/literature
|
||||||
|
```
|
||||||
|
|
||||||
|
### 场景 5 · 用属性替代文件夹(动态视图)
|
||||||
|
|
||||||
|
Obsidian 的现代理念:**属性优于文件夹**。不用深层目录,而是用 frontmatter 做动态筛选。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 所有 "active 项目" 用 property 查(配合 obsidian-bases)
|
||||||
|
obsidian property:set name=status value=active file="项目X"
|
||||||
|
|
||||||
|
# 然后在 obsidian-bases 里建一个视图:
|
||||||
|
# view: "进行中项目" where: status == "active" sort: due asc
|
||||||
|
```
|
||||||
|
|
||||||
|
### 场景 6 · 别名用于多语言/多写法
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
---
|
||||||
|
title: Virtual Threads
|
||||||
|
aliases: [虚拟线程, 协程-Java 版, Project Loom]
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
||||||
|
wiki 中写 `[[虚拟线程]]` 或 `[[Project Loom]]` 都能链到同一篇。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Dataview / Bases 字段设计建议
|
||||||
|
|
||||||
|
> 参考:dsebastien《Dataview frontmatter guide》、blacksmithgu/obsidian-dataview 文档
|
||||||
|
|
||||||
|
| 字段类型 | 示例 | Dataview 友好 | Bases 友好 | 备注 |
|
||||||
|
|---------|------|-------------|-----------|------|
|
||||||
|
| `text` | `title: 笔记` | ✅ | ✅ | 基础字符串 |
|
||||||
|
| `list` | `tags: [a,b]` | ✅ | ✅ | 多值用列表 |
|
||||||
|
| `number` | `priority: 3` | ✅(支持运算) | ✅ | 可排序可筛选 |
|
||||||
|
| `checkbox` | `done: true` | ✅ | ✅ | 布尔值 |
|
||||||
|
| `date` | `due: 2026-05-01` | ✅(支持 duration) | ✅ | 必须用 ISO 格式 |
|
||||||
|
| `datetime` | `created: 2026-04-09T10:30` | ✅ | ✅ | 含时间戳 |
|
||||||
|
| inline 字段 | `Key:: Value` | ✅ 仅 Dataview | ❌ Bases 不支持 | **Bases 只认 frontmatter,不认 inline** |
|
||||||
|
|
||||||
|
**铁律**:如果你用 Bases,**永远用 frontmatter**,不要用 `Key:: Value` inline 字段。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 与其他技能的协作
|
||||||
|
|
||||||
|
| 场景 | 链路 |
|
||||||
|
|-----|------|
|
||||||
|
| 搜索命中后筛选 | **obsidian-search** → obsidian-meta(按 tag/status 二次过滤) |
|
||||||
|
| 批量属性维护 | obsidian-meta + **obsidian**(files 列出目标) |
|
||||||
|
| 按属性查询 | obsidian-meta(写入)→ **obsidian-bases**(查询展示) |
|
||||||
|
| 任务联动 | obsidian-meta(`status: done`)+ **obsidian-tasks**(`- [x]`) |
|
||||||
|
| 每日笔记自动打标签 | **obsidian-daily** + obsidian-meta |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 常见陷阱
|
||||||
|
|
||||||
|
| 现象 | 原因 | 对策 |
|
||||||
|
|------|------|------|
|
||||||
|
| `property:set` 后 Obsidian 不显示 | 打开的是缓存视图 | `obsidian reload` 或重新打开笔记 |
|
||||||
|
| 日期字段在 Dataview 里无法排序 | 写成了 text 类型 | `property:set type=date` 明确类型 |
|
||||||
|
| Bases 读不到 `Key:: Value` | Bases 只认 frontmatter | 把 inline 字段改写到 YAML 头 |
|
||||||
|
| 属性值含特殊字符报错 | YAML 特殊字符未引号 | 含 `: [] {} #` 的值必须加 `""` |
|
||||||
|
| tag 层级识别错误 | 中间有空格 | 层级 tag 不能有空格:`#area/tech` ✅,`#area/ tech` ❌ |
|
||||||
|
| 批量改 tag 覆盖了已有 tag | `property:set` 是覆盖不是追加 | 先 `property:read`,合并后再 `set` |
|
||||||
@@ -0,0 +1,284 @@
|
|||||||
|
---
|
||||||
|
name: obsidian-plugins
|
||||||
|
description: 管理 Obsidian 环境层配置——插件(核心/社区,启用/禁用/安装/卸载)、主题切换、CSS snippets、Templates 模板、内置命令(command id)、快捷键 hotkeys。高频场景:首次配置 vault 时批量装常用插件、按团队规范统一主题/CSS。触发词:启用插件、社区插件、Obsidian 主题、CSS snippet、Templates、快捷键、hotkey、内置命令、首次配置 vault、安装插件。不用于笔记内容 CRUD(obsidian 核心技能),不用于 frontmatter 属性(obsidian-meta)。
|
||||||
|
---
|
||||||
|
|
||||||
|
# Obsidian Plugins · 环境配置管理
|
||||||
|
|
||||||
|
> Obsidian 的"控制面板":插件、主题、CSS、模板、命令、快捷键。一份技能管完所有环境配置。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 何时使用
|
||||||
|
|
||||||
|
- **启用/禁用/安装/卸载**核心或社区插件
|
||||||
|
- 切换 / 安装 / 卸载**主题**
|
||||||
|
- 管理 **CSS snippets**(自定义样式片段)
|
||||||
|
- 管理 **Templates**(Obsidian Templates 核心插件的模板文件)
|
||||||
|
- 查看 / 执行 Obsidian 内置**命令**(`obsidian command id=...`)
|
||||||
|
- 查询 / 管理**快捷键**(hotkeys)
|
||||||
|
- 切换 **Restricted Mode**(安全模式,禁用社区插件)
|
||||||
|
|
||||||
|
## 不用于
|
||||||
|
|
||||||
|
- 笔记内容 CRUD → **obsidian** 核心技能
|
||||||
|
- Frontmatter 管理 → **obsidian-meta**
|
||||||
|
- Vault 层面同步设置 → **obsidian-history**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 命令速查
|
||||||
|
|
||||||
|
### 插件(Plugins)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 列出
|
||||||
|
obsidian plugins # 列出所有已安装插件(tsv 默认)
|
||||||
|
obsidian plugins filter=core # 只看核心插件
|
||||||
|
obsidian plugins filter=community # 只看社区插件
|
||||||
|
obsidian plugins versions # 含版本号
|
||||||
|
obsidian plugins format=json # JSON 输出
|
||||||
|
|
||||||
|
obsidian plugins:enabled # 只列启用的
|
||||||
|
obsidian plugins:enabled filter=community versions format=json
|
||||||
|
|
||||||
|
obsidian plugin id=dataview # 某插件详情
|
||||||
|
obsidian plugin id=<id> # 通过 ID 查询
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 启用/禁用/安装/卸载
|
||||||
|
obsidian plugin:enable id=daily-notes # 启用核心插件
|
||||||
|
obsidian plugin:enable id=dataview filter=community
|
||||||
|
obsidian plugin:disable id=dataview filter=community
|
||||||
|
obsidian plugin:install id=obsidian-git enable # 安装并立即启用(社区)
|
||||||
|
obsidian plugin:uninstall id=dataview
|
||||||
|
obsidian plugin:reload id=dataview # 开发用:重载插件
|
||||||
|
```
|
||||||
|
|
||||||
|
### 安全模式(Restricted Mode)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
obsidian plugins:restrict on # 开启受限模式(禁用所有社区插件)
|
||||||
|
obsidian plugins:restrict off # 关闭
|
||||||
|
obsidian plugins:restrict # 查询状态
|
||||||
|
```
|
||||||
|
|
||||||
|
### 主题(Themes)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
obsidian themes # 列出所有已安装主题
|
||||||
|
obsidian themes versions # 含版本号
|
||||||
|
obsidian theme # 当前主题
|
||||||
|
obsidian theme name="Minimal" # 某主题详情
|
||||||
|
|
||||||
|
obsidian theme:set name="Minimal" # 切换主题
|
||||||
|
obsidian theme:set name="" # 恢复默认
|
||||||
|
obsidian theme:install name="Minimal" enable # 安装并启用
|
||||||
|
obsidian theme:uninstall name="Minimal"
|
||||||
|
```
|
||||||
|
|
||||||
|
### CSS Snippets
|
||||||
|
|
||||||
|
```bash
|
||||||
|
obsidian snippets # 列出所有已安装 snippets
|
||||||
|
obsidian snippets:enabled # 已启用的
|
||||||
|
|
||||||
|
obsidian snippet:enable name="compact-tables"
|
||||||
|
obsidian snippet:disable name="compact-tables"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Templates(核心插件)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
obsidian templates # 列出所有模板
|
||||||
|
obsidian templates total # 数量
|
||||||
|
|
||||||
|
obsidian template:read name="daily" # 读取模板内容
|
||||||
|
obsidian template:read name="daily" resolve title="2026-04-09" # 解析变量后读取
|
||||||
|
|
||||||
|
obsidian template:insert name="meeting" # 插入到当前激活文件
|
||||||
|
```
|
||||||
|
|
||||||
|
> 💡 Templates 插件需要先启用:`obsidian plugin:enable id=templates` 并在设置中指定模板文件夹。
|
||||||
|
|
||||||
|
### Commands(Obsidian 内置命令系统)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
obsidian commands # 列出所有可用命令
|
||||||
|
obsidian commands filter=editor # 按前缀筛选
|
||||||
|
obsidian commands filter=daily # 每日笔记相关命令
|
||||||
|
|
||||||
|
obsidian command id="editor:toggle-bold" # 执行命令(触发 Obsidian 内部动作)
|
||||||
|
obsidian command id="workspace:split-vertical"
|
||||||
|
obsidian command id="app:go-back"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Hotkeys 快捷键
|
||||||
|
|
||||||
|
```bash
|
||||||
|
obsidian hotkeys # 列出所有快捷键(tsv)
|
||||||
|
obsidian hotkeys format=json
|
||||||
|
obsidian hotkeys all # 含未绑定快捷键的命令
|
||||||
|
obsidian hotkeys verbose # 显示是否自定义
|
||||||
|
obsidian hotkeys total # 数量
|
||||||
|
|
||||||
|
obsidian hotkey id="editor:toggle-bold" # 查询某命令的快捷键
|
||||||
|
obsidian hotkey id="editor:toggle-bold" verbose
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## AI Agent 最佳实践
|
||||||
|
|
||||||
|
### 场景 1 · 首次配置检查清单
|
||||||
|
|
||||||
|
Agent 第一次进入某 vault,验证基础环境:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
# obsidian-doctor.sh:环境体检
|
||||||
|
|
||||||
|
echo "=== Vault 基础 ==="
|
||||||
|
obsidian vault info=name
|
||||||
|
obsidian version
|
||||||
|
|
||||||
|
echo "=== 核心插件启用状态 ==="
|
||||||
|
REQUIRED=("daily-notes" "templates" "file-recovery" "command-palette" "backlink" "outgoing-link")
|
||||||
|
for p in "${REQUIRED[@]}"; do
|
||||||
|
STATUS=$(obsidian plugin id=$p 2>/dev/null | grep -o 'enabled: true' && echo "✅" || echo "❌ $p 未启用")
|
||||||
|
echo "$STATUS"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "=== 社区插件 ==="
|
||||||
|
obsidian plugins filter=community versions
|
||||||
|
|
||||||
|
echo "=== 主题 ==="
|
||||||
|
obsidian theme
|
||||||
|
|
||||||
|
echo "=== 受限模式 ==="
|
||||||
|
obsidian plugins:restrict
|
||||||
|
```
|
||||||
|
|
||||||
|
### 场景 2 · 为 AI 工作流推荐的最小插件集
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 启用核心插件(最小集)
|
||||||
|
obsidian plugin:enable id=daily-notes
|
||||||
|
obsidian plugin:enable id=templates
|
||||||
|
obsidian plugin:enable id=file-recovery
|
||||||
|
obsidian plugin:enable id=backlink
|
||||||
|
obsidian plugin:enable id=outgoing-link
|
||||||
|
obsidian plugin:enable id=tag-pane
|
||||||
|
obsidian plugin:enable id=graph
|
||||||
|
obsidian plugin:enable id=properties # Obsidian 1.4+ 的属性面板
|
||||||
|
|
||||||
|
# 可选:启用 Bases(1.9+)
|
||||||
|
obsidian plugin:enable id=bases
|
||||||
|
```
|
||||||
|
|
||||||
|
**推荐社区插件**(AI 协作友好):
|
||||||
|
|
||||||
|
| 插件 ID | 用途 | 何时需要 |
|
||||||
|
|---------|------|---------|
|
||||||
|
| `obsidian-git` | Git 集成 | 永远需要(vault 备份) |
|
||||||
|
| `templater-obsidian` | 高级模板(JS 可执行) | 动态模板 |
|
||||||
|
| `dataview` | 查询语言 | 还没迁移到 Bases |
|
||||||
|
| `tasks` | 高级任务管理 | 重度 GTD 用户 |
|
||||||
|
| `calendar` | 日历侧栏 | 频繁用每日笔记 |
|
||||||
|
| `advanced-uri` | URI 命令增强 | 脚本化自动化 |
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 批量安装
|
||||||
|
for p in obsidian-git templater-obsidian tasks calendar; do
|
||||||
|
obsidian plugin:install id=$p enable
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
### 场景 3 · 动态调用 Obsidian 内部命令
|
||||||
|
|
||||||
|
`obsidian command id=...` 可以执行**任意** Obsidian 命令,相当于 UI 层的自动化:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 拆分工作区(左侧文件树 + 右侧编辑)
|
||||||
|
obsidian command id="workspace:split-vertical"
|
||||||
|
|
||||||
|
# 打开快速切换器
|
||||||
|
obsidian command id="switcher:open"
|
||||||
|
|
||||||
|
# 打开命令面板(不常用,因为命令面板本身是交互式 UI)
|
||||||
|
obsidian command id="command-palette:open"
|
||||||
|
|
||||||
|
# 切换 Reading View
|
||||||
|
obsidian command id="markdown:toggle-preview"
|
||||||
|
|
||||||
|
# 折叠所有标题
|
||||||
|
obsidian command id="editor:fold-all"
|
||||||
|
```
|
||||||
|
|
||||||
|
**发现命令 ID**:`obsidian commands | less` 或 `obsidian commands filter=<prefix>`。
|
||||||
|
|
||||||
|
### 场景 4 · 模板驱动的笔记创建
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. 先看有哪些模板
|
||||||
|
obsidian templates
|
||||||
|
|
||||||
|
# 2. 预览模板内容
|
||||||
|
obsidian template:read name="project-kickoff" resolve title="Alpha"
|
||||||
|
|
||||||
|
# 3. 基于模板创建新笔记(通过 create + content)
|
||||||
|
CONTENT=$(obsidian template:read name="project-kickoff" resolve title="Alpha")
|
||||||
|
obsidian create path="10-Projects/alpha/README.md" content="$CONTENT" open
|
||||||
|
```
|
||||||
|
|
||||||
|
### 场景 5 · CSS Snippet 自动切换(深色/浅色模式)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 检测系统时间切换不同的 CSS snippet
|
||||||
|
HOUR=$(date +%H)
|
||||||
|
if [ "$HOUR" -ge 19 ] || [ "$HOUR" -lt 7 ]; then
|
||||||
|
obsidian snippet:enable name="dark-extra"
|
||||||
|
obsidian snippet:disable name="light-extra"
|
||||||
|
else
|
||||||
|
obsidian snippet:enable name="light-extra"
|
||||||
|
obsidian snippet:disable name="dark-extra"
|
||||||
|
fi
|
||||||
|
```
|
||||||
|
|
||||||
|
### 场景 6 · 快捷键审计
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 查自定义过的快捷键(避免冲突)
|
||||||
|
obsidian hotkeys verbose format=json | jq '.[] | select(.custom == true)'
|
||||||
|
|
||||||
|
# 查没有快捷键绑定的命令(发现可以加快捷键的命令)
|
||||||
|
obsidian hotkeys all format=json | jq '.[] | select(.hotkey == null)'
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 与其他技能的协作
|
||||||
|
|
||||||
|
| 场景 | 链路 |
|
||||||
|
|-----|------|
|
||||||
|
| 启用 Daily Notes 前置 | obsidian-plugins → **obsidian-daily** |
|
||||||
|
| 启用 Bases 前置 | obsidian-plugins(`plugin:enable id=bases`)→ **obsidian-bases** |
|
||||||
|
| 启用 Templates 前置 | obsidian-plugins → **obsidian-daily**(daily template) |
|
||||||
|
| 启用 File Recovery 前置 | obsidian-plugins → **obsidian-history** |
|
||||||
|
| 推荐插件清单 | obsidian-plugins + **obsidian-workflow-pkm** |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 常见陷阱
|
||||||
|
|
||||||
|
| 现象 | 原因 | 对策 |
|
||||||
|
|------|------|------|
|
||||||
|
| `plugin:install` 失败 | 处于 Restricted Mode | `plugins:restrict off` |
|
||||||
|
| 社区插件 ID 写错 | 大小写/连字符敏感 | 先 `plugins filter=community` 查正确 ID |
|
||||||
|
| `command id=...` 无效 | 命令 ID 写错 | `commands filter=<prefix>` 查询 |
|
||||||
|
| Template 变量未解析 | 没加 `resolve` 参数 | `template:read name=<n> resolve` |
|
||||||
|
| Templates 插件找不到模板 | 模板文件夹没配 | Settings → Templates → Template folder location |
|
||||||
|
| 切主题后样式错乱 | 新主题与某 snippet 冲突 | 临时 `snippet:disable` 所有 |
|
||||||
|
| 社区插件升级后命令失效 | 插件 API 变更 | `plugin:reload` 或重启 Obsidian |
|
||||||
|
| Restricted Mode 下 agent 脚本报错 | Community 插件全部禁用 | 脚本增加 `plugins:restrict` 检查 |
|
||||||
@@ -0,0 +1,185 @@
|
|||||||
|
---
|
||||||
|
name: obsidian-search
|
||||||
|
description: Obsidian vault 全文搜索与链接图谱分析。触发场景:搜索笔记内容、查反链/出链、体检图谱健康度(孤立笔记 orphans、断头笔记 deadends、未解析链接 unresolved)、AI 回答前做语义召回(RAG)。触发词:搜索笔记、找笔记、反链、出链、孤立笔记、图谱体检、知识库体检。不用于 tag 查询(obsidian-meta)或 Bases 结构化查询(obsidian-bases)。
|
||||||
|
---
|
||||||
|
|
||||||
|
# Obsidian Search · 搜索与图谱分析
|
||||||
|
|
||||||
|
> 官方 `obsidian` CLI 的搜索与链接分析子集。让 AI agent 能像读取一个知识图谱数据库一样理解你的 vault。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 何时使用
|
||||||
|
|
||||||
|
- 全文搜索笔记内容(关键词、正则、限定文件夹)
|
||||||
|
- 找到一篇笔记的**反链**(谁引用了我)或**出链**(我引用了谁)
|
||||||
|
- **图谱健康度体检**:找出孤立笔记、没有出链的断头、未解析的坏链
|
||||||
|
- 在 AI agent 做问答/总结前,**先做语义召回**,把最相关的几篇文章喂给模型
|
||||||
|
|
||||||
|
## 不用于
|
||||||
|
|
||||||
|
- 查找含某 **tag** 的笔记 → **obsidian-meta** (`tags`, `tag name=<tag> verbose`)
|
||||||
|
- 查询 frontmatter **property** → **obsidian-meta** (`properties`, `property:read`)
|
||||||
|
- 按 Bases 视图结构化查询 → **obsidian-bases**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 命令速查
|
||||||
|
|
||||||
|
### 全文搜索
|
||||||
|
|
||||||
|
```bash
|
||||||
|
obsidian search query="云原生" # 基础全文搜索
|
||||||
|
obsidian search query="云原生" path="10-Projects" # 限定文件夹
|
||||||
|
obsidian search query="云原生" limit=20 # 限制结果数
|
||||||
|
obsidian search query="云原生" case # 区分大小写
|
||||||
|
obsidian search query="云原生" total # 只返回匹配计数
|
||||||
|
obsidian search query="云原生" format=json # JSON 输出(agent 友好)
|
||||||
|
|
||||||
|
obsidian search:context query="云原生" # 搜索 + 显示匹配行上下文
|
||||||
|
obsidian search:context query="云原生" format=json
|
||||||
|
|
||||||
|
obsidian search:open query="云原生" # 在 Obsidian 中打开搜索面板
|
||||||
|
```
|
||||||
|
|
||||||
|
### 出链 / 反链
|
||||||
|
|
||||||
|
```bash
|
||||||
|
obsidian links file="云原生运行时经济学" # 当前笔记出链
|
||||||
|
obsidian links file=<name> total # 只返回出链数
|
||||||
|
|
||||||
|
obsidian backlinks file=<name> # 反链(tsv 默认)
|
||||||
|
obsidian backlinks file=<name> counts # 含每个反链的引用次数
|
||||||
|
obsidian backlinks file=<name> format=json # JSON 输出
|
||||||
|
obsidian backlinks file=<name> total # 反链总数
|
||||||
|
```
|
||||||
|
|
||||||
|
### 图谱健康度(三件套)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
obsidian orphans # 孤立笔记(没有任何反链 = 没人引用我)
|
||||||
|
obsidian orphans total # 仅返回数量
|
||||||
|
obsidian orphans all # 含非 markdown 文件
|
||||||
|
|
||||||
|
obsidian deadends # 断头笔记(没有任何出链 = 我没引用任何人)
|
||||||
|
obsidian deadends total
|
||||||
|
|
||||||
|
obsidian unresolved # 未解析链接(链接指向不存在的笔记)
|
||||||
|
obsidian unresolved counts # 含每个坏链的引用次数
|
||||||
|
obsidian unresolved verbose # 含源文件
|
||||||
|
obsidian unresolved format=json
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## AI Agent 最佳实践
|
||||||
|
|
||||||
|
### 场景 1 · 做问答前的语义召回
|
||||||
|
|
||||||
|
AI agent 回答用户问题时,不要只凭记忆编造,而要先做召回:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Step 1: 全文搜索,拿到 top-20 候选
|
||||||
|
obsidian search:context query="<用户问题关键词>" limit=20 format=json
|
||||||
|
|
||||||
|
# Step 2: 根据匹配摘要挑 3~5 篇最相关的,逐篇 read
|
||||||
|
obsidian read file="<候选 1>"
|
||||||
|
obsidian read file="<候选 2>"
|
||||||
|
|
||||||
|
# Step 3: 基于检索到的内容回答,并标注来源
|
||||||
|
```
|
||||||
|
|
||||||
|
这是 **RAG(Retrieval-Augmented Generation)的 CLI 实现**,无需向量数据库。
|
||||||
|
|
||||||
|
### 场景 2 · 知识库季度体检
|
||||||
|
|
||||||
|
每季度跑一次"三件套"健康检查,清理知识库:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 孤立笔记(可能是废稿,或需要补反链)
|
||||||
|
obsidian orphans format=json > /tmp/orphans.json
|
||||||
|
|
||||||
|
# 断头笔记(需要补充关联阅读)
|
||||||
|
obsidian deadends > /tmp/deadends.txt
|
||||||
|
|
||||||
|
# 未解析链接(笔记被删除或重命名导致的坏链)
|
||||||
|
obsidian unresolved verbose format=json > /tmp/unresolved.json
|
||||||
|
```
|
||||||
|
|
||||||
|
**处理建议**(交给 AI agent 分类):
|
||||||
|
|
||||||
|
| 类型 | 判定 | 处理 |
|
||||||
|
|------|------|------|
|
||||||
|
| 孤立笔记 | 正文 > 200 字 | 读内容,找相关主题补反链 |
|
||||||
|
| 孤立笔记 | 正文 ≤ 200 字 | 可能是废稿,移到 `00-Inbox/` 待清理 |
|
||||||
|
| 断头笔记 | 永久笔记(`50-Zettel/`) | 违反 Zettelkasten 原则,**必须补出链** |
|
||||||
|
| 断头笔记 | 日常笔记 | 一般可接受 |
|
||||||
|
| 未解析链接 | 指向已删除笔记 | 删除或修复链接 |
|
||||||
|
| 未解析链接 | 指向未来笔记(占位) | 保留,或创建占位笔记 |
|
||||||
|
|
||||||
|
### 场景 3 · 重命名前的安全检查
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 准备把 "旧标题" 改名为 "新标题"
|
||||||
|
obsidian backlinks file="旧标题" format=json # 先看谁引用我
|
||||||
|
|
||||||
|
# 如果反链数 > 0,且文件是 markdown 链接而非 wikilink,需要手动修复
|
||||||
|
# wikilink [[旧标题]] 会被 obsidian move 自动更新
|
||||||
|
# markdown [链接](旧标题.md) 需要手动替换
|
||||||
|
|
||||||
|
obsidian move path="50-Zettel/旧标题.md" to="50-Zettel/新标题.md"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 场景 4 · 为新笔记找"相关阅读"
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 写完一篇新笔记后,自动找出 vault 中相关的旧笔记
|
||||||
|
TITLE="云原生运行时经济学"
|
||||||
|
KEYWORDS=("云原生" "运行时" "成本" "密度")
|
||||||
|
|
||||||
|
for kw in "${KEYWORDS[@]}"; do
|
||||||
|
obsidian search query="$kw" limit=5 format=json
|
||||||
|
done
|
||||||
|
# 由 agent 合并去重,挑出 top-3 ~ 5 篇,在新笔记末尾插入 "## 相关阅读" 区块
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Agent 写入模式:把搜索结果转成笔记
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 搜索 + 写入结果到一篇"检索报告"
|
||||||
|
QUERY="虚拟线程"
|
||||||
|
obsidian create path="99-Log/search-${QUERY}-$(date +%Y%m%d).md" content="# 检索报告: ${QUERY}
|
||||||
|
|
||||||
|
生成时间: $(date '+%Y-%m-%d %H:%M')
|
||||||
|
|
||||||
|
## 全文匹配
|
||||||
|
$(obsidian search:context query=\"${QUERY}\" limit=20)
|
||||||
|
|
||||||
|
## 反链分析
|
||||||
|
(针对 top-3 笔记的反链分析)
|
||||||
|
"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 与其他技能的协作
|
||||||
|
|
||||||
|
| 前置 → 当前 → 后继 | 典型链路 |
|
||||||
|
|------------------|---------|
|
||||||
|
| **obsidian** → obsidian-search → **obsidian-meta** | 先发现 vault,再搜索定位,再读 frontmatter |
|
||||||
|
| **obsidian-search** → **obsidian-meta** | 搜索后用 tags 做二次筛选 |
|
||||||
|
| **obsidian-search** → **obsidian-workflow-pkm** | 搜索结果作为 Zettelkasten 补链、MOC 构建的输入 |
|
||||||
|
| **obsidian-search** → **obsidian** (`read`) | 搜索召回 → 逐篇精读 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 常见陷阱
|
||||||
|
|
||||||
|
| 现象 | 原因 | 对策 |
|
||||||
|
|------|------|------|
|
||||||
|
| `search` 结果太多 | 未加 `limit` | `limit=20 path=<folder>` 双重限定 |
|
||||||
|
| `backlinks` 为空但确实有引用 | 用的是 markdown 链接而非 wikilink | `search query="[文件名]"` 兜底 |
|
||||||
|
| `orphans` 把每日笔记也列进来 | daily note 一般无人引用 | 在 agent 逻辑里过滤 `90-Daily/` 路径 |
|
||||||
|
| `unresolved` 出现"未来占位" | 预先写了 `[[未创建的笔记]]` | 占位是 Zettelkasten 合法模式,不要自动删 |
|
||||||
@@ -0,0 +1,218 @@
|
|||||||
|
---
|
||||||
|
name: obsidian-tasks
|
||||||
|
description: 管理 Obsidian vault 中基于 Markdown 复选框(`- [ ]`/`- [x]`)的任务清单与 GTD 工作流:跨文件列出/筛选任务、切换单条任务状态、项目进度统计、收集-处理-执行流程。触发词:todo、待办、任务清单、完成任务、GTD、任务状态。不用于 Linear/飞书任务(linear/lark-task),不用于 frontmatter status 字段(obsidian-meta)。
|
||||||
|
---
|
||||||
|
|
||||||
|
# Obsidian Tasks · 任务清单管理
|
||||||
|
|
||||||
|
> 基于 Markdown 复选框语法 `- [ ]` / `- [x]` 的任务管理子集。每个任务 = 笔记某一行。适合 GTD(Getting Things Done)与 Zettelkasten 流程化任务。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 何时使用
|
||||||
|
|
||||||
|
- 列出 vault 中**所有任务**(跨文件)
|
||||||
|
- 筛选**未完成**(todo)或**已完成**(done)的任务
|
||||||
|
- 按**状态字符**筛选(`- [ ]` 待办、`- [x]` 完成、`- [/]` 进行中、`- [?]` 存疑等)
|
||||||
|
- **切换单个任务**状态(ref = `path:line`)
|
||||||
|
- 配合每日笔记做 GTD 收集/回顾流程
|
||||||
|
|
||||||
|
## 不用于
|
||||||
|
|
||||||
|
- Linear issue → **linear** 技能
|
||||||
|
- 飞书任务 → **lark-task** 技能
|
||||||
|
- Frontmatter 级别的 `status: done` → **obsidian-meta**(那是笔记级状态,不是任务级)
|
||||||
|
- 任务的视觉化看板 → **obsidian-bases** + obsidian-tasks
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 命令速查
|
||||||
|
|
||||||
|
### 列出任务
|
||||||
|
|
||||||
|
```bash
|
||||||
|
obsidian tasks # vault 所有任务(text 默认)
|
||||||
|
obsidian tasks todo # 只列未完成
|
||||||
|
obsidian tasks done # 只列已完成
|
||||||
|
obsidian tasks verbose # 按文件分组,含行号
|
||||||
|
obsidian tasks format=json # JSON 输出(agent 友好)
|
||||||
|
obsidian tasks total # 仅返回任务总数
|
||||||
|
|
||||||
|
obsidian tasks file="项目Alpha" # 某文件的任务
|
||||||
|
obsidian tasks path="10-Projects/alpha/README.md"
|
||||||
|
obsidian tasks active # 当前激活文件的任务
|
||||||
|
obsidian tasks daily # 今天每日笔记的任务
|
||||||
|
|
||||||
|
obsidian tasks status="/" # 按自定义状态字符筛选(进行中)
|
||||||
|
obsidian tasks status="?" # 存疑
|
||||||
|
obsidian tasks status="!" # 重要
|
||||||
|
obsidian tasks status="-" # 取消
|
||||||
|
```
|
||||||
|
|
||||||
|
### 操作单个任务
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 方式 1:用 ref(path:line)
|
||||||
|
obsidian task ref="10-Projects/alpha/README.md:42" toggle
|
||||||
|
obsidian task ref="10-Projects/alpha/README.md:42" done
|
||||||
|
obsidian task ref="10-Projects/alpha/README.md:42" todo
|
||||||
|
obsidian task ref="10-Projects/alpha/README.md:42" status="/"
|
||||||
|
|
||||||
|
# 方式 2:用 file + line
|
||||||
|
obsidian task file="项目Alpha" line=42 done
|
||||||
|
|
||||||
|
# 方式 3:操作每日笔记
|
||||||
|
obsidian task daily line=7 toggle
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task Emoji Shorthand 约定(社区标准)
|
||||||
|
|
||||||
|
Obsidian Tasks 插件广泛使用的状态字符:
|
||||||
|
|
||||||
|
| 字符 | 含义 | 渲染 |
|
||||||
|
|-----|------|------|
|
||||||
|
| ` ` | 待办 | `- [ ]` |
|
||||||
|
| `x` | 已完成 | `- [x]` |
|
||||||
|
| `/` | 进行中 | `- [/]` |
|
||||||
|
| `?` | 存疑/需澄清 | `- [?]` |
|
||||||
|
| `!` | 重要/关键 | `- [!]` |
|
||||||
|
| `-` | 已取消 | `- [-]` |
|
||||||
|
| `>` | 已转发/委派 | `- [>]` |
|
||||||
|
| `<` | 已调度(计划中) | `- [<]` |
|
||||||
|
|
||||||
|
CLI 的 `status="<char>"` 参数支持这些自定义字符。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## AI Agent 最佳实践
|
||||||
|
|
||||||
|
### 场景 1 · 每日任务收集(GTD 收集阶段)
|
||||||
|
|
||||||
|
每天早晨,扫描所有来源把任务汇总到当天每日笔记:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. 收集昨天未完成的任务
|
||||||
|
obsidian tasks todo format=json > /tmp/open-tasks.json
|
||||||
|
|
||||||
|
# 2. 提取 vault 中所有 "TODO:" "FIXME:" "XXX:" 标记(这些不是正式 task)
|
||||||
|
obsidian search query="TODO:" limit=50 format=json
|
||||||
|
obsidian search query="FIXME:" limit=50 format=json
|
||||||
|
|
||||||
|
# 3. 由 agent 分类后,写入今天的每日笔记(见 obsidian-daily 技能)
|
||||||
|
obsidian daily:append content="\n## 今日任务\n- [ ] 处理 TODO: ...\n- [ ] 继续昨日未完成: ..."
|
||||||
|
```
|
||||||
|
|
||||||
|
### 场景 2 · 周回顾(Weekly Review)
|
||||||
|
|
||||||
|
GTD 的核心仪式,每周一次:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. 本周已完成(展示成就)
|
||||||
|
obsidian tasks done verbose format=json > /tmp/done-this-week.json
|
||||||
|
|
||||||
|
# 2. 未完成且超期 7+ 天的任务(僵尸任务,需要决策)
|
||||||
|
obsidian tasks todo verbose format=json > /tmp/stale-tasks.json
|
||||||
|
|
||||||
|
# 3. 由 agent 生成周报
|
||||||
|
obsidian create path="99-Log/weekly-$(date +%Y-W%V).md" content="# 周回顾\n..."
|
||||||
|
```
|
||||||
|
|
||||||
|
### 场景 3 · 项目进度检查
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 某项目的完成度
|
||||||
|
obsidian tasks path="10-Projects/alpha/README.md" total # 总数
|
||||||
|
obsidian tasks path="10-Projects/alpha/README.md" done total # 已完成数
|
||||||
|
|
||||||
|
# 计算百分比后写回 frontmatter(配合 obsidian-meta)
|
||||||
|
# progress = done / total * 100
|
||||||
|
obsidian property:set name=progress value=65 type=number file="项目Alpha"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 场景 4 · AI 生成任务的注入规范
|
||||||
|
|
||||||
|
当 AI agent 为用户拆解任务时,输出格式应遵循:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## AI 拆解任务 · 2026-04-09
|
||||||
|
|
||||||
|
来源:用户需求"重构认证模块"
|
||||||
|
拆解方式:按 PR 颗粒度,每个任务 < 2h
|
||||||
|
|
||||||
|
- [ ] 📖 阅读现有认证中间件代码
|
||||||
|
- [ ] 🧪 补充现有逻辑的单元测试(无则写)
|
||||||
|
- [ ] ✂️ 抽取 Token 验证为独立函数
|
||||||
|
- [/] 🔧 引入 JWT 库替换自研实现
|
||||||
|
- [ ] 📝 更新 API 文档
|
||||||
|
- [ ] ✅ 回归测试
|
||||||
|
```
|
||||||
|
|
||||||
|
**约定**:
|
||||||
|
- Emoji 前缀标注任务类型(📖 阅读 / 🧪 测试 / ✂️ 重构 / 🔧 开发 / 📝 文档 / ✅ 验证)
|
||||||
|
- 带 `/`(进行中)的任务至多 1 个(WIP 限制)
|
||||||
|
- 每个任务自描述,不依赖上下文才能理解
|
||||||
|
|
||||||
|
### 场景 5 · 跨笔记任务聚合视图
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 把所有 `50-Zettel/` 下的待办聚合到一个 MOC 笔记
|
||||||
|
obsidian tasks path="50-Zettel" todo verbose format=json > /tmp/zettel-tasks.json
|
||||||
|
|
||||||
|
# 写入 MOC
|
||||||
|
obsidian create path="60-MOC/open-research-questions.md" content="# 待解决的研究问题\n..."
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Bash 脚本范式:完整的 Daily Standup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
# 每日站会助手:生成今日状态
|
||||||
|
|
||||||
|
TODAY=$(date +%Y-%m-%d)
|
||||||
|
YESTERDAY=$(date -d "yesterday" +%Y-%m-%d 2>/dev/null || date -v -1d +%Y-%m-%d)
|
||||||
|
|
||||||
|
echo "# Daily Standup · ${TODAY}"
|
||||||
|
echo ""
|
||||||
|
echo "## ✅ 昨日完成"
|
||||||
|
obsidian tasks done verbose format=json | \
|
||||||
|
jq -r '.[] | select(.completed >= "'${YESTERDAY}'") | "- \(.text) [\(.file):\(.line)]"'
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "## 🔄 今日计划"
|
||||||
|
obsidian tasks todo verbose format=json | \
|
||||||
|
jq -r '.[] | "- [ ] \(.text) [\(.file):\(.line)]"' | head -10
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "## 🚧 进行中"
|
||||||
|
obsidian tasks status="/" verbose format=json | \
|
||||||
|
jq -r '.[] | "- [/] \(.text) [\(.file):\(.line)]"'
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 与其他技能的协作
|
||||||
|
|
||||||
|
| 场景 | 链路 |
|
||||||
|
|-----|------|
|
||||||
|
| 每日任务注入 | obsidian-tasks → **obsidian-daily**(`daily:append`) |
|
||||||
|
| 项目进度同步 | obsidian-tasks(统计)→ **obsidian-meta**(`property:set progress`) |
|
||||||
|
| 任务可视化 | obsidian-tasks(写入)→ **obsidian-bases**(视图展示) |
|
||||||
|
| GTD 周回顾工作流 | **obsidian-workflow-pkm**(编排) |
|
||||||
|
| Linear 双向同步 | obsidian-tasks + **linear** |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 常见陷阱
|
||||||
|
|
||||||
|
| 现象 | 原因 | 对策 |
|
||||||
|
|------|------|------|
|
||||||
|
| `task toggle` 不生效 | line 数字错了 | `tasks verbose` 先确认行号 |
|
||||||
|
| 缩进子任务被识别为独立任务 | Markdown 语法正常 | 接受:Obsidian 视子任务为独立 |
|
||||||
|
| 自定义 status 字符不显示 | 主题不支持 | 切换支持 Tasks Emoji 的主题 |
|
||||||
|
| tasks 命令返回空 | 路径/文件名错 | 用 `obsidian files` 先确认 |
|
||||||
|
| 每日任务重复出现 | 没有迁移机制 | 在每日模板里写"迁移昨日未完成"逻辑 |
|
||||||
|
| AI 滥加任务导致 WIP 爆炸 | 没设置上限 | 约定:进行中(`/`)至多 1~3 个 |
|
||||||
@@ -0,0 +1,650 @@
|
|||||||
|
---
|
||||||
|
name: obsidian-workflow-pkm
|
||||||
|
description: Obsidian PKM 端到端编排层——专为"多步骤复合需求"设计,组合调用 obsidian-* 子技能。覆盖 Inbox→Zettelkasten 原子化、MOC 主题地图、PARA 项目归档、Karpathy LLM-Wiki、周报/月报汇总、季度知识库体检、文献批量导入、Web Clip→永久笔记。**优先匹配**:当用户说"整理 inbox/构建 MOC/做季度体检/汇总周报/clip 这篇文章"等多步骤指令时,先进入本技能(编排层)再下发子技能;单一原子操作(搜一篇笔记、改一个属性)请直接用 obsidian-search/meta 等专项子技能。触发词:整理 inbox、原子化笔记、构建 MOC、PARA 归档、LLM wiki、周报、月报、知识库体检、Zettelkasten 流程、web clip、网页剪藏、批量导入文献。
|
||||||
|
---
|
||||||
|
|
||||||
|
# Obsidian Workflow · PKM 编排工作流
|
||||||
|
|
||||||
|
> 参照 `lark-workflow-*` 的命名与定位——这是**编排层**技能,调用各 `obsidian-*` 子技能完成端到端 PKM 流程。不用于单一原子操作,那些请用对应专项技能。
|
||||||
|
|
||||||
|
> **设计哲学**:每个工作流都是"**步骤序列 + 决策点 + 审计记录**"。AI agent 按步骤执行、在决策点等待用户确认(按项目 CLAUDE.md 规则)、所有写入记录到 daily note。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 何时使用
|
||||||
|
|
||||||
|
| 场景 | 工作流 |
|
||||||
|
|------|--------|
|
||||||
|
| 清理 Inbox,把闪念变成永久笔记 | **Workflow 1: Inbox → Atomic → Permanent** |
|
||||||
|
| 从零构建一个主题的 MOC | **Workflow 2: MOC Builder** |
|
||||||
|
| 已完成项目归档到 Archive | **Workflow 3: PARA 归档** |
|
||||||
|
| 用 LLM 构建一个可维护的主题 Wiki | **Workflow 4: Karpathy LLM-Wiki** |
|
||||||
|
| 生成周报/月报 | **Workflow 5: 周报 / 月报汇总** |
|
||||||
|
| 季度知识库健康度体检 | **Workflow 6: 季度体检** |
|
||||||
|
| 从网页/PDF 批量导入并原子化 | **Workflow 7: 文献批量导入** |
|
||||||
|
| 单篇网页剪藏 → 永久笔记 | **Workflow 8: Web Clip → Permanent** |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Workflow 1 · Inbox → Atomic → Permanent(Zettelkasten 核心流程)
|
||||||
|
|
||||||
|
**目标**:把 `00-Inbox/` 中的零散捕获,重写为 `50-Zettel/` 下的原子永久笔记,并自动补双向链接。
|
||||||
|
|
||||||
|
### 步骤
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────┐
|
||||||
|
│ 1. 扫描 Inbox │ obsidian-search 列出 00-Inbox/ 所有文件
|
||||||
|
└────────┬────────┘
|
||||||
|
↓
|
||||||
|
┌─────────────────┐
|
||||||
|
│ 2. 逐篇读取 │ obsidian (read) 读原文
|
||||||
|
└────────┬────────┘
|
||||||
|
↓
|
||||||
|
┌─────────────────┐
|
||||||
|
│ 3. AI 原子化改写 │ 一个概念一篇笔记,标题 = 概念主干
|
||||||
|
└────────┬────────┘
|
||||||
|
↓
|
||||||
|
┌─────────────────┐ ┌ 决策点 ┐
|
||||||
|
│ 4. 用户确认 │ ───→│ 继续? │
|
||||||
|
└────────┬────────┘ └───┬────┘
|
||||||
|
↓ ↓
|
||||||
|
┌─────────────────┐
|
||||||
|
│ 5. 找相关永久笔记 │ obsidian-search (search + backlinks)
|
||||||
|
└────────┬────────┘
|
||||||
|
↓
|
||||||
|
┌─────────────────┐
|
||||||
|
│ 6. 创建新笔记 │ obsidian (create) 到 50-Zettel/
|
||||||
|
│ + 补反链 │ obsidian-meta (property:set refs)
|
||||||
|
└────────┬────────┘
|
||||||
|
↓
|
||||||
|
┌─────────────────┐
|
||||||
|
│ 7. 移除原 inbox │ obsidian (delete) 或 move 到 40-Archive
|
||||||
|
└────────┬────────┘
|
||||||
|
↓
|
||||||
|
┌─────────────────┐
|
||||||
|
│ 8. 审计日志 │ obsidian-daily (daily:append)
|
||||||
|
└─────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### Bash 实现骨架
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
# workflow_inbox_to_permanent.sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# 审计函数
|
||||||
|
log() {
|
||||||
|
obsidian daily:append inline content="
|
||||||
|
- \`$(date +%H:%M)\` **inbox→permanent** $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Step 1: 列 Inbox
|
||||||
|
INBOX_FILES=$(obsidian files folder="00-Inbox" ext=md format=json)
|
||||||
|
COUNT=$(echo "$INBOX_FILES" | jq 'length')
|
||||||
|
log "扫描 Inbox:共 ${COUNT} 个待处理文件"
|
||||||
|
|
||||||
|
# Step 2-6: 逐篇处理(由 agent 驱动)
|
||||||
|
echo "$INBOX_FILES" | jq -r '.[] | .path' | while read -r path; do
|
||||||
|
# Step 2: 读原文
|
||||||
|
ORIG=$(obsidian read path="$path")
|
||||||
|
|
||||||
|
# Step 3: AI 原子化(由 agent 完成,此处伪代码)
|
||||||
|
# - 分析 ORIG 内容,抽取 1~N 个原子概念
|
||||||
|
# - 为每个概念生成 ZID、标题、正文、建议标签
|
||||||
|
|
||||||
|
# Step 4: 展示拆解结果给用户,等待确认
|
||||||
|
echo "原文: $path"
|
||||||
|
echo "拆解为:"
|
||||||
|
echo " 1. 概念A - <标题>"
|
||||||
|
echo " 2. 概念B - <标题>"
|
||||||
|
read -p "继续? (y/N) " confirm
|
||||||
|
[ "$confirm" != "y" ] && continue
|
||||||
|
|
||||||
|
# Step 5: 搜索相关永久笔记
|
||||||
|
for concept in "$CONCEPTS"; do
|
||||||
|
RELATED=$(obsidian search query="$concept" path="50-Zettel" limit=5 format=json)
|
||||||
|
# agent 挑出 top-3 作为 refs
|
||||||
|
done
|
||||||
|
|
||||||
|
# Step 6: 创建永久笔记
|
||||||
|
ZID=$(date +%Y%m%d%H%M%S)
|
||||||
|
TITLE="<AI 生成的概念标题>"
|
||||||
|
CONTENT="---
|
||||||
|
zettel_id: ${ZID}
|
||||||
|
title: ${TITLE}
|
||||||
|
created: $(date +%Y-%m-%d)
|
||||||
|
source: ${path}
|
||||||
|
refs: [[[相关笔记1]], [[相关笔记2]]]
|
||||||
|
tags: [concept, <auto-tag>]
|
||||||
|
---
|
||||||
|
|
||||||
|
# ${TITLE}
|
||||||
|
|
||||||
|
<AI 原子化后的正文>
|
||||||
|
|
||||||
|
## 相关
|
||||||
|
- [[相关笔记1]]
|
||||||
|
- [[相关笔记2]]
|
||||||
|
"
|
||||||
|
obsidian create path="50-Zettel/${ZID} - ${TITLE}.md" content="$CONTENT"
|
||||||
|
|
||||||
|
# Step 7: 清理 Inbox 原文
|
||||||
|
obsidian move path="$path" to="40-Archive/inbox-$(date +%Y-%m)/$(basename "$path")"
|
||||||
|
log "处理完成:$path → 50-Zettel/${ZID}"
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Workflow 2 · MOC Builder(主题地图构建)
|
||||||
|
|
||||||
|
**目标**:给定一个主题关键词,自动从 vault 中召回相关笔记,组织成一个 MOC(Map of Content)入口。
|
||||||
|
|
||||||
|
### 步骤
|
||||||
|
|
||||||
|
```
|
||||||
|
1. 输入主题关键词(如"云原生运行时经济学")
|
||||||
|
2. 多关键词扩展 → 由 agent 生成 3-5 个相关词
|
||||||
|
3. 对每个词跑 obsidian-search(限定到 50-Zettel/)
|
||||||
|
4. 合并去重 → 候选列表
|
||||||
|
5. 按笔记的 created 日期排序 → 时间线
|
||||||
|
6. 按 tags 聚类 → 主题分组
|
||||||
|
7. AI 生成 MOC 结构:
|
||||||
|
## 核心概念
|
||||||
|
## 实践案例
|
||||||
|
## 相关研究
|
||||||
|
## 时间线
|
||||||
|
8. 用户确认结构
|
||||||
|
9. 创建 60-MOC/<主题>.md
|
||||||
|
10. 为每篇被引用的笔记补反链(可选)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 关键命令链
|
||||||
|
|
||||||
|
```bash
|
||||||
|
TOPIC="云原生运行时经济学"
|
||||||
|
KEYWORDS=("云原生" "运行时" "GraalVM" "虚拟线程" "冷启动")
|
||||||
|
|
||||||
|
# Step 3-4: 召回
|
||||||
|
RESULTS=""
|
||||||
|
for kw in "${KEYWORDS[@]}"; do
|
||||||
|
RESULTS+=$(obsidian search query="$kw" path="50-Zettel" limit=20 format=json)
|
||||||
|
done
|
||||||
|
|
||||||
|
# Step 5-6: 由 agent 合并/排序/聚类
|
||||||
|
|
||||||
|
# Step 9: 创建 MOC
|
||||||
|
obsidian create path="60-MOC/${TOPIC}.md" content="# MOC · ${TOPIC}
|
||||||
|
|
||||||
|
> 本主题地图由 AI 于 $(date +%Y-%m-%d) 构建
|
||||||
|
|
||||||
|
## 核心概念
|
||||||
|
- [[笔记1]]
|
||||||
|
- [[笔记2]]
|
||||||
|
|
||||||
|
## 实践案例
|
||||||
|
- [[笔记3]]
|
||||||
|
|
||||||
|
## 相关研究
|
||||||
|
- [[笔记4]]
|
||||||
|
|
||||||
|
## 时间线
|
||||||
|
- 2024-01 [[早期笔记]]
|
||||||
|
- 2025-06 [[中期笔记]]
|
||||||
|
- 2026-04 [[最新笔记]]
|
||||||
|
"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Workflow 3 · PARA 归档
|
||||||
|
|
||||||
|
**目标**:扫描 `10-Projects/`,找出 `status: done` 且超过 14 天无更新的项目,批量移到 `40-Archive/`。
|
||||||
|
|
||||||
|
### 步骤
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
# workflow_para_archive.sh
|
||||||
|
|
||||||
|
# 1. 找 done 状态项目
|
||||||
|
obsidian files folder="10-Projects" format=json | \
|
||||||
|
jq -r '.[] | .path' | while read -r path; do
|
||||||
|
|
||||||
|
# 2. 读 status
|
||||||
|
STATUS=$(obsidian property:read name=status path="$path" 2>/dev/null)
|
||||||
|
UPDATED=$(obsidian property:read name=updated path="$path" 2>/dev/null)
|
||||||
|
|
||||||
|
# 3. 判断是否符合归档条件
|
||||||
|
if [ "$STATUS" = "done" ]; then
|
||||||
|
DAYS_AGO=$(( ($(date +%s) - $(date -d "$UPDATED" +%s)) / 86400 ))
|
||||||
|
if [ "$DAYS_AGO" -gt 14 ]; then
|
||||||
|
# 4. 先检查反链(确保没有活跃项目仍在引用)
|
||||||
|
BACKLINKS=$(obsidian backlinks path="$path" total)
|
||||||
|
if [ "$BACKLINKS" -gt 0 ]; then
|
||||||
|
echo "⚠ 跳过(有 ${BACKLINKS} 个反链):$path"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 5. 用户确认(按项目 CLAUDE.md 规则)
|
||||||
|
read -p "归档 $path ? (y/N) " confirm
|
||||||
|
[ "$confirm" != "y" ] && continue
|
||||||
|
|
||||||
|
# 6. 移到 Archive
|
||||||
|
NEW_PATH="40-Archive/$(basename $(dirname $path))/$(basename $path)"
|
||||||
|
obsidian move path="$path" to="$NEW_PATH"
|
||||||
|
|
||||||
|
# 7. 审计
|
||||||
|
obsidian daily:append inline content="
|
||||||
|
- 📦 归档项目:$path → $NEW_PATH"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Workflow 4 · Karpathy LLM-Wiki(AI 驱动主题 Wiki)
|
||||||
|
|
||||||
|
**目标**:针对一个研究主题,用 LLM 自动收集 → 综合 → 结构化成一份可维护的 Wiki。
|
||||||
|
|
||||||
|
> 参考:Karpathy《LLM Knowledge Bases in Obsidian》
|
||||||
|
|
||||||
|
### 步骤
|
||||||
|
|
||||||
|
```
|
||||||
|
1. 输入主题 + 10~20 个初始源(URL / PDF / 论文)
|
||||||
|
2. 对每个源:
|
||||||
|
- 下载/读取内容
|
||||||
|
- AI 提炼:核心观点 + 关键事实 + 术语表
|
||||||
|
- 写入 20-Literature/<source>.md
|
||||||
|
3. 综合阶段:
|
||||||
|
- AI 读所有 Literature 笔记
|
||||||
|
- 生成 Wiki 大纲(章节结构)
|
||||||
|
- 用户确认大纲
|
||||||
|
4. 写作阶段:
|
||||||
|
- 按大纲逐章生成内容
|
||||||
|
- 每个事实标注来源([[20-Literature/xxx]])
|
||||||
|
- 写入 30-Resources/wiki-<topic>.md
|
||||||
|
5. 迭代:
|
||||||
|
- 用户提新问题 → AI 查 Literature 补答
|
||||||
|
- 用户贡献新源 → Step 2~4 增量更新
|
||||||
|
6. 维护:
|
||||||
|
- 每次更新在 frontmatter 记录 `last_updated`
|
||||||
|
- 每月跑一次"过期源检测"(URL 404 / 事实过时)
|
||||||
|
```
|
||||||
|
|
||||||
|
### SCHEMA.md 片段(告诉 agent 如何维护 Wiki)
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## Wiki 维护约定
|
||||||
|
|
||||||
|
- Wiki 文件位于 `30-Resources/wiki-<topic>.md`
|
||||||
|
- 每个事实必须有 `[[20-Literature/xxx]]` 来源标注
|
||||||
|
- Frontmatter 必须包含:
|
||||||
|
- `topic: <主题>`
|
||||||
|
- `last_updated: <日期>`
|
||||||
|
- `sources_count: <数字>`
|
||||||
|
- `open_questions: <list>`
|
||||||
|
- 更新 Wiki 时,只追加或修订,不删除旧段落(保留版本演化)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Workflow 5 · 周报 / 月报汇总
|
||||||
|
|
||||||
|
**目标**:自动从每日笔记、完成任务、git log、PR 列表中生成周报。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
# workflow_weekly_report.sh
|
||||||
|
|
||||||
|
WEEK=$(date +%Y-W%V)
|
||||||
|
LAST_MONDAY=$(date -d "last monday" +%Y-%m-%d 2>/dev/null || date -v -mon +%Y-%m-%d)
|
||||||
|
|
||||||
|
# 1. 收集本周每日笔记内容
|
||||||
|
DAILY_CONTENT=""
|
||||||
|
for i in {0..6}; do
|
||||||
|
DATE=$(date -d "${LAST_MONDAY} +${i} days" +%Y-%m-%d 2>/dev/null)
|
||||||
|
CONTENT=$(obsidian read path="90-Daily/${DATE}.md" 2>/dev/null)
|
||||||
|
DAILY_CONTENT+="$CONTENT\n\n"
|
||||||
|
done
|
||||||
|
|
||||||
|
# 2. 收集已完成任务
|
||||||
|
DONE=$(obsidian tasks done verbose format=json)
|
||||||
|
|
||||||
|
# 3. 收集搜索关键词(AI 写作/代码/会议/学习)
|
||||||
|
WRITING=$(obsidian search:context query="写作" limit=10 format=json)
|
||||||
|
MEETINGS=$(obsidian search:context query="会议" limit=10 format=json)
|
||||||
|
|
||||||
|
# 4. AI 生成周报
|
||||||
|
REPORT="# 周报 · ${WEEK}
|
||||||
|
|
||||||
|
## ✅ 本周完成
|
||||||
|
<agent 从 DONE 提取>
|
||||||
|
|
||||||
|
## 📝 主要产出
|
||||||
|
<agent 从 DAILY_CONTENT 提取>
|
||||||
|
|
||||||
|
## 🧠 学习与思考
|
||||||
|
<agent 从 DAILY_CONTENT 的晚间回顾提取>
|
||||||
|
|
||||||
|
## 📅 下周计划
|
||||||
|
<agent 从未完成任务推导>
|
||||||
|
"
|
||||||
|
|
||||||
|
# 5. 写入 vault
|
||||||
|
obsidian create path="99-Log/weekly-${WEEK}.md" content="$REPORT" open
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Workflow 6 · 季度知识库体检
|
||||||
|
|
||||||
|
**目标**:三件套 + 元数据一致性检查 + 归档建议。
|
||||||
|
|
||||||
|
### 检查项
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. 图谱健康三件套
|
||||||
|
obsidian orphans format=json > /tmp/q-orphans.json
|
||||||
|
obsidian deadends format=json > /tmp/q-deadends.json
|
||||||
|
obsidian unresolved verbose format=json > /tmp/q-unresolved.json
|
||||||
|
|
||||||
|
# 2. 元数据一致性
|
||||||
|
obsidian files format=json | jq -r '.[] | .path' | while read -r p; do
|
||||||
|
# 检查每篇是否有 created 字段
|
||||||
|
obsidian property:read name=created path="$p" 2>/dev/null || echo "MISSING_CREATED: $p"
|
||||||
|
# 检查每篇是否有 tags
|
||||||
|
obsidian property:read name=tags path="$p" 2>/dev/null || echo "MISSING_TAGS: $p"
|
||||||
|
done > /tmp/q-metadata.txt
|
||||||
|
|
||||||
|
# 3. Tag 体系审计
|
||||||
|
obsidian tags counts sort=count format=json > /tmp/q-tags.json
|
||||||
|
# 由 agent 找出:低频 tag、命名不一致、未层级化
|
||||||
|
|
||||||
|
# 4. 归档建议
|
||||||
|
obsidian files folder="10-Projects" format=json | \
|
||||||
|
jq -r '.[] | .path' > /tmp/q-projects.txt
|
||||||
|
# 由 agent 读每个项目的 status + updated,提 done + stale 归档建议
|
||||||
|
|
||||||
|
# 5. 生成体检报告
|
||||||
|
obsidian create path="99-Log/health-$(date +%Y-Q$((($(date +%m)-1)/3+1))).md" content="$REPORT"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 输出报告模板
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# 知识库季度体检 · 2026-Q2
|
||||||
|
|
||||||
|
## 🧪 体检结论
|
||||||
|
- 总笔记数:X
|
||||||
|
- 孤立笔记:X(占 Y%)
|
||||||
|
- 断头笔记:X
|
||||||
|
- 未解析链接:X
|
||||||
|
- 元数据缺失:X
|
||||||
|
|
||||||
|
## 🔴 高危问题
|
||||||
|
- ...
|
||||||
|
|
||||||
|
## 🟡 优化建议
|
||||||
|
- ...
|
||||||
|
|
||||||
|
## 🟢 健康指标
|
||||||
|
- ...
|
||||||
|
|
||||||
|
## 行动项(自动生成 task)
|
||||||
|
- [ ] 清理 N 篇孤立笔记
|
||||||
|
- [ ] 修复 N 个未解析链接
|
||||||
|
- [ ] 合并 N 个低频 tag
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Workflow 7 · 文献批量导入
|
||||||
|
|
||||||
|
**目标**:从网页/PDF 批量导入到 `20-Literature/`,每篇自动生成:摘要、关键词、与现有知识库的关联。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 依赖:Web Clipper 或 obsidian-advanced-uri 插件
|
||||||
|
# 简化流程:
|
||||||
|
|
||||||
|
URLS=("https://..." "https://..." "https://...")
|
||||||
|
|
||||||
|
for url in "${URLS[@]}"; do
|
||||||
|
# 1. 下载原文(用 Bash curl 或 Clipper)
|
||||||
|
CONTENT=$(curl -s "$url" | <html-to-markdown>)
|
||||||
|
|
||||||
|
# 2. AI 提炼
|
||||||
|
SUMMARY="<AI 生成的 300 字摘要>"
|
||||||
|
KEYWORDS="<AI 生成的关键词列表>"
|
||||||
|
|
||||||
|
# 3. 找已有相关笔记
|
||||||
|
RELATED=""
|
||||||
|
for kw in $KEYWORDS; do
|
||||||
|
RELATED+=$(obsidian search query="$kw" limit=5 format=json)
|
||||||
|
done
|
||||||
|
|
||||||
|
# 4. 创建 Literature 笔记
|
||||||
|
TS=$(date +%Y%m%d%H%M%S)
|
||||||
|
obsidian create path="20-Literature/${TS}-$(slugify).md" content="---
|
||||||
|
type: literature
|
||||||
|
title: <原文标题>
|
||||||
|
source: ${url}
|
||||||
|
created: $(date +%Y-%m-%d)
|
||||||
|
tags: [literature, ${KEYWORDS}]
|
||||||
|
related: [$(agent 填充)]
|
||||||
|
---
|
||||||
|
|
||||||
|
## 摘要
|
||||||
|
${SUMMARY}
|
||||||
|
|
||||||
|
## 关键词
|
||||||
|
${KEYWORDS}
|
||||||
|
|
||||||
|
## 原文要点
|
||||||
|
<AI 提炼的 bullet points>
|
||||||
|
|
||||||
|
## 与现有知识库的关联
|
||||||
|
- [[相关笔记 1]]
|
||||||
|
- [[相关笔记 2]]
|
||||||
|
|
||||||
|
## 原文链接
|
||||||
|
${url}
|
||||||
|
"
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Workflow 8 · Web Clip → Permanent(单篇网页剪藏)
|
||||||
|
|
||||||
|
**目标**:用户给一个 URL(或一段文字),AI 抓取→清洗→提炼→落 `30-Resources/` 或 `50-Zettel/`,比 Workflow 7(批量文献)更轻量、即时。
|
||||||
|
|
||||||
|
### 与 Workflow 7 的区别
|
||||||
|
|
||||||
|
| 维度 | Workflow 7 | Workflow 8 |
|
||||||
|
|------|-----------|-----------|
|
||||||
|
| 触发 | 一批 URL/PDF | 单条 URL/选文 |
|
||||||
|
| 目录 | `20-Literature/` | `30-Resources/` 或 `50-Zettel/` |
|
||||||
|
| 时机 | 批处理 | 即时单次 |
|
||||||
|
| 决策点 | 一次全批确认 | 每次都确认 |
|
||||||
|
|
||||||
|
### 步骤
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────────┐
|
||||||
|
│ 1. 抓取网页正文 │ defuddle(社区标准)/ WebFetch / curl + readability
|
||||||
|
└────────┬─────────┘
|
||||||
|
↓
|
||||||
|
┌──────────────────┐
|
||||||
|
│ 2. 清洗为 Markdown│ 去广告/导航/评论;保留正文 + 图链 + 代码块
|
||||||
|
└────────┬─────────┘
|
||||||
|
↓
|
||||||
|
┌──────────────────┐ ┌ 决策点 ┐
|
||||||
|
│ 3. 用户预览原文 │ ───→│ 落库? │
|
||||||
|
└────────┬─────────┘ └───┬────┘
|
||||||
|
↓ ↓
|
||||||
|
┌──────────────────┐
|
||||||
|
│ 4. AI 提炼摘要+关键词│
|
||||||
|
└────────┬─────────┘
|
||||||
|
↓
|
||||||
|
┌──────────────────┐
|
||||||
|
│ 5. obsidian-search│ 找已有相关笔记
|
||||||
|
│ 关联召回 │
|
||||||
|
└────────┬─────────┘
|
||||||
|
↓
|
||||||
|
┌──────────────────┐
|
||||||
|
│ 6. 创建笔记 │ frontmatter: source=url, type=clip
|
||||||
|
│ + 双向链接 │
|
||||||
|
└────────┬─────────┘
|
||||||
|
↓
|
||||||
|
┌──────────────────┐
|
||||||
|
│ 7. daily:append │ 审计:URL + 落位路径
|
||||||
|
└──────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### Bash 实现骨架
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
# workflow_web_clip.sh
|
||||||
|
|
||||||
|
URL="$1"
|
||||||
|
TARGET_DIR="${2:-30-Resources}" # 默认 30-Resources,可指定 50-Zettel
|
||||||
|
|
||||||
|
# 1. 抓取 + 清洗(按可用性优先级回退)
|
||||||
|
if command -v defuddle &>/dev/null; then
|
||||||
|
# 社区首选:defuddle 专门为 LLM 设计,去 chrome
|
||||||
|
CLEAN=$(defuddle "$URL" --markdown)
|
||||||
|
elif command -v readability-cli &>/dev/null; then
|
||||||
|
CLEAN=$(readability-cli "$URL" --output md)
|
||||||
|
else
|
||||||
|
# 兜底:让 AI agent 走 WebFetch + 手工清洗
|
||||||
|
CLEAN=$(echo "USE WebFetch tool with prompt: extract main content as clean markdown")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 2. AI 提炼
|
||||||
|
TITLE=$(echo "$CLEAN" | head -1 | sed 's/^#\s*//')
|
||||||
|
SUMMARY="<AI 300 字摘要>"
|
||||||
|
KEYWORDS="<AI 提炼关键词,逗号分隔>"
|
||||||
|
|
||||||
|
# 3. 关联召回
|
||||||
|
RELATED=$(obsidian search query="$KEYWORDS" limit=5 format=json | jq -r '.[].path')
|
||||||
|
|
||||||
|
# 4. 落库
|
||||||
|
SLUG=$(echo "$TITLE" | tr ' ' '-' | tr -dc 'a-zA-Z0-9-_一-龥')
|
||||||
|
DATE=$(date +%Y-%m-%d)
|
||||||
|
PATH_NEW="${TARGET_DIR}/${DATE}-${SLUG}.md"
|
||||||
|
|
||||||
|
obsidian create path="$PATH_NEW" content="---
|
||||||
|
type: clip
|
||||||
|
title: ${TITLE}
|
||||||
|
source: ${URL}
|
||||||
|
created: ${DATE}
|
||||||
|
tags: [clip]
|
||||||
|
related: [${RELATED}]
|
||||||
|
---
|
||||||
|
|
||||||
|
## TL;DR
|
||||||
|
${SUMMARY}
|
||||||
|
|
||||||
|
## 关键词
|
||||||
|
${KEYWORDS}
|
||||||
|
|
||||||
|
## 正文(清洗后)
|
||||||
|
${CLEAN}
|
||||||
|
|
||||||
|
## 与现有知识库
|
||||||
|
- 见 frontmatter related 字段
|
||||||
|
"
|
||||||
|
|
||||||
|
# 5. 审计
|
||||||
|
obsidian daily:append content="\n- [web-clip] ${URL} → [[${PATH_NEW}]]"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 注意
|
||||||
|
|
||||||
|
- `defuddle` 是 Obsidian 团队官方维护的 web→markdown 清洗工具([github.com/kepano/defuddle](https://github.com/kepano/defuddle)),比 readability-cli 更专为 LLM 优化(去 token 浪费)
|
||||||
|
- 没装 defuddle 时,AI agent 应主动用 **WebFetch 工具** 抓取并 prompt 模型"清洗为正文 markdown"
|
||||||
|
- **去重检查**:落库前先 `obsidian search query="source: ${URL}"`,避免同一篇 clip 两次
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 通用工作流约定
|
||||||
|
|
||||||
|
### 1. 决策点 × 步骤 × 审计
|
||||||
|
|
||||||
|
每个工作流都是 `执行 → 决策点 → 审计`:
|
||||||
|
|
||||||
|
- **执行**:由 agent 自动调用各 obsidian-* 技能
|
||||||
|
- **决策点**:在"写入前"、"删除前"、"移动前"三类操作必须等待用户确认(项目 CLAUDE.md 规则 4)
|
||||||
|
- **审计**:每个写入操作在 `obsidian-daily`(日志)+ `99-Log/ai-actions-<date>.md`(结构化记录)
|
||||||
|
|
||||||
|
### 2. 安全栏杆
|
||||||
|
|
||||||
|
- 批量操作前 **git checkpoint**(或 `obsidian-history` 手动快照)
|
||||||
|
- 批量操作前 **`obsidian sync off`**(避免同步抖动)
|
||||||
|
- Agent 一次只能动 1 个工作流;不能并发两个写入 workflow
|
||||||
|
|
||||||
|
### 3. 命名约定
|
||||||
|
|
||||||
|
- 工作流脚本:`workflow_<name>.sh`,放在 vault 根的 `99-Log/scripts/` 或用户 `~/.claude/scripts/`
|
||||||
|
- 工作流日志:`99-Log/workflow-<name>-YYYYMMDD.md`
|
||||||
|
- 工作流模板:`70-Templates/workflow-<name>.md`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 与其他 obsidian-* 技能的调用关系
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
WF[obsidian-workflow-pkm]
|
||||||
|
CORE[obsidian 核心]
|
||||||
|
SEARCH[obsidian-search]
|
||||||
|
META[obsidian-meta]
|
||||||
|
TASKS[obsidian-tasks]
|
||||||
|
DAILY[obsidian-daily]
|
||||||
|
BASES[obsidian-bases]
|
||||||
|
HIST[obsidian-history]
|
||||||
|
|
||||||
|
WF --> CORE
|
||||||
|
WF --> SEARCH
|
||||||
|
WF --> META
|
||||||
|
WF --> TASKS
|
||||||
|
WF --> DAILY
|
||||||
|
WF --> BASES
|
||||||
|
WF --> HIST
|
||||||
|
|
||||||
|
DAILY -.审计日志.-> WF
|
||||||
|
HIST -.检查点.-> WF
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 常见陷阱
|
||||||
|
|
||||||
|
| 现象 | 原因 | 对策 |
|
||||||
|
|------|------|------|
|
||||||
|
| 工作流中途失败导致状态不一致 | 没有事务 | 先 git checkpoint;失败后从 checkpoint 恢复 |
|
||||||
|
| Agent 在决策点没等用户 | 没实现交互 | 脚本用 `read -p`,Claude Code 用 AskUserQuestion |
|
||||||
|
| 批量处理把同一笔记处理两次 | 没用 idempotent 标记 | 处理完在 frontmatter 加 `processed_by: inbox_workflow` |
|
||||||
|
| MOC 构建召回漏掉笔记 | 关键词单一 | 用 3~5 个扩展词 + 标签 + 出/反链三路召回 |
|
||||||
|
| 周报漏数据 | daily note 没写 | 先跑 `obsidian files folder=90-Daily` 检查覆盖 |
|
||||||
|
| 归档误移有反链的项目 | 没检查 backlinks | 归档前必须 `backlinks total == 0` 断言 |
|
||||||
|
| Literature 导入重复 | 未去重 | 用 URL hash 做 ID,frontmatter `source_hash` |
|
||||||
|
| LLM-Wiki 越改越乱 | 没版本化 | 每次大改前 git commit + `last_updated` 更新 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 参考
|
||||||
|
|
||||||
|
- **Andrej Karpathy** · LLM-Powered Knowledge Bases in Obsidian
|
||||||
|
- **Addo Zhang** · Obsidian Skills for AI Agents(Medium 2026.2)
|
||||||
|
- **Tiago Forte** · PARA Method
|
||||||
|
- **Niklas Luhmann** · Zettelkasten
|
||||||
|
- **Nick Milo** · Linking Your Thinking (LYT) + Maps of Content
|
||||||
|
- **dsebastien** · 16 Practical AI Use Cases with Obsidian
|
||||||
@@ -0,0 +1,273 @@
|
|||||||
|
---
|
||||||
|
name: obsidian
|
||||||
|
description: 当前目录(或任一上级目录)存在 `.obsidian/` 文件夹,或项目 CLAUDE.md 含 obsidian/vault/知识库关键词时,主动激活整个 obsidian-* 技能族。本技能为核心入口:vault 发现、笔记 CRUD(read/create/append/move/delete)、建立 AI 协作约定文件(SCHEMA.md)。触发词:obsidian、vault、知识库、wikilink、笔记库。专项操作请路由到对应 obsidian-* 子技能。
|
||||||
|
---
|
||||||
|
|
||||||
|
# Obsidian · 核心技能
|
||||||
|
|
||||||
|
> vault 发现、笔记 CRUD、AI 协作约定层的入口。专项能力请跳转到对应 `obsidian-*` 子技能。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 0. Vault 自动检测 SOP
|
||||||
|
|
||||||
|
**以下信号出现时主动激活,无需用户明确请求**:
|
||||||
|
|
||||||
|
| 检测项 | 置信度 |
|
||||||
|
|-------|-------|
|
||||||
|
| 当前目录或上级目录存在 `.obsidian/` 文件夹 | ⭐⭐⭐⭐⭐ |
|
||||||
|
| 项目 CLAUDE.md 含 `obsidian`/`vault`/`知识库` 关键词 | ⭐⭐⭐⭐ |
|
||||||
|
| 目录存在 `*.canvas` 或 `*.base` 文件 | ⭐⭐⭐⭐ |
|
||||||
|
| 根目录有 `SCHEMA.md`/`AGENTS.md` 且存在大量 `.md` 文件 | ⭐⭐⭐⭐⭐ |
|
||||||
|
| 用户话语含 `[[wikilink]]`/`PARA`/`Zettelkasten`/`MOC` | ⭐⭐⭐ |
|
||||||
|
|
||||||
|
**检测到 vault 后的标准动作**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. 确认 vault 身份
|
||||||
|
obsidian vaults
|
||||||
|
obsidian vault info=path
|
||||||
|
|
||||||
|
# 2. 查找约定文件(关键上下文)
|
||||||
|
obsidian read file="SCHEMA" 2>/dev/null || \
|
||||||
|
obsidian read file="AGENTS" 2>/dev/null || \
|
||||||
|
obsidian read file="CLAUDE" 2>/dev/null || \
|
||||||
|
obsidian read file="README" 2>/dev/null
|
||||||
|
|
||||||
|
# 3. 没有约定文件 → 主动建议用户创建(见本文档第 5 章 SCHEMA.md 模板)
|
||||||
|
|
||||||
|
# 4. 按用户意图路由到对应子技能(见第 2 节速查表)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 心智模型
|
||||||
|
|
||||||
|
- **Vault = 磁盘上一个普通文件夹**,里面是 `.md` 纯文本笔记
|
||||||
|
- **不需要数据库、不需要云服务**,可以直接用任何编辑器读写
|
||||||
|
- **官方 `obsidian` CLI** 通过本地协议与桌面应用通信,能做一切 Obsidian 内置操作
|
||||||
|
- **AI Agent 友好性**:文件纯文本可自由读写;vault 语义由 SCHEMA.md / AGENTS.md 承载,agent 读一次即可理解整个知识库
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 子技能速查
|
||||||
|
|
||||||
|
| 场景 | 子技能 | 代表命令 |
|
||||||
|
|-----|-------|---------|
|
||||||
|
| 全文搜索、反链/出链、图谱健康度(orphans/deadends/unresolved) | **obsidian-search** | `search / backlinks / orphans` |
|
||||||
|
| tags、frontmatter properties、aliases、bookmarks | **obsidian-meta** | `tags / property:set / aliases` |
|
||||||
|
| Markdown 任务清单(`- [ ]`)、GTD | **obsidian-tasks** | `tasks / task toggle` |
|
||||||
|
| 每日笔记读写、晨间模板、晚间回顾 | **obsidian-daily** | `daily / daily:append / daily:read` |
|
||||||
|
| Obsidian Bases 数据库视图(1.9+) | **obsidian-bases** | `bases / base:query / base:create` |
|
||||||
|
| 版本历史、误删恢复、Obsidian Sync | **obsidian-history** | `history / sync / diff` |
|
||||||
|
| 插件、主题、快捷键、Templates | **obsidian-plugins** | `plugin:enable / theme:set / commands` |
|
||||||
|
| 端到端 PKM 工作流(Inbox→Zettel/MOC/PARA/周报/体检) | **obsidian-workflow-pkm** | 组合调用上述技能 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 命令语法与基础约定
|
||||||
|
|
||||||
|
```
|
||||||
|
obsidian <command> [key=value ...]
|
||||||
|
obsidian vault=<name> <command> [key=value ...] # 指定 vault
|
||||||
|
```
|
||||||
|
|
||||||
|
**三条铁律**:
|
||||||
|
|
||||||
|
1. **`file=<name>` 按 wikilink 名称解析**(无需扩展名,全局查找);**`path=<path>` 是精确路径**(如 `folder/note.md`)
|
||||||
|
2. 含空格的值必须引号:`name="My Note"`,内容换行用 `\n`,Tab 用 `\t`
|
||||||
|
3. **AI agent 输出格式一律用 `format=json`**,便于 `jq` 解析
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Vault 基础命令速查
|
||||||
|
|
||||||
|
### Vault 管理
|
||||||
|
|
||||||
|
```bash
|
||||||
|
obsidian vaults # 列出所有已知 vault
|
||||||
|
obsidian vault # 当前 vault 信息
|
||||||
|
obsidian vault info=path # 只返回 vault 路径
|
||||||
|
obsidian vault=<name> <command> # 切换到指定 vault 执行命令
|
||||||
|
obsidian reload # 重载 vault
|
||||||
|
obsidian version # Obsidian 版本
|
||||||
|
```
|
||||||
|
|
||||||
|
### 文件列表与导航
|
||||||
|
|
||||||
|
```bash
|
||||||
|
obsidian files # 列出 vault 所有文件
|
||||||
|
obsidian files folder=<path> # 按文件夹筛选
|
||||||
|
obsidian files ext=md # 按扩展名筛选
|
||||||
|
obsidian files total # 只返回文件数
|
||||||
|
|
||||||
|
obsidian folders # 列出所有文件夹
|
||||||
|
obsidian folder path=<path> info=files # 某文件夹详情
|
||||||
|
|
||||||
|
obsidian recents # 最近打开的文件
|
||||||
|
obsidian tabs # 当前打开的标签页
|
||||||
|
obsidian random:read # 随机读一篇(灵感触发)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 文件读与查看
|
||||||
|
|
||||||
|
```bash
|
||||||
|
obsidian read file=<name> # 按名读取
|
||||||
|
obsidian read path=<path> # 按路径读取
|
||||||
|
obsidian file file=<name> # 文件元信息(路径、大小、时间戳)
|
||||||
|
obsidian outline file=<name> format=md # 标题层级结构
|
||||||
|
obsidian wordcount file=<name> # 字数统计
|
||||||
|
```
|
||||||
|
|
||||||
|
### 文件写入与变更
|
||||||
|
|
||||||
|
```bash
|
||||||
|
obsidian create name="新笔记" content="# 标题\n\n正文" open
|
||||||
|
obsidian create path="Projects/Alpha/README.md" template="project"
|
||||||
|
|
||||||
|
obsidian append path=<path> content="\n- 追加的一行"
|
||||||
|
obsidian prepend path=<path> content="## 新的顶部章节\n\n"
|
||||||
|
|
||||||
|
obsidian move path="old/note.md" to="new/folder/note.md" # 自动更新 wikilinks
|
||||||
|
obsidian rename file=<name> name="新名称"
|
||||||
|
obsidian delete file=<name> # 移到回收站
|
||||||
|
obsidian delete file=<name> permanent # 永久删除(危险)
|
||||||
|
|
||||||
|
obsidian open file=<name> newtab # 在 Obsidian 中打开
|
||||||
|
```
|
||||||
|
|
||||||
|
> ⚠ **只读优先**:AI agent 写入操作默认走 `append`/`create`;`move`/`delete` 前先 `backlinks` 检查依赖。
|
||||||
|
|
||||||
|
### Obsidian Flavored Markdown 语法速查
|
||||||
|
|
||||||
|
> AI 写入笔记内容时**必须遵守 OFM 语法**——它是普通 Markdown 的超集,下列特性 Obsidian 解析、其他渲染器忽略。
|
||||||
|
|
||||||
|
| 语法 | 写法 | 用途 | 注意 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| **Wikilink** | `[[Note Title]]` | 内部笔记跳转 | 优先于 `[text](path.md)`;`obsidian move` 会自动重写它 |
|
||||||
|
| Wikilink 别名 | `[[Note Title\|显示文本]]` | 改显示但保持跳转目标 | `\|` 前后无空格 |
|
||||||
|
| **Embed(嵌入)** | `![[Note Title]]` | 嵌入整篇笔记内容 | 比 wikilink 多一个 `!` |
|
||||||
|
| Embed 段落 | `![[Note Title#二级标题]]` | 只嵌入特定章节 | 标题区分大小写 |
|
||||||
|
| Embed 块 | `![[Note Title#^blockid]]` | 嵌入单个块 | 配合下方块引用 |
|
||||||
|
| **块引用 ID** | 段落末尾追加 ` ^blockid` | 给段落起锚点 | `^` 前要有空格,ID 不可含空格 |
|
||||||
|
| **Callout** | `> [!note] 标题`<br>`> 正文` | 信息卡片 | 类型:note/info/tip/warning/danger/success/quote/abstract/example/question/fail/bug/todo |
|
||||||
|
| Callout 可折叠 | `> [!note]+` 默认展开 / `> [!note]-` 默认折叠 | 长内容收纳 | `+`/`-` 紧跟类型后 |
|
||||||
|
| **Tag** | `#tag` 或 `#parent/child` | 分类索引 | 不可有空格;嵌套用 `/` |
|
||||||
|
| **Frontmatter** | 文件首行三横杠 YAML 块 | 笔记元数据 | 详细规范见 `obsidian-meta` 技能 |
|
||||||
|
| **Highlight** | `==高亮文本==` | 视觉强调 | OFM 扩展 |
|
||||||
|
| 数学公式 | 行内 `$E=mc^2$` / 块 `$$...$$` | LaTeX | MathJax 解析 |
|
||||||
|
| 任务 | `- [ ]` / `- [x]` | 复选框 | 详细操作见 `obsidian-tasks` |
|
||||||
|
| Mermaid | ` ```mermaid ` 代码块 | 图表 | 渲染器内置 |
|
||||||
|
|
||||||
|
**写入时高频陷阱**:
|
||||||
|
|
||||||
|
1. **CLI `content=` 参数里 `\n` 是换行**,写 callout 时每行都要加 `> ` 前缀:
|
||||||
|
```bash
|
||||||
|
obsidian append path="note.md" content="\n> [!warning] 注意\n> 这是第二行\n"
|
||||||
|
```
|
||||||
|
2. **Wikilink 不要扩展名**:写 `[[Daily/2026-04-09]]` 而非 `[[Daily/2026-04-09.md]]`
|
||||||
|
3. **Embed 加 frontmatter 时**:被嵌入的笔记如果有 frontmatter,会**整块跟着嵌**——用块引用 `![[Note#^id]]` 精确控制
|
||||||
|
4. **Callout 嵌套**:内层多一个 `>`,即 `>>` 开头
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. AI Agent 协作原则
|
||||||
|
|
||||||
|
### 约定先行
|
||||||
|
|
||||||
|
Agent 进入 vault 第一件事:读 **SCHEMA.md**(或 AGENTS.md / CLAUDE.md)。它定义:
|
||||||
|
- 文件夹语义(`10-Projects/` 是什么)
|
||||||
|
- 命名规则
|
||||||
|
- Frontmatter 规范
|
||||||
|
- 标签体系
|
||||||
|
- Agent 行为准则
|
||||||
|
|
||||||
|
**没有 SCHEMA.md 的 vault → 主动建议用户创建**(见下方模板)。
|
||||||
|
|
||||||
|
### 安全与可追溯
|
||||||
|
|
||||||
|
- **只读优先**:查询命令(search/backlinks/tags/properties)永远安全,优先使用
|
||||||
|
- **写入前备份**:批量 move/rename 前先 `git commit` 或 `obsidian sync off` + history checkpoint
|
||||||
|
- **可审计**:每次 AI 写入在 `daily:append` 留一条记录,或写到 `99-Log/agent-actions-<date>.md`
|
||||||
|
- **避免魔改 frontmatter**:只新增字段,不删已有字段(除非用户明确要求)
|
||||||
|
|
||||||
|
### 命名与链接建议
|
||||||
|
|
||||||
|
- 笔记名:`<YYYYMMDDHHmm> <标题>` 或 `<主题> - <副标题>`,避免特殊字符 `:/\|?*`
|
||||||
|
- 文件夹:编号前缀便于排序(`00-Inbox/`、`10-Projects/`、`50-Zettel/`)
|
||||||
|
- **wikilinks 优先**于 markdown links:`[[Note Title]]` 可被 `obsidian move` 自动更新
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. SCHEMA.md 模板
|
||||||
|
|
||||||
|
创建到 vault 根目录(AI agent 每次进入 vault 必读):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
obsidian create path="SCHEMA.md" content="$(cat <<'EOF'
|
||||||
|
# Vault Schema
|
||||||
|
|
||||||
|
> AI agent 协作约定。修改本文件后请同步到项目 CLAUDE.md。
|
||||||
|
|
||||||
|
## 组织范式
|
||||||
|
- 框架:PARA + Zettelkasten 混合
|
||||||
|
- 主语言:简体中文
|
||||||
|
|
||||||
|
## 文件夹语义
|
||||||
|
| 路径 | 含义 | 准入规则 |
|
||||||
|
|------|------|---------|
|
||||||
|
| 00-Inbox/ | 未整理捕获 | 任何原始笔记 |
|
||||||
|
| 10-Projects/ | 有截止日期的项目 | 含 project_name/ 子目录 |
|
||||||
|
| 20-Areas/ | 长期责任领域 | 常绿笔记 |
|
||||||
|
| 30-Resources/ | 参考资料 | 主题知识 |
|
||||||
|
| 40-Archive/ | 已完成/过期 | 从其他目录移入 |
|
||||||
|
| 50-Zettel/ | 原子永久笔记 | 单一概念,双向链接 |
|
||||||
|
| 90-Daily/ | 每日笔记 | 自动生成 |
|
||||||
|
| 99-Log/ | Agent 操作日志 | 机器写入,永久保留 |
|
||||||
|
|
||||||
|
## Frontmatter 规范
|
||||||
|
\`\`\`yaml
|
||||||
|
---
|
||||||
|
title: 笔记标题
|
||||||
|
created: 2026-04-09
|
||||||
|
updated: 2026-04-09
|
||||||
|
status: draft | active | done | archived
|
||||||
|
tags: [tag1, tag2]
|
||||||
|
source: url | book | meeting
|
||||||
|
aliases: []
|
||||||
|
---
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
## AI Agent 行为准则
|
||||||
|
1. 进入 vault 必须先读本文件
|
||||||
|
2. 写入前必须创建/维护 frontmatter
|
||||||
|
3. 删除/重命名前先 backlinks 检查
|
||||||
|
4. 每次写操作在 99-Log/agent-actions-<date>.md 追加记录
|
||||||
|
5. 永远不修改 .obsidian/ 目录下的任何文件
|
||||||
|
EOF
|
||||||
|
)" open
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Windows 环境注意事项
|
||||||
|
|
||||||
|
| 项目 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| Obsidian 配置文件 | `%APPDATA%\obsidian\obsidian.json` |
|
||||||
|
| 桌面应用依赖 | 必须保持 Obsidian 桌面版运行,CLI 通过本地协议通信 |
|
||||||
|
| 路径分隔符 | CLI 内部使用正斜杠 `/`,即便在 Windows 上 |
|
||||||
|
| 中文文件名 | Git Bash 默认 UTF-8,双引号包裹即可 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. 常见陷阱
|
||||||
|
|
||||||
|
| 现象 | 原因 | 对策 |
|
||||||
|
|------|------|------|
|
||||||
|
| `file=<name>` 找到了错的笔记 | 名称不唯一 | 改用 `path=<full/path.md>` |
|
||||||
|
| `create` 报错 "vault not found" | 未指定 vault | 加 `vault=<name>` 或先 `obsidian vaults` |
|
||||||
|
| `append` 没有换行 | 未加 `\n` 前缀 | `content="\n- 新行"` |
|
||||||
|
| 批量操作后 wikilinks 失效 | 使用了系统 `mv` 而非 `obsidian move` | 永远用 `obsidian move`,它自动更新链接 |
|
||||||
|
| CLI 命令不响应 | Obsidian 桌面应用未运行 | 先启动 Obsidian |
|
||||||
|
| Agent 反复修改同一字段 | 没读 SCHEMA.md | 进入 vault 第一步必须读约定文件 |
|
||||||
Reference in New Issue
Block a user