Phase 3 节段合并:远端 decisions.md 中"obsidian skill 集对标社区基准的审查 + 优化(2026-06-12)" Section 自动合并到本地(远端独有 → 追加到末尾,无 remote-diverge)。 Phase 5 memory-update: - decisions.md frontmatter commit38beecb→fad7335- project_overview.md 更新 obsidian 行:9 技能 → 10 技能,标注社区对标基准 Phase 6 memory-lint: - 文件级引用 AUTO-FIX:decisions.md 1→3(达到 SYNTHESIS_THRESHOLD=3,列为核心枢纽节点) - MEMORY.md 引用列同步:decisions=3 / project_overview=1 / feedback_plugin_dev=1 / lint_report=0 - NEED-HUMAN: 0 - section 级跨文件引用仍 < 3,无 synthesis 升级候选 Phase 7-9:CLAUDE.md 元数据更新(commit hash + 决策项 11→12 + obsidian 10 技能)。
165 lines
13 KiB
Markdown
165 lines
13 KiB
Markdown
---
|
||
name: 架构决策
|
||
description: Marketplace 设计中的关键技术决策及其原因
|
||
type: project
|
||
last_updated: 2026-06-12
|
||
commit: fad7335
|
||
---
|
||
|
||
# 关键架构决策
|
||
|
||
## 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#签名变更全量扫描]]、kepano/obsidian-skills、AgriciDaniel/claude-obsidian
|