Compare commits

...
15 Commits
Author SHA1 Message Date
SkyJourneyandClaude Sonnet 5 437ab425be chore: 记忆文件 commit 锚点回填至 9e1dcf6
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015D4xWG3gRWkUKJDgyvtyJw
2026-08-25 17:03:02 +08:00
SkyJourneyandClaude Sonnet 5 9e1dcf6634 docs(hermes): 记录实测结果——安全扫描误判修复确认 + MCP session-id 已知 bug
- README:http raw 链接安装、用户/profile 级安装范围说明;两条新警告
  (description 触发安全扫描的原因、Hermes MCP session-id 已知 bug 阻塞
  huanxi/huanxi-admin/zentao 的 HTTP MCP 连接,链接 hermes-agent#20349)
- CLAUDE.md:开发指南补充同样两点
- decisions.md:新增两条决策记录,标注此前"待实测"的两点均已确认通过

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015D4xWG3gRWkUKJDgyvtyJw
2026-08-25 17:02:56 +08:00
SkyJourneyandClaude Sonnet 5 106c394a46 chore(hermes): packs/*.yaml ref 同步 bump 到 aaf43e1(description 精简后的 commit)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015D4xWG3gRWkUKJDgyvtyJw
2026-08-25 16:29:42 +08:00
SkyJourneyandClaude Sonnet 5 aaf43e1990 fix(hermes): 精简 plugin.json description,规避安全扫描误判
huanxi/huanxi-admin/zentao 的 description 里字面写了 ~/.hermes/config.yaml
路径,被 Hermes 的 community-source 安全扫描误判为 persistence 类危险模式
(community source 任意 1 个 finding 即 BLOCKED,--force 也无法覆盖)。
plugin.json 的 description 本就该是一句话简介,操作指令保留在 README 即可,
不应该在 description 里重复写配置路径。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015D4xWG3gRWkUKJDgyvtyJw
2026-08-25 16:29:17 +08:00
SkyJourneyandClaude Sonnet 5 df375117ae feat(hermes): 新增 packs/ 逐插件 pack manifest,同步记忆体系收尾
packs/*.yaml 的 ref 均锁定到上一个 commit(56ae43f),指向本次新增的
huanxi/huanxi-admin/memcore-hermes/obsidian/zentao 五个插件目录;
另加 all.yaml 支持一次性全装。同步刷新记忆文件的 commit 锚点。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015D4xWG3gRWkUKJDgyvtyJw
2026-08-25 15:40:56 +08:00
SkyJourneyandClaude Sonnet 5 56ae43f6d3 feat(hermes): 新增 Hermes Agent 插件市场支持,含独立 memcore-hermes
- huanxi/huanxi-admin/obsidian/zentao 新增裸 plugin.json(Agent Plugins v1.0.0 标准),复用同一份 skills/
- 凭证类插件不打包 mcp.json(规范禁止内嵌密钥),改为 README 里的 ~/.hermes/config.yaml 手动配置指引
- memcore-hermes:记忆目录复用优先级 .claude/memory → .codex/memory → 新建 .agents/memory,显式规避与 Hermes 原生全局 MEMORY.md/USER.md 重复记录
- 后续将追加 packs/*.yaml(hermes plugins pack install 用),需要本次 commit 的 SHA

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015D4xWG3gRWkUKJDgyvtyJw
2026-08-25 15:39:31 +08:00
SkyJourneyandClaude Sonnet 5 42f8e9f483 chore: memory-sync — 归档 zentao-mcp 网桥双认证格式兼容决策
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015D4xWG3gRWkUKJDgyvtyJw
2026-08-25 13:59:38 +08:00
SkyJourneyandClaude Sonnet 5 9d9e31c98e [feat] Add zentao plugin (Claude Code + Codex dual scaffold)
新增禅道项目管理系统插件,含项目集/产品/项目/执行、需求
(story/epic/requirement)、Bug、任务、测试、计划与发布、反馈工单
八个工作流技能,自动配置 MCP 连接(禅道「个人中心 → 获取凭证」
自助生成 14 天 Token)。

MCP Server 是团队自建的 zentao-mcp 网桥(部署在
pm.ops.yixiong-tech.com/mcp),基于开源 openapi-mcp-server 二次开发。
Claude 侧走 userConfig 钥匙链 + 自定义 token 头;Codex 侧受限于官方
插件格式只支持 bearer_token_env_var,走 Authorization: Bearer——网桥
那边已经加了 preferred_header/bearer_mode 配置项统一归一化处理,两条
路径都验证过连通。

三轮审查(静态字段对照 openapi.json、跨文件一致性、真实端点实测)
修正过程中发现的问题,技能文档里引用的工具名全部跟服务器真实注册
的 118 个工具核对过。

同步更新:.claude-plugin/marketplace.json、.agents/plugins/marketplace.json、
README.md、CLAUDE.md 的插件索引与说明;README 补充「获取凭证」操作
截图(已脱敏)。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016pFx6jnym6kRWRQ5JyDUNv
2026-08-25 13:50:41 +08:00
SkyJourneyandClaude Sonnet 5 1606d73c41 chore: memory-sync — 归档 Codex 插件骨架/bearer_token_env_var/不做Antigravity兼容等决策
新增 3 条 decisions.md 条目:Codex/ChatGPT 桌面应用插件骨架设计(三插件
共享 skills/、memcore 独立目录的原因)、Codex 侧 MCP Token 用
bearer_token_env_var 字段的踩坑与本地缓存刷新方法、调研后决定不做
Google Antigravity(agy)兼容。project_overview.md 已发布插件表格补
Codex 支持列,CLAUDE.md 补 Codex plugin.json 硬约束小节与并行结构说明。

memory-lint 顺带修了本机 shell 环境下 Phase 3C 快扫自引用排除逻辑失效
的问题(grep -r 输出不带 ./ 前缀导致误判),修复 1 处断链 + 1 处双链
缺失反向链接。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LVyxoP4cDXeoQ3uAqLcEd2
2026-08-22 18:20:31 +08:00
SkyJourneyandClaude Sonnet 5 a64c64667c fix(codex): huanxi/huanxi-admin MCP token 改用 bearer_token_env_var 字段
原来的 headers.Authorization: "Bearer ${VAR}" 是字符串模板插值写法,
Codex 官方文档(config.toml 场景)没有支持这种写法,正式字段是
bearer_token_env_var(只放变量名,不放值)。openai/codex#24401 目前
仍在讨论插件级 MCP server 用户密钥配置路径未定案的问题,环境变量注入
是当前唯一可用的路径,README 补充了对应免责声明和排查提示。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LVyxoP4cDXeoQ3uAqLcEd2
2026-08-22 17:36:57 +08:00
SkyJourneyandClaude Sonnet 5 eb0e7c3006 docs: README 补充 ChatGPT 桌面应用(原 Codex App)的图形界面安装引导
注册自定义市场源目前只有命令行/手动改配置文件两种方式,桌面应用本身
没有输入市场 URL 的图形入口——如实标注这个限制。市场源生效后可在桌面
应用「设置 → 插件」里图形化安装。另外补充桌面应用(Dock/开始菜单启动)
不继承 shell export 的环境变量这个坑,huanxi/huanxi-admin 的 Token 在
桌面应用场景下需要用 launchctl setenv(macOS)或系统环境变量(Windows)
设置。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LVyxoP4cDXeoQ3uAqLcEd2
2026-08-22 17:17:12 +08:00
SkyJourneyandClaude Sonnet 5 3de9b054ef feat(codex): 新增 Codex CLI 插件市场支持,含独立 memcore-codex
huanxi/huanxi-admin/obsidian 复用 Claude Code 版技能内容,新增
.codex-plugin/plugin.json + .mcp.json(Token 走环境变量,Codex 无等价
钥匙链机制)。memcore 因架构差异(AGENTS.md 会话入口、.codex/memory
目录约定、无远程同步)独立新增 memcore-codex 插件:以本机已装的 Codex
原生版为底稿,抽出 memcore-shared 共享 include,并吸纳 Claude 版的速
度分档过期检测、NEED-HUMAN 稳定 ID 保活、兜底锚点、更完整报告模板四
项内容。新增 .agents/plugins/marketplace.json 收录四个插件,均通过
Codex 官方 validate_plugin.py 校验。

README/CHANGELOG 同步补充双端安装配置引导。删除已被取代的旧
feat/codex-marketplace 骨架分支和已合并的 feat/memcore-optimizations 分支。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LVyxoP4cDXeoQ3uAqLcEd2
2026-08-22 17:13:59 +08:00
SkyJourneyandClaude Sonnet 5 afc8e2c7f8 docs: 新增 README.md 与 CHANGELOG.md
README:安装指引(marketplace add + plugin install,用完整 git URL——
自建 Gitea 不是 GitHub,owner/repo 简写不适用)+ 四个插件的用途说明。

CHANGELOG:本仓库不走语义化版本,plugin.json 不设 version 字段,
按推送 main 的时间线整理每次带来的用户可感知变化。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018xxRKMuiGR4wYT3QbwCpDc
2026-08-22 02:20:28 +08:00
SkyJourneyandClaude Sonnet 5 c8dffe0e4c docs: 同步「已发布插件」表格与项目记忆——huanxi 拆分个人端/管理端
sync_marketplace.py 自动化不了这两处:CLAUDE.md 的「已发布插件」表格、
project_overview.md 的插件清单,手工把原来的单行 huanxi 拆成 huanxi
(个人端 7 技能)/ huanxi-admin(管理端 4 技能,本次首发)两行,技能名
按 huanxi-menagement 仓库 skills/ 的实际内容更新。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018xxRKMuiGR4wYT3QbwCpDc
2026-08-22 02:15:56 +08:00
SkyJourneyandClaude Sonnet 5 600c0dd323 feat: 寰汐插件随 v1.0.0 生产切换升级到 v2 技能组,新增独立管理端插件
huanxi 插件的技能内容从 v1 全面替换为 v2(huanxi-org/huanxi-weekly 等
v1 专属技能下线,新增 huanxi-issue/huanxi-lookup/huanxi-meeting),MCP
连接与 Token 获取方式同步更新为个人中心自助生成。

新增独立的 huanxi-admin 插件(管理端 4 个技能,hxa_ Token,普通员工无需
安装),此前一直卡在"v2 未部署到生产域名前不推送"这条约束,今晚寰汐
v1.0.0 生产切换完成后条件满足。

产物由 huanxi-menagement 仓库 skills/sync_marketplace.py 生成,技能源码
单一真相在该仓库的 skills/,本仓库只接收产物、不手工编辑。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018xxRKMuiGR4wYT3QbwCpDc
2026-08-22 02:14:34 +08:00
75 changed files with 3911 additions and 1170 deletions
+68
View File
@@ -0,0 +1,68 @@
{
"name": "yixiong-codex-hub",
"interface": {
"displayName": "蚁熊 Codex 技能市场"
},
"plugins": [
{
"name": "huanxi",
"source": {
"source": "local",
"path": "./plugins/huanxi"
},
"policy": {
"installation": "AVAILABLE",
"authentication": "ON_INSTALL"
},
"category": "Productivity"
},
{
"name": "huanxi-admin",
"source": {
"source": "local",
"path": "./plugins/huanxi-admin"
},
"policy": {
"installation": "AVAILABLE",
"authentication": "ON_INSTALL"
},
"category": "Productivity"
},
{
"name": "memcore",
"source": {
"source": "local",
"path": "./plugins/memcore-codex"
},
"policy": {
"installation": "AVAILABLE",
"authentication": "ON_INSTALL"
},
"category": "Productivity"
},
{
"name": "obsidian",
"source": {
"source": "local",
"path": "./plugins/obsidian"
},
"policy": {
"installation": "AVAILABLE",
"authentication": "ON_INSTALL"
},
"category": "Productivity"
},
{
"name": "zentao",
"source": {
"source": "local",
"path": "./plugins/zentao"
},
"policy": {
"installation": "AVAILABLE",
"authentication": "ON_INSTALL"
},
"category": "Productivity"
}
]
}
+11 -1
View File
@@ -8,7 +8,12 @@
{
"name": "huanxi",
"source": "./plugins/huanxi",
"description": "寰汐企业管理系统插件:日报/负责人日报/周报/任务管理/组织查询,含 MCP Server 自动配置(Bearer Token 直连"
"description": "寰汐企业管理系统 · 个人端:日报负责人日报、任务、议题、会议、组织检索六个工作流技能,自动配置个人端 MCP 连接(hxp_ Token,在寰汐个人中心自助生成"
},
{
"name": "huanxi-admin",
"source": "./plugins/huanxi-admin",
"description": "寰汐企业管理系统 · 管理端:汇报盘点、模块与成员配置、运维简报三个工作流技能,自动配置管理端 MCP 连接(hxa_ Token,由后台管理员发放)。普通员工无需安装"
},
{
"name": "memcore",
@@ -19,6 +24,11 @@
"name": "obsidian",
"source": "./plugins/obsidian",
"description": "Obsidian 知识库 AI 协作插件族:检测到 .obsidian/ 目录自动激活,含 vault 管理、搜索图谱、frontmatter、任务、每日笔记、Bases 数据库、Canvas 视觉层、版本历史、插件配置、PKM 编排工作流共 10 个技能"
},
{
"name": "zentao",
"source": "./plugins/zentao",
"description": "禅道项目管理系统:项目集/产品/项目/执行、需求(story/epic/requirement)、Bug、任务、测试、计划与发布、反馈工单八个工作流技能,自动配置 MCP 连接(禅道「个人中心 → 获取凭证」自助生成 14 天 Token"
}
]
}
+5 -5
View File
@@ -1,9 +1,9 @@
# Memory Index
> _Last synced: 2026-07-10 | Base commit: `a13898b`_
> _Last synced: 2026-08-25 | Base commit: `56ae43f`_
| 文件 | 描述 | 类型 | 引用 | 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 |
| decisions.md | 关键架构决策:无版本号/userConfig/Bearer Token/SKILL.md规范/路径锁定/memcore三项优化/memcore-shared共享层/lint_report保活/Base commit兜底/obsidian社区对标审查/memory-lint速度分档过期检测/Codex插件骨架与memcore-codex独立目录/Codex侧bearer_token_env_var/不做Antigravity兼容/zentao-mcp网桥双认证格式兼容/Hermes插件骨架与packs选装/Hermes安全扫描description限制/Hermes MCP session-id已知bug | project | 3* | 9e1dcf6 |
| project_overview.md | 项目定位、目录结构、插件规范、发布流程(huanxi/huanxi-admin/memcore/obsidian/zentao,均含 Codex + Hermes 支持情况 | project | 2 | 56ae43f |
| feedback_plugin_dev.md | 插件开发协作规范:同步四处/路径解析/工具签名对照/MCP docstring单一真相/签名变更全量扫描 | feedback | 2 | 38beecb |
| lint_report.md | memory-lint 最新执行结果 | lint | 0 | a64c646 |
+89 -5
View File
@@ -1,9 +1,9 @@
---
name: 架构决策
description: Marketplace 设计中的关键技术决策及其原因:无版本号/userConfig/Bearer Token/SKILL.md规范/路径锁定/memcore三项优化/memcore-shared共享层/lint_report保活/Base commit兜底/obsidian社区对标审查/memory-lint速度分档过期检测
description: Marketplace 设计中的关键技术决策及其原因:无版本号/userConfig/Bearer Token/SKILL.md规范/路径锁定/memcore三项优化/memcore-shared共享层/lint_report保活/Base commit兜底/obsidian社区对标审查/memory-lint速度分档过期检测/Codex插件骨架与memcore-codex独立目录/Codex侧bearer_token_env_var/不做Antigravity兼容/zentao-mcp网桥双认证格式兼容/Hermes插件骨架与packs选装/Hermes安全扫描description限制/Hermes MCP session-id已知bug
type: project
last_updated: 2026-07-10
commit: a13898b
last_updated: 2026-08-25
commit: 9e1dcf6
---
# 关键架构决策
@@ -24,7 +24,7 @@ commit: a13898b
**Why**`sensitive: true` 将 token 存入系统钥匙链(或 `~/.claude/.credentials.json`),不会出现在 settings.json 中,避免随仓库提交泄露。Claude Code 安装插件时自动弹窗提示用户输入,体验好于环境变量。
**How to apply**:其他需要用户配置 API Key/Token 的插件,均应使用此模式,不要用 `${ENV_VAR}` 方式。
**How to apply**:其他需要用户配置 API Key/Token 的插件,均应使用此模式,不要用 `${ENV_VAR}` 方式。此模式仅限 Claude Code 侧——Codex 没有等价钥匙链机制,见 [[decisions.md#Codex 侧 MCP Token 用 bearer_token_env_var,不用 ${VAR} 模板(2026-08-22]]。
```json
"userConfig": {
@@ -37,7 +37,7 @@ commit: a13898b
}
```
**See Also**[[project_overview.md#已发布插件]]
**See Also**[[project_overview.md#已发布插件]]、[[decisions.md#zentao-mcp 网桥已打补丁,双认证格式兼容(2026-08-25]]
---
@@ -174,3 +174,87 @@ commit: a13898b
**How to apply**:新增/调整任何"距离上次更新多久算过期"的判定逻辑时,优先考虑用活跃度信号(提交频次、变更行数等)分档,而非固定日历阈值。常量集中在 `memcore-shared` 全局常量表单点维护,调整数值只改一处。
**See Also**[[decisions.md#memcore-shared:路径锁定 + 全局常量的单一来源]]
---
## Codex/ChatGPT 桌面应用插件骨架——三个插件共享 skills/memcore 独立目录(2026-08-22
**结论**huanxi、huanxi-admin、obsidian 的 Codex 版本通过在同一插件目录下新增 `.codex-plugin/plugin.json`(与 `.claude-plugin/plugin.json` 并列)实现,共用同一份 `skills/``memcore` 因为 Codex 插件校验器要求 `skills` 字段必须精确指向 `./skills`(不能自定义子路径),且 Codex 版记忆体系架构(`AGENTS.md` 会话入口 / `.codex/memory` 目录约定 / 无远程同步)与 Claude 版本质不同,无法共用同一份 `skills/` 内容,故新建独立插件目录 `plugins/memcore-codex/`marketplace.json 里对外插件名仍叫 `memcore`(目录名与插件名不要求一致)。`memcore-codex` 以本机已装的 Codex 原生 memcore 技能为底稿,抽出 `memcore-shared` 共享 include,并吸纳了 Claude 版四项内容:过期检测速度分档、NEED-HUMAN 稳定 ID 保活、memory-update 锚点丢失兜底、更完整的 lint_report 模板。
**Why**:用本机已安装的 Codex `plugin-creator` 技能自带的 `validate_plugin.py` 实测确认——`skills` 字段规整化后必须精确等于 `"skills"``mcpServers` 字符串路径必须精确等于 `"./.mcp.json"`,且都必须在插件根目录(不能嵌套进 `.codex-plugin/`);顶层 `interface` 块(displayName/shortDescription/longDescription/developerName/category/capabilities/defaultPrompt)是必填项,`hooks` 字段不被接受,`disable-model-invocation` 只能是 `false` 或不写。旧的 `feat/codex-marketplace` 分支骨架因为缺 `interface` 块、`.mcp.json` 放错位置,实际过不了这个校验(已删除该分支)。Codex 侧技能级"内部 include 不给用户直接调用"靠 `agents/openai.yaml``policy.allow_implicit_invocation: false` + description 措辞实现,不能像 Claude 侧那样用 frontmatter 禁用模型调用。
**How to apply**:新增/修改 Codex 插件时,先跑本机 `~/.codex/skills/.system/plugin-creator/scripts/validate_plugin.py <plugin-path>` 校验再算完成;技能内容若和 Claude 版能共用就共用同一 `skills/`,若架构本质不同(如需要独立会话入口/目录约定)就整个插件目录独立,不要硬塞进同一 `skills/`
**See Also**[[project_overview.md#已发布插件]]、[[decisions.md#memcore-shared:路径锁定 + 全局常量的单一来源]]、[[decisions.md#memcore lint_report 增量保活:稳定 ID + resolved 跳过]]、[[decisions.md#memory-update Phase 1 锚点丢失兜底]]
---
## Codex 侧 MCP Token 用 bearer_token_env_var,不用 ${VAR} 模板(2026-08-22
**结论**CodexCLI + ChatGPT 桌面应用)没有等价于 Claude `userConfig` 钥匙链的插件级敏感配置机制。`.mcp.json` 里 HTTP 类型 MCP server 的 Bearer Token 必须用专用字段 `bearer_token_env_var: "ENV_VAR_NAME"`(只放变量名,不放值,由 Codex 进程启动时读取该环境变量),而不是在 `headers` 里写 `"Authorization": "Bearer ${VAR}"` 模板插值——后者不被 Codex 支持,会把 `${VAR}` 字面量原样发出去导致鉴权失败。
**Why**:查证 Codex 官方 MCP 配置文档(`config.toml` / `codex mcp add` 场景)确认专用字段是 `bearer_token_env_var` / `env_http_headers`;且有未解决的官方 issue[openai/codex#24401](https://github.com/openai/codex/issues/24401))明确指出插件打包的 MCP server 目前没有官方定义的用户密钥配置路径,环境变量注入(父进程启动前已设置)是当前唯一现实可用方式。实测踩坑:改完 `.mcp.json` 后本机 `codex plugin add` 缓存的旧版本(`~/.codex/plugins/cache/<marketplace>/<plugin>/<version>/`)不会自动更新,必须 `codex plugin marketplace upgrade <marketplace>` 刷新快照后重新 `codex plugin add` 才会生效。
**How to apply**:新增/修改任何 Codex 插件的 HTTP MCP server 配置,一律用 `bearer_token_env_var` 字段;环境变量的设置方式区分场景——CLI 用 shell `export`(写进启动脚本),ChatGPT 桌面应用(图形界面启动,不继承 shell)用 macOS `launchctl setenv` 或 Windows 系统环境变量。改完插件内容 push 后,本机测试前要先 `codex plugin marketplace upgrade <marketplace>` + 重新 `codex plugin add <plugin>@<marketplace>`,否则读到的还是装的时候那份缓存。
**See Also**[[decisions.md#huanxi plugin 使用 userConfig 而非环境变量传 Token]](对照:Claude 侧用 userConfig 钥匙链,Codex 侧被迫用环境变量,是两个平台能力差异,不是我们设计不一致)、[[decisions.md#zentao-mcp 网桥已打补丁,双认证格式兼容(2026-08-25]]
---
## 不做 AntigravityGoogle agy / Antigravity 2.0)兼容(2026-08-22
**结论**:调研后决定暂不为 Google Antigravity CLIagy)和 Antigravity 2.0 桌面应用建插件市场骨架。
**Why**:官方文档(antigravity.google/docs/cli/features/)确认 agy 支持插件(skills/agents/rules/MCP/hooks 打包),但**没有** marketplace 概念——无 `marketplace.json`、无"注册市场源"命令,只有 `agy plugin install <本地路径或 git URL>` 直接安装;网上搜到的"agy 支持 marketplace.json"等说法查证后均来自第三方社区工具(如 `agy-plugins-cli`),非 Google 官方能力。Antigravity 2.0 桌面应用官方文档完全没提插件/市场机制。该产品线是 Google I/O 2026 才发布,文档还在变动(schema 页面实测 404)。
**How to apply**Claude Code 和 Codex 是当前团队实际使用的主流工具,继续投入维护;未来遇到新 AI 编程工具想接入本 marketplace 时,先确认该工具官方是否有稳定的 marketplace/plugin 协议(有市场索引格式 + 远程仓库注册命令),协议不成熟就先不投入,避免跟着一个还在剧烈变动的规范返工。
**See Also**[[project_overview.md#已发布插件]]
---
## zentao-mcp 网桥已打补丁,双认证格式兼容(2026-08-25)
**结论**zentao-mcp 网桥(部署在 `pm.ops.yixiong-tech.com/mcp`,基于 merzzzl/openapi-mcp-server 二次开发)已确认同时兼容两种认证格式:Claude 侧 `.claude-plugin/plugin.json` 用的自定义 `headers: {"token": "..."}`,以及 Codex 侧 `.mcp.json``bearer_token_env_var` 机制底层发出的标准 `Authorization: Bearer <token>`
**Why**:新增 zentao 插件时曾担心两侧 header 格式不一致会导致 Codex 链路认证失败——Claude 侧网桥原生认的是自定义 `token` header,而 Codex 的 `bearer_token_env_var` 只会发标准 Bearer 格式,两者字面不同。用户确认网桥已就此打过补丁,双格式都认,不存在兼容问题。
**How to apply**zentao 插件的 Claude/Codex 双端 Token 配置模式确认与 huanxi 一致([[decisions.md#huanxi plugin 使用 userConfig 而非环境变量传 Token]] + [[decisions.md#Codex 侧 MCP Token 用 bearer_token_env_var,不用 ${VAR} 模板(2026-08-22]]),无需为 zentao 网桥单独定制认证适配。未来若网桥做重大改版,需重新确认这条双格式兼容性是否还成立。
**See Also**[[project_overview.md#已发布插件]]
---
## Hermes 插件骨架:Agent Plugins v1 + packs 选装(2026-08-25
**结论**huanxi/huanxi-admin/obsidian/zentao 在插件根目录新增裸 `plugin.json`[Agent Plugins v1.0.0](https://agent-plugins.org/) 标准,字段仅 `$schema`+`name`+可选元数据),复用同一份 `skills/``memcore` 因架构差异走独立目录 `plugins/memcore-hermes/`(记忆目录优先级 `.claude/memory``.codex/memory` → 新建 `.agents/memory`,且显式提醒 Hermes 自己按 profile 隔离的全局 `~/.hermes/memories/` 不是项目记忆后端)。分发不走 `hermes plugins install owner/repo`(该命令按文档examples只支持整仓库=一个插件包),改用 `packs/<name>.yaml` + `hermes plugins pack install`pack manifest 的 `subdir` 字段官方支持 monorepo 定位)。
**Why**:调研过程中依次排除了三条路径——① `hermes plugins install owner/repo` 无 subdir 支持(用户质疑"仓库多插件不合理"后深挖才找到 pack 机制,此前调研不够);② 自建 `plugins.index_url` 覆盖官方社区索引会让用户暂时搜不到 NousResearch 官方索引里的插件,属单值配置非叠加,用户认为代价太大;③ 最终定为每插件一个 `packs/<name>.yaml`,互不影响、无副作用。凭证类插件不打包 `mcp.json` 是因为 Agent Plugins v1 规范明文禁止内嵌密钥(headers/env 都不行),Hermes 原生 `~/.hermes/config.yaml` 支持 `${VAR}` 插值,改为 README 手动配置指引,用户体验类比 Codex 桌面应用的 `launchctl setenv` 变通方案。
**How to apply**Hermes 的 `ref` 字段要求精确 40 位 commit SHA、不接受分支名,`packs/*.yaml` 需要在每次相关内容发布后手动 bump(不像 Claude Code 的 git SHA 自动追新)。两处此前未经验证的点已由用户用真实 Hermes 实测确认:① `pack install` 支持直接传 http(s) raw 链接,不用先 clone;② `subdir` 定位的目录只有 `plugin.json`(没有原生 `plugin.yaml`)能被正确安装(前提是通过安全扫描,见 [[decisions.md#Hermes 插件安装安全扫描:plugin.json description 不能含配置路径字面量(2026-08-25)]])。
**See Also**[[project_overview.md#已发布插件]]、[[decisions.md#Hermes 插件安装安全扫描:plugin.json description 不能含配置路径字面量(2026-08-25]]、[[decisions.md#Hermes MCP Streamable HTTP session-id 已知 bug——凭证类插件连接受阻(2026-08-25]]
---
## Hermes 插件安装安全扫描:plugin.json description 不能含配置路径字面量(2026-08-25)
**结论**huanxi/huanxi-admin/zentao 的 `plugin.json` `description` 字段精简为一句话简介,删除了原先写的 `~/.hermes/config.yaml` 等操作指引文字;具体配置步骤只保留在 README 里。
**Why**:用户实测 `hermes plugins pack install` 被安全扫描 BLOCKED——Hermes 官方文档确认 community source(非 Nous 官方审核)插件的扫描是零容忍策略,任意 1 个 finding 就拒绝安装且 `--force` 无法覆盖;报错精确指向 `plugin.json:5`description 字段),命中的是 `CRITICAL persistence` 类别。description 里字面写的 `~/.hermes/config.yaml`(点前缀配置文件路径字符串)大概率撞上了扫描器针对"持久化/自我修改配置"模式的启发式规则——这类字符串常见于恶意插件描述自己如何篡改用户配置实现驻留,扫描器无法区分"教用户怎么手动配置"和"指导 AI 怎么植入后门"两种语义。
**How to apply**:任何 Hermes 插件(尤其面向 community source 分发的)的 `plugin.json` description 只写功能简介,不要出现具体文件路径(尤其 `~/.` 开头的配置/凭证类路径)、shell 命令片段或操作步骤——这类内容一律放 README,不进 plugin.json。遇到 BLOCKED 报错时先看 `Verdict`/`findings` 指向的具体文件和行号,大概率能定位到触发字符串。
**See Also**[[decisions.md#Hermes 插件骨架:Agent Plugins v1 + packs 选装(2026-08-25]]
---
## Hermes MCP Streamable HTTP session-id 已知 bug——凭证类插件连接受阻(2026-08-25)
**结论**huanxi/huanxi-admin/zentao 在 Hermes 上配置 HTTP 类型 MCP Server 后,`initialize` 握手能成功,但后续请求会报 400 并最终 park 连接。用 curl 直连 zentao-mcp 网桥验证过网桥本身没问题(认证正常、`initialize` 返回 200 且带 `mcp-session-id`),判断是 Hermes 客户端未正确捕获/回传 Streamable HTTP 协议要求的 `mcp-session-id`,与 [NousResearch/hermes-agent#20349](https://github.com/NousResearch/hermes-agent/issues/20349) 描述的现象一致。用户决定暂不深究 workaround,等 Hermes 上游修复。
**Why**MCP Streamable HTTP 传输协议是有状态会话——服务器在 `initialize` 响应头里下发 `mcp-session-id`,客户端后续请求必须原样带回 `Mcp-Session-Id` 请求头,服务器才认下一步请求;curl 手工构造带完整 header 的请求能跑通全流程,排除了网桥端的问题。`protocol: legacy`/`skip_preflight: true` 都试过无效,因为问题出在握手**之后**的会话保持,不是握手协商本身。
**How to apply**:这不是我们插件配置能修的问题,不要在 plugin.json/pack/README 里继续折腾 MCP 相关参数试图绕过。定期检查 [#20349](https://github.com/NousResearch/hermes-agent/issues/20349) 状态,Hermes 发布修复版本后回来验证并更新 README 里的已知问题说明;`obsidian`/`memcore-hermes` 不含 MCP,不受影响,可以正常使用。
**See Also**[[decisions.md#Hermes 插件骨架:Agent Plugins v1 + packs 选装(2026-08-25]]
+16 -20
View File
@@ -2,13 +2,13 @@
name: 记忆健康检查报告
description: memory-lint 最新一次执行的检查结果与待处理项
type: lint
last_updated: 2026-07-10
commit: a13898b
last_updated: 2026-08-25
commit: 9d9e31c
---
# 记忆健康检查报告
> _执行时间: 2026-07-10 | Base commit: `a13898b` | Last synced: 2026-07-10_
> _执行时间: 2026-08-25 | Base commit: `9d9e31c` | Last synced: 2026-08-25_
>
> **如何使用**NEED-HUMAN 条目末尾有 `<!-- id: xxxxxxxx -->` 标记。处理完或决定不处理时,在同段追加 `<!-- resolved: DATE, 简要原因 -->`,下次 lint 该条目自动跳过。
@@ -16,18 +16,16 @@ commit: a13898b
| 检查项 | AUTO-FIX | NEED-HUMAN(含已 resolved 跳过 N 项) |
|--------|---------|-----------|
| 1 孤儿 / 2 幽灵 / 3A 引用 / 3B 双链 | 0 / 0 / 2 / 0 | — / — / 0 / 1(含已 resolved 跳过 0 项) |
| 1 孤儿 / 2 幽灵 / 3A 引用 / 3B 双链 | 0 / 0 / 0 / 0 | — / — / 0 / 1(含已 resolved 跳过 0 项) |
| 4 矛盾 / 5 过期 / 6 污染 | — | 0 / 0 / 0 |
**AUTO-FIX 已执行 2 项 | NEED-HUMAN 列出 1 项 | 历史已 resolved 跳过 0 项**
**AUTO-FIX 已执行 0(本轮结构性检查全部通过,新增的 zentao-mcp 网桥决策条目双向引用在 memory-update 阶段已手工补齐) | 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
本轮无需 AUTO-FIX:孤儿 / 幽灵 / 断链 / 双链非对称检测均通过(新增的 `decisions.md#zentao-mcp 网桥已打补丁,双认证格式兼容(2026-08-25)` 条目与 `huanxi userConfig``Codex bearer_token_env_var``project_overview.md#已发布插件` 三处的双向链接已在 memory-update 阶段随内容一并写入)。
---
@@ -39,7 +37,7 @@ commit: a13898b
|------|----------|------|
| — | — | 无候选 |
当前所有 decisions/feedback 条目的**单 section 级**跨文件引用数均 < 3,无 synthesis 升级候选。
`feedback_plugin_dev.md#MCP 后端工具签名变更后必须全量扫描所有 skill``decisions.md``lint_report.md` 两个文件引用(2 次,未达阈值 3);此前一次快扫误报为 3 次,是本机 shell 环境下 `grep -r` 输出不带 `./` 前缀导致自引用排除逻辑失效所致,本次已用去重比对方式重新核实,非真实候选。
---
@@ -55,26 +53,24 @@ commit: a13898b
---
## 文件级引用计数(来自 Phase 3A,按源文件去重)
## 文件级引用计数(来自 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 |
| **decisions.md** | **3\*** | feedback_plugin_dev.md / project_overview.md / lint_report.md |
| project_overview.md | 2 | decisions.md / lint_report.md |
| feedback_plugin_dev.md | 2 | decisions.md / lint_report.md |
| 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),跳过 |
| feedback_plugin_dev.md | 2026-06-12 | 74 | 17 | 0.22 | 低于 LOW_VELOCITY(0.3) 且 days_since(74) < ABSOLUTE_DAYS(180),不判定过期 |
| decisions.md | 2026-08-25 | 0 | | — | 不足 MIN_DAYS(7),跳过 |
| project_overview.md | 2026-08-25 | 0 | — | — | 不足 MIN_DAYS(7),跳过 |
| lint_report.md | 2026-08-25 | 0 | — | — | 不足 MIN_DAYS(7),跳过 |
+13 -9
View File
@@ -1,9 +1,9 @@
---
name: 项目概述
description: yixiong-claude-marketplace 的定位、目录结构、插件规范和发布流程
description: yixiong-claude-marketplace 的定位、目录结构、插件规范和发布流程,同时支持 Claude Code 与 Codex/ChatGPT 桌面应用两条市场线(huanxi/huanxi-admin/memcore/obsidian/zentao 五个已发布插件)
type: project
last_updated: 2026-06-12
commit: fad7335
last_updated: 2026-08-25
commit: 56ae43f
---
# 蚁熊内部 Claude Code Marketplace
@@ -58,13 +58,17 @@ description: "触发描述(用户实际口语,不用内部视角)"
## 已发布插件
| 插件 | 技能 | 特性 |
|------|------|------|
| `huanxi` | 6 个(report/leader/task/weekly/org/shared | userConfig Bearer Token + MCP ServerURL 走 office 子域,无端口) |
| `memcore` | 4 个(memory-sync/lint/update/shared | 纯技能,无 MCPmemcore-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 子流程 |
| 插件 | 技能 | 特性 | Codex 支持 | Hermes 支持 |
|------|------|------|------|------|
| `huanxi` | 个人端 7 个(report/leader/task/issue/meeting/lookup/shared | userConfig Bearer Tokenhxp_+ MCP ServerURL 走 office 子域,无端口) |`.codex-plugin/plugin.json` 共用同一 `skills/`Token 走环境变量 `HUANXI_TOKEN``bearer_token_env_var` | ✅ 裸 `plugin.json`Agent Plugins v1)共用同一 `skills/`,不打包 `mcp.json`Token 走 `~/.hermes/config.yaml` 手动 `${VAR}` 插值 |
| `huanxi-admin` | 管理端 4 个(admin-report/admin-module/admin-ops/admin-shared | userConfig Bearer Tokenhxa_+ MCP Server;普通员工无需安装,2026-08-21 v1.0.0 生产切换后首次发布 | ✅ 同上模式,Token 环境变量 `HUANXI_ADMIN_TOKEN` | ✅ 同 huanxi 模式,Token 环境变量 `HUANXI_ADMIN_TOKEN` |
| `memcore` | Claude 版 4 个(memory-sync/lint/update/shared | 纯技能,无 MCPmemcore-shared 作内部 include(路径锁定 + 阈值常量 + PROJECT_DIR 解析),支持 synonyms.md 等价词表、Phase 3C 即时引用快扫、Phase 0 并发冲突保护、lint_report 稳定 ID + resolved 跳过、Base commit 兜底 | ✅ 独立目录 `plugins/memcore-codex/`(不与 Claude 版共用 `skills/`),架构不同:`AGENTS.md` 会话入口、`.claude/memory` 优先复用否则落 `.codex/memory`、无远程同步 | ✅ 独立目录 `plugins/memcore-hermes/`,记忆目录优先级 `.claude/memory``.codex/memory` → 新建 `.agents/memory`;显式提醒不与 Hermes 原生全局 `~/.hermes/memories/`(按 profile 隔离)混淆 |
| `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 子流程 | ✅ `.codex-plugin/plugin.json` 共用同一 `skills/`,无 MCP 无需 Token | ✅ 裸 `plugin.json` 共用同一 `skills/`,无 MCP 无需配置 |
| `zentao` | 8 个(project/story/bug/task/test/plan/misc/shared | userConfig Token(禅道「个人中心 → 获取凭证」14 天有效期自助生成,非 Bearer 标准格式,走自定义 header `"token": "${user_config.token}"`+ MCP ServerMCP Server 是基于开源 merzzzl/openapi-mcp-server 二次开发的 zentao-mcp 网桥,部署在 `pm.ops.yixiong-tech.com/mcp`,请求体字段统一包在 `payload` 里;README 配了三张截图(`docs/images/zentao-token/`)图解获取凭证流程 | ✅ `.codex-plugin/plugin.json` 共用同一 `skills/`Token 走环境变量 `ZENTAO_TOKEN``bearer_token_env_var`);网桥已确认同时兼容自定义 `token` header 与标准 `Authorization: Bearer`,双端认证均可用 | ✅ 裸 `plugin.json` 共用同一 `skills/`Token 走 `~/.hermes/config.yaml` 手动配置 `headers: {token: "${ZENTAO_TOKEN}"}` |
**See Also**[[decisions.md#huanxi plugin 使用 userConfig 而非环境变量传 Token]]
Codex/ChatGPT 桌面应用侧市场索引独立维护在 `.agents/plugins/marketplace.json`marketplace 名 `yixiong-codex-hub`),与 Claude 侧 `.claude-plugin/marketplace.json``yixiong-claude-hub`)并存,互不干扰。Hermes 侧没有中心化市场索引机制,靠仓库根目录 [`packs/`](../../packs) 下逐插件的 pack manifest`hermes plugins pack install ./packs/<name>.yaml`)选装,`ref` 需在每次相关发布后手动 bump 到最新 commit SHA。已确认不做 AntigravityGoogle agy)兼容。
**See Also**[[decisions.md#huanxi plugin 使用 userConfig 而非环境变量传 Token]]、[[decisions.md#Codex/ChatGPT 桌面应用插件骨架——三个插件共享 skills/memcore 独立目录(2026-08-22]]、[[decisions.md#不做 AntigravityGoogle agy / Antigravity 2.0)兼容(2026-08-22]]、[[decisions.md#zentao-mcp 网桥已打补丁,双认证格式兼容(2026-08-25]]、[[decisions.md#Hermes 插件骨架:Agent Plugins v1 + packs 选装(2026-08-25]]
## 发布流程
+31
View File
@@ -0,0 +1,31 @@
# 更新记录
本仓库不走语义化版本号——`plugin.json` 不设 `version` 字段,Claude Code 用 git commit SHA 作为版本基准,每次推送 `main` 分支即视为新版本,已安装用户会话启动时自动检测更新。这份记录按时间线整理每次推送带来的用户可感知变化,最新的排在最上面。
## 2026-08-22
- **新增 Codex CLI 支持**`huanxi`/`huanxi-admin`/`obsidian` 复用 Claude Code 版技能内容,新增 `.codex-plugin/plugin.json` + `.mcp.json`Token 走环境变量 `HUANXI_TOKEN`/`HUANXI_ADMIN_TOKEN`Codex 没有等价的钥匙链机制);`memcore` 因架构差异(`AGENTS.md` 会话入口、`.codex/memory` 目录约定、无远程同步)独立新增 `memcore-codex` 插件,以本机已装的 Codex 原生版为底稿,吸纳了 Claude 版的速度分档过期检测、NEED-HUMAN 稳定 ID 保活、兜底锚点、更完整报告模板四项内容,并抽出 `memcore-shared` 共享 include。新增 `.agents/plugins/marketplace.json` 收录四个插件,均通过 Codex 官方 `validate_plugin.py` 校验
- README 补充 Claude Code / Codex CLI 双端的安装命令与配置引导(huanxi Token 获取步骤、Codex 环境变量注入方式、memcore 两版本架构差异说明)
- **`huanxi` 全面升级到 v2 技能组**:技能内容从寰汐 v1 全面替换为 v2,`huanxi-org`/`huanxi-weekly` 等 v1 专属技能下线,新增 `huanxi-issue`/`huanxi-lookup`/`huanxi-meeting`;MCP 连接与 Token 获取方式同步更新为寰汐「个人中心 → MCP Token 管理」自助生成
- **新增 `huanxi-admin` 插件**:管理端 4 个技能(汇报盘点、模块与成员配置、运维简报),需要后台管理员发放 `hxa_` Token,普通员工无需安装。此前一直卡在"寰汐 v2 未部署到生产域名前不推送"这条约束,随寰汐 v1.0.0 生产切换完成后正式首发
## 2026-07-10
- `memcore``memory-lint` 过期检测从固定天数阈值改为按仓库提交速度分档:高频迭代项目下更早报警,低活跃项目下不会因为"只是没人动"就被误判为过期
## 2026-06-17
- `huanxi` 技能修正工具调用描述与实际参数不一致的问题,补充"工具定义优先于技能文档描述"的规范
## 2026-06-12
- `obsidian` 新增 `obsidian-canvas` 技能(JSON Canvas 1.0 视觉层支持),核心 `obsidian` 技能补齐 OFMObsidian Flavored Markdown)语法速查,`workflow-pkm` 补 Web Clip 子流程,整体做了一轮描述去冗余
- `huanxi``memcore` 全量修正技能描述与实际行为之间的漂移
## 2026-05-10
- `memcore` 三项优化:等价表述清单(降低 lint 误报)、Phase 3C 即时引用快扫(同步触发 synthesis 升级候选检测,不必等 lint)、并发写入冲突保护(多机/多会话同时写记忆文件时的合并策略)
## 2026-05-08
- 仓库最早的记录节点:`obsidian` 插件与 `memcore` 路径锁定相关决策归档
+34 -4
View File
@@ -1,4 +1,4 @@
<!-- Last updated: 2026-07-10 | Commit: a13898b -->
<!-- Last updated: 2026-08-25 | Commit: 9e1dcf6 -->
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
@@ -22,6 +22,10 @@ plugins/
└── SKILL.md # 技能实现(frontmatter + Markdown 指令)
```
本仓库同时是 Codex/ChatGPT 桌面应用的插件市场,独立索引在 `.agents/plugins/marketplace.json`。huanxi/huanxi-admin/obsidian 在各自插件目录下再放一份 `.codex-plugin/plugin.json`(与 `.claude-plugin/plugin.json` 并列),共用同一份 `skills/``memcore` 因架构差异(见下方「Codex plugin.json」与「memcore 技能调用关系」两节)走独立目录 `plugins/memcore-codex/`
本仓库还支持 Hermes AgentNous Research 开源本地 Agent),走开放标准 [Agent Plugins v1.0.0](https://agent-plugins.org/)huanxi/huanxi-admin/obsidian/zentao 在插件根目录再放一份**裸** `plugin.json`(不嵌套在点前缀目录里,规范要求),共用同一份 `skills/``memcore` 因架构差异同样走独立目录 `plugins/memcore-hermes/`。Hermes 没有中心化市场命令,靠 [`packs/`](./packs) 目录下的 pack manifest`hermes plugins pack install`)逐个选装,见下方「Hermes plugin.json」一节。
## 核心文件格式
### marketplace.json(市场索引)
@@ -65,6 +69,28 @@ description: 一句话说明该技能的用途(Claude 用此判断何时触发
`description` 字段是触发判据,务必精确描述使用场景,避免与其他技能产生歧义。
### Codex plugin.jsonCodex 侧插件元数据)
用本机 `~/.codex/skills/.system/plugin-creator/scripts/validate_plugin.py <plugin-path>` 校验后确认的硬性约束(与 Claude 侧 plugin.json 不通用,不要照抄):
- `skills` 字段规整化后必须精确等于 `"skills"`,不能指向自定义子路径
- `mcpServers` 若为字符串路径,必须精确等于 `"./.mcp.json"`,且该文件在**插件根目录**(不能嵌套进 `.codex-plugin/`);HTTP 类型 MCP server 的 Bearer Token 用专用字段 `bearer_token_env_var: "ENV_VAR_NAME"`,不支持 `${VAR}` 模板插值(见 [[decisions.md#Codex 侧 MCP Token 用 bearer_token_env_var,不用 ${VAR} 模板(2026-08-22]]
- 顶层 `interface` 块必填:`displayName`/`shortDescription`/`longDescription`/`developerName`/`category`/`capabilities`/`defaultPrompt`
- 不支持 `hooks` 字段
- 技能 frontmatter 的 `disable-model-invocation` 只能是 `false` 或不写;技能"内部 include 不给用户直接调用"要用该技能 `agents/openai.yaml` 里的 `policy.allow_implicit_invocation: false` + description 措辞实现
### Hermes plugin.jsonHermes 侧插件元数据)
跟 Claude/Codex 侧都不通用,走 [agent-plugins.org 官方 spec](https://agent-plugins.org/specification) 定义的硬性约束:
- 文件必须叫 `plugin.json`,直接放在插件根目录(不能嵌套进任何点前缀目录)
- 必需字段只有 `$schema` + `name``name` 限定 `[a-z0-9.-]`、164 字符,不能以 `-`/`.` 开头结尾,不能出现连续的 `--`/`..`
- `skills/` 目录下每个直接子目录只要含 `SKILL.md` 就会被识别为一个技能,不需要额外声明
- **规范禁止在 `mcp.json` 里内嵌密钥**(headers/env 都不行,也没有等价于 `bearer_token_env_var`/`userConfig` 的字段):带 Token 的插件(huanxi/huanxi-admin/zentao)因此不打包 `mcp.json`MCP 配置改走 README 里的 `~/.hermes/config.yaml` 手动指引(该文件原生支持 `${VAR}` 环境变量插值)
- 单仓库多插件靠 `hermes plugins pack install ./packs/<name>.yaml``subdir` 字段定位子目录,`ref` 必须是精确 40 位 commit SHA(不接受分支名),改动插件后要记得同步 bump `packs/*.yaml` 里的 `ref``pack install` 已实测确认支持直接传 http(s) raw 链接,也确认纯 `plugin.json`(无原生 `plugin.yaml`)能被正确安装
- **`description` 字段不要写配置文件路径字面量**(如 `~/.hermes/config.yaml`)——Hermes 对 community source 插件的安装前安全扫描零容忍,命中一次就 BLOCKED、`--force` 不能覆盖,此类路径字符串容易被误判成 persistence 危险模式,见 [[decisions.md#Hermes 插件安装安全扫描:plugin.json description 不能含配置路径字面量(2026-08-25]]
- **已知问题**huanxi/huanxi-admin/zentao 的 HTTP MCP 在 Hermes 上会因为 Streamable HTTP `mcp-session-id` 回传 bug 连不上([NousResearch/hermes-agent#20349](https://github.com/NousResearch/hermes-agent/issues/20349)),非我们插件问题,等上游修复,见 [[decisions.md#Hermes MCP Streamable HTTP session-id 已知 bug——凭证类插件连接受阻(2026-08-25]]
## 新增插件流程
1.`plugins/` 下创建目录 `plugins/<plugin-name>/`
@@ -76,9 +102,13 @@ description: 一句话说明该技能的用途(Claude 用此判断何时触发
| 插件 | 技能 | 说明 |
|------|------|------|
| `huanxi` | `/huanxi-shared` `/huanxi-report` `/huanxi-leader` `/huanxi-task` `/huanxi-weekly` `/huanxi-org` | 寰汐企业管理系统完整工作流,含 MCP Server 自动配置 |
| `huanxi` | `/huanxi-shared` `/huanxi-report` `/huanxi-leader` `/huanxi-task` `/huanxi-issue` `/huanxi-meeting` `/huanxi-lookup` | 寰汐企业管理系统 · 个人端(7 技能),以本人身份操作,含 MCP Server 自动配置hxp_ Token |
| `huanxi-admin` | `/huanxi-admin-shared` `/huanxi-admin-report` `/huanxi-admin-module` `/huanxi-admin-ops` | 寰汐企业管理系统 · 管理端(4 技能),全量视角,需后台管理员发放 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 |
| `zentao` | `/zentao-shared` `/zentao-project` `/zentao-story` `/zentao-bug` `/zentao-task` `/zentao-test` `/zentao-plan` `/zentao-misc` | 禅道项目管理系统(8 个技能),含 MCP Server 自动配置(禅道「个人中心 → 获取凭证」14 天 Token);MCP Server 是基于开源 [merzzzl/openapi-mcp-server](https://github.com/merzzzl/openapi-mcp-server) 二次开发的 zentao-mcp 网桥,部署在 `pm.ops.yixiong-tech.com/mcp`,请求体字段统一包在 `payload` 里 |
五个插件均有 Codex/ChatGPT 桌面应用版本(见上方「Codex plugin.json」一节)和 Hermes Agent 版本(见上方「Hermes plugin.json」一节)。huanxi/huanxi-admin/obsidian/zentao 的 Codex 版、Hermes 版都共用本表里的同一份 `skills/``memcore` 的 Codex 版是独立目录 `plugins/memcore-codex/`Hermes 版是独立目录 `plugins/memcore-hermes/`(内容与下方 Claude 版 memcore 均不同,三边分别维护,不要假设同步)。已调研并确认不做 Google Antigravityagy)兼容——其官方文档目前没有 marketplace 概念。
### memcore 技能调用关系
@@ -113,8 +143,8 @@ description: 一句话说明该技能的用途(Claude 用此判断何时触发
```
.claude/memory/
├── MEMORY.md # 索引(入口)
├── decisions.md # 关键架构决策(含 memcore-shared/lint_report 保活/Base commit 兜底/obsidian 社区对标审查/memory-lint 速度分档过期检测等 13 项)
├── project_overview.md # 项目定位与结构(huanxi/memcore/obsidian 10 技能 已发布插件
├── decisions.md # 关键架构决策(含 memcore-shared/lint_report 保活/Base commit 兜底/obsidian 社区对标审查/memory-lint 速度分档过期检测/Codex 插件骨架与 memcore-codex 独立目录/bearer_token_env_var/不做 Antigravity 兼容/zentao-mcp 网桥双认证格式兼容/Hermes 插件骨架与 packs 选装/Hermes 安全扫描 description 限制/Hermes MCP session-id 已知 bug 等 20 项)
├── project_overview.md # 项目定位与结构(huanxi/huanxi-admin/memcore/obsidian/zentao 已发布插件,均含 Codex + Hermes 支持情况
├── feedback_plugin_dev.md # 插件开发协作规范(含 MCP docstring 单一真相、签名变更全量扫描)
└── lint_report.md # 记忆健康检查报告(按需)
```
+194
View File
@@ -0,0 +1,194 @@
# 蚁熊技能市场
蚁熊团队内部的插件市场,同时支持 **Claude Code**、**Codex(含 ChatGPT 桌面应用与 CLI 两种形态)**和 **Hermes Agent**——汇聚团队在真实业务场景里打磨出来的技能与工作流插件,从项目管理到知识库协作,从代码审查到数据工程,装上它,让 AI 编程助手更懂蚁熊。
## 快速安装
### Claude Code
```
/plugin marketplace add https://gitea.rk-health.com/yixiong/yixiong-claude-marketplace.git
```
添加市场源之后,按需安装具体插件:
```
/plugin install huanxi@yixiong-claude-hub
/plugin install huanxi-admin@yixiong-claude-hub
/plugin install memcore@yixiong-claude-hub
/plugin install obsidian@yixiong-claude-hub
/plugin install zentao@yixiong-claude-hub
```
已安装的插件会在会话启动时自动检测更新——本仓库不走语义化版本号,每次推送 `main` 分支即视为新版本。
### Codex CLI / ChatGPT 桌面应用
Codex 的桌面客户端已经并入 **ChatGPT 桌面应用**(原先叫 Codex App),插件市场和技能在 CLI、桌面应用、VS Code 插件三端共用同一套 `.agents/plugins/marketplace.json`
**第一步——注册市场源(仅命令行,桌面应用没有输入市场 URL 的图形入口):**
```
codex plugin marketplace add https://gitea.rk-health.com/yixiong/yixiong-claude-marketplace.git
```
没有终端环境,或者只想用桌面应用的话,也可以手动把同样的条目写进配置文件,效果等价:
- 只想在这台机器全局生效:`~/.agents/plugins/marketplace.json`
- 只想在某个仓库生效:`<仓库根目录>/.agents/plugins/marketplace.json`(本仓库已经自带一份,克隆下来就有)
写完保存后,**完全退出并重新打开 ChatGPT 桌面应用**(不是切后台,是完全退出进程)才会生效,官方文档目前没有提供"设置里粘贴 URL"这种图形化入口。
**第二步——安装插件:**
- **命令行**
```
codex plugin add huanxi@yixiong-codex-hub
codex plugin add huanxi-admin@yixiong-codex-hub
codex plugin add memcore@yixiong-codex-hub
codex plugin add obsidian@yixiong-codex-hub
codex plugin add zentao@yixiong-codex-hub
```
- **ChatGPT 桌面应用(图形界面)**:市场源注册生效后,打开 **设置(Settings)→ 插件(Plugins**,或侧边栏的 **Plugins** 入口,就能看到我们的市场和这五个插件,点击安装即可,不用碰命令行。
安装完成后开一个新会话,Codex 才会加载新装的技能和 MCP 工具。
> ⚠️ **桌面应用读不到 shell 里 `export` 的环境变量**`huanxi`/`huanxi-admin`/`zentao` 的 Token 走环境变量注入(见下一节),但 macOS/Windows 上从 Dock/开始菜单启动的图形应用不会继承 `~/.zshrc` 里 `export` 的变量——这是终端应用和图形应用两种不同的启动路径决定的,不是我们插件的问题。桌面应用场景要设置成**系统级/用户级持久环境变量**才行,具体见下一节。
>
> ⚠️ **插件级 Token 配置目前是 Codex 官方还没定案的能力**:截至本文写作时,插件打包的 MCP server 没有类似 Claude 侧「安装时弹窗填 Token」的正式支持(见 [openai/codex#24401](https://github.com/openai/codex/issues/24401)),环境变量是目前唯一现实可用的路径。装完插件连不上 MCP,先检查 Token 环境变量是不是在 Codex/ChatGPT 启动**之前**就已经生效。
> Codex 侧的插件清单独立维护在 [`.agents/plugins/marketplace.json`](./.agents/plugins/marketplace.json)。除 `memcore` 外,其余四个插件与 Claude Code 版共用同一份 `skills/``memcore` 因为架构差异(会话入口、记忆目录约定、有无远程同步都不同)走的是独立目录 [`plugins/memcore-codex/`](./plugins/memcore-codex),两边分开维护。
### Hermes Agent
HermesNous Research 开源的本地 Agent)没有像 Claude/Codex 那样的"注册市场源"命令,但官方支持一个跨客户端开放标准 [Agent Plugins v1.0.0](https://agent-plugins.org/)`plugin.json` + `skills/`),且 `hermes plugins pack install` 支持 `subdir` 定位 monorepo 子目录——所以我们没有另开仓库,而是在每个插件根目录放一份裸 `plugin.json`,复用同一份 `skills/`,用一组 [`packs/`](./packs) 里的 pack manifest 文件做选装。
**安装(想装哪个装哪个,互不影响):**
```bash
# 方式一:先看会装什么,再装(本地路径,需要先 clone)
git clone https://gitea.rk-health.com/yixiong/yixiong-claude-marketplace.git
cd yixiong-claude-marketplace
hermes plugins pack show ./packs/zentao.yaml
hermes plugins pack install ./packs/zentao.yaml
# 方式二:不用 clone,直接传 raw 链接(已验证可用)
hermes plugins pack install https://gitea.rk-health.com/yixiong/yixiong-claude-marketplace/raw/branch/main/packs/zentao.yaml
```
想一次装全部五个:`hermes plugins pack install ./packs/all.yaml`。
装的插件是**用户/profile 级**的,不是项目级——Hermes 的 `plugins install`/`pack install` 都没有 `--scope`/`--project` 之类的参数,固定装进 `$HERMES_HOME/plugins/`(默认 profile 就是 `~/.hermes/plugins/`),装完之后在这台机器的哪个目录开 Hermes 会话都能用,跟"只在这个仓库目录里生效"的直觉不一样。
> ⚠️ **`ref` 是手动维护的定长 commit SHA,不会像 Claude Code 那样自动追新**——Hermes 的 pack manifest 要求精确 40 位 commit SHA,不接受分支名,我们每次发布都会同步 bump `packs/*.yaml` 里的 `ref`;如果你 clone 下来的代码比 pack 文件新,装的仍是 pack 里锁定的那个旧版本,想要最新内容就 `git pull` 到对应 commit 或等我们下一次发布。
>
> ⚠️ **凭证类插件(`huanxi`/`huanxi-admin`/`zentao`)不含 MCP 声明**——Agent Plugins v1 的 `mcp.json` 规范明文禁止内嵌密钥,所以这三个插件只打包了技能,MCP Server 需要你在 `~/.hermes/config.yaml` 里手动加几行(下面各插件小节有具体片段),比 Claude 的"装插件时弹窗填 Token"体验差一点,这是协议本身的限制,不是我们没做完。
>
> ⚠️ **`plugin.json` 的 `description` 不要写配置路径字面量**——Hermes 对 community source(非官方审核)插件的安装前安全扫描是"零容忍"策略,任意 1 个 finding 就直接 BLOCKED、`--force` 也无法覆盖;早期版本我们在 description 里写了 `~/.hermes/config.yaml` 这种点前缀路径字符串,被误判成 persistence(持久化)类危险模式挡了下来。现在 description 只放一句话简介,配置指令都放在这份 README 里,不会再触发。
>
> ⚠️ **已知问题(非我们插件的锅,等 Hermes 上游修复)**:`huanxi`/`huanxi-admin`/`zentao` 走 HTTP 类型 MCP Server,实测在 Hermes 上会卡在 `initialize` 握手之后——网桥正确返回了 `mcp-session-id`Streamable HTTP 协议的有状态会话标识),但 Hermes 客户端没有正确捕获/回传这个 session id,导致后续请求被判定为无效、报 400,最终连接被 park。这跟 [NousResearch/hermes-agent#20349](https://github.com/NousResearch/hermes-agent/issues/20349) 描述的现象一致,用 curl 直连网桥验证过网桥本身没问题(认证、握手响应都正常)。装完插件后如果 MCP 连不上,先去这条 issue 底下看有没有新版本修复,`protocol: legacy` 试过没用(握手本身不是问题所在);`obsidian`/`memcore-hermes` 不受影响(不含 MCP)。
## 插件一览
| 插件 | 技能数 | 适用场景 | 谁需要装 | Claude Code | Codex | Hermes |
|---|---|---|---|:---:|:---:|:---:|
| [`huanxi`](./plugins/huanxi) | 7 | 寰汐企业管理系统个人端——日报、负责人日报、任务、议题、会议、组织检索 | 全员 | ✅ | ✅ | ✅ |
| [`huanxi-admin`](./plugins/huanxi-admin) | 4 | 寰汐管理端——汇报盘点、模块与成员配置、运维简报 | 需要后台管理员发放 `hxa_` Token 的管理岗 | ✅ | ✅ | ✅ |
| [`memcore`](./plugins/memcore) / [`memcore-codex`](./plugins/memcore-codex) / [`memcore-hermes`](./plugins/memcore-hermes) | 4 | 项目记忆体系核心引擎——跨会话记忆的同步/增量更新/健康校验 | 用 Claude Code / Codex / Hermes 做长期项目的开发者 | ✅ | ✅ | ✅ |
| [`obsidian`](./plugins/obsidian) | 10 | Obsidian 知识库全套协作工作流——vault 管理、搜索图谱、Bases、Canvas、每日笔记等 | 用 Obsidian 做知识管理的人 | ✅ | ✅ | ✅ |
| [`zentao`](./plugins/zentao) | 8 | 禅道项目管理——项目集/产品/项目/执行、需求(story/epic/requirement)、Bug、任务、测试、计划与发布、反馈工单 | 用禅道管项目/需求/Bug/任务的人 | ✅ | ✅ | ✅ |
### huanxi / huanxi-admin
寰汐是蚁熊内部的项目管理与团队协同系统。`huanxi` 以你本人的身份操作,权限与网页端一致;`huanxi-admin` 是全量管理视角,高危操作(账号启停、提权、删除)不在这个端点里,普通员工不需要装。
**配置步骤:**
1. 去寰汐「个人中心 → MCP Token 管理」自助生成一个 `hxp_` 开头的 Token`huanxi-admin` 的 `hxa_` Token 由后台管理员单独发放,普通员工无需申请)。
2. **Claude Code**:执行 `/plugin install` 时会提示输入 Token,直接粘贴即可——存放在系统钥匙链,不会明文写入配置文件。
3. **Codex CLI / ChatGPT 桌面应用**Codex 没有等价的钥匙链机制,Token 走环境变量注入,两种运行方式的设置方法不一样:
- **命令行**:启动前 `export` 即可,建议写进 shell 启动脚本(`~/.zshrc` / `~/.bashrc`),避免每次开新终端都要重新导出:
```bash
export HUANXI_TOKEN=hxp_你的token # huanxi 个人端
export HUANXI_ADMIN_TOKEN=hxa_你的token # huanxi-admin 管理端
```
- **ChatGPT 桌面应用(图形界面启动,不经过 shell)**:`export` 对它无效,要设成系统级持久变量:
- macOS:终端里跑一次 `launchctl setenv HUANXI_TOKEN hxp_你的token``huanxi-admin` 同理换成 `HUANXI_ADMIN_TOKEN`),然后重新打开桌面应用;这个设置只在当前登录会话有效,重启电脑要重新执行,长期用建议放进登录项脚本
- Windows:「系统属性 → 环境变量」里新增用户变量 `HUANXI_TOKEN` / `HUANXI_ADMIN_TOKEN`,保存后重新打开应用
4. **Hermes Agent**:装完插件包(只含技能,不含 MCP 声明)后,在 `~/.hermes/config.yaml` 里手动加一段,`${VAR}` 会在连接时从环境变量解析,不会明文写死在文件里:
```yaml
mcp_servers:
huanxi:
url: "https://huanxi.office.yixiong-tech.com/mcp/"
headers:
Authorization: "Bearer ${HUANXI_TOKEN}"
huanxi-admin: # 只有装了 huanxi-admin 才需要这段
url: "https://huanxi.office.yixiong-tech.com/admin-mcp/"
headers:
Authorization: "Bearer ${HUANXI_ADMIN_TOKEN}"
```
再设置环境变量(Hermes 是本地长驻进程,跟终端应用同源,`export` 写法同 Codex CLI 那节):`export HUANXI_TOKEN=hxp_你的token`。
### memcore
给 AI 编程助手加一套跨会话持久记忆的引擎:`memory-sync` 做全量同步、`memory-update` 做增量写入、`memory-lint` 做健康校验(孤儿引用、断链、内容矛盾、过期检测)。不依赖 MCP,纯技能实现,**无需任何配置,安装即用**。
Claude Code 版([`plugins/memcore`](./plugins/memcore))以 `.claude/memory/` 为唯一权威,`memory-sync` 会额外和 `~/.claude/projects/*/memory/` 做远程镜像同步,支持多机协作。Codex 版([`plugins/memcore-codex`](./plugins/memcore-codex))架构不同:会话入口是 `AGENTS.md` 而非 `CLAUDE.md`,记忆目录优先复用已有的 `.claude/memory/`、否则落在 `.codex/memory/`,且**不做远程同步**——Codex 没有等价的跨机器 auto memory 层,记忆只落在当前仓库内。Hermes 版([`plugins/memcore-hermes`](./plugins/memcore-hermes))会话入口同样是 `AGENTS.md`,记忆目录复用优先级是 `.claude/memory/` → `.codex/memory/` → 都没有则新建 `.agents/memory/`(目录名不绑定单一工具,方便未来第三个工具接入);Hermes 自己有一套按 profile 隔离的全局记忆(`~/.hermes/memories/MEMORY.md`/`USER.md`),跟项目级记忆是两回事,memcore-hermes 会在同步时提醒这个边界,避免同一份项目事实两处漂移。三个版本共享同一套 `SYNTHESIS_THRESHOLD`、过期检测速度分档等常量设计,但各自独立维护。
### obsidian
检测到项目里有 `.obsidian/` 目录会自动激活,覆盖 vault 管理、全文与图谱搜索、frontmatter、任务、每日笔记、Bases 数据库、Canvas 视觉层、版本历史、插件配置、PKM 编排十个技能,对标社区里比较成熟的 Obsidian 技能实现后做了扩展。**无需任何配置**Claude Code、Codex CLI、Hermes Agent 共用同一份技能内容。
### zentao
禅道是蚁熊内部的项目/需求/Bug/任务管理系统。插件覆盖项目集(program)/产品/项目/执行的层级管理、需求条线(story 用户故事 / epic 业务需求 / requirement 用户需求三种类型及其状态机)、Bug 全流程、任务状态机、测试用例与测试单、产品计划/版本/发布、反馈与工单、附件改名,共 8 个工作流技能。
**配置步骤:**
1. 登录禅道,头像下拉菜单点「获取凭证」:
<img src="./docs/images/zentao-token/01-menu.png" width="240" alt="头像下拉菜单 → 获取凭证" />
2. 点击「生成凭证」——注意提示:生成新凭证会让旧凭证立即失效,且明文只在生成后展示一次,务必当场保存;有效期 14 天,到期需重新获取:
<img src="./docs/images/zentao-token/02-generate.png" width="480" alt="生成凭证确认弹窗" />
3. 弹窗会给出「API 地址」和「Token」两项,Claude Code / Codex 安装时都只需要 Token(API 地址已经写死在插件的 MCP 配置里,不用手动填):
<img src="./docs/images/zentao-token/03-token.png" width="480" alt="API 地址与 Token 展示" />
4. **Claude Code**:执行 `/plugin install` 时会提示输入 Token,直接粘贴即可——存放在系统钥匙链,不会明文写入配置文件。
5. **Codex CLI / ChatGPT 桌面应用**:Token 走环境变量注入,设置方式同 `huanxi`
- **命令行**`export ZENTAO_TOKEN=你的token`,建议写进 `~/.zshrc` / `~/.bashrc`
- **ChatGPT 桌面应用**macOS 用 `launchctl setenv ZENTAO_TOKEN 你的token`,Windows 走「系统属性 → 环境变量」新增用户变量 `ZENTAO_TOKEN`,设置后需重新打开应用
6. **Hermes Agent**:装完插件包后在 `~/.hermes/config.yaml` 里加一段(注意 zentao-mcp 网桥认的 header 字段是 `token`,不是标准 `Authorization: Bearer`):
```yaml
mcp_servers:
zentao:
url: "https://pm.ops.yixiong-tech.com/mcp"
headers:
token: "${ZENTAO_TOKEN}"
```
再 `export ZENTAO_TOKEN=你的token`。
## 开发
给这个市场新增插件、技能实现规范、`marketplace.json`/`plugin.json` 格式说明,见 [CLAUDE.md](./CLAUDE.md)。
Codex 插件的 `.codex-plugin/plugin.json` 有几个硬性约束(用本机 `plugin-creator` 技能自带的 `validate_plugin.py` 校验):`skills` 字段必须精确指向 `./skills`、`mcpServers` 字符串路径必须精确指向 `./.mcp.json`(都在插件根目录,不能嵌套在 `.codex-plugin/` 里),且顶层 `interface` 块(`displayName`/`shortDescription`/`longDescription`/`developerName`/`category`/`capabilities`/`defaultPrompt`)是必填项。
Hermes 插件走开放标准 [Agent Plugins v1.0.0](https://agent-plugins.org/specification)`plugin.json` 是裸文件(不嵌套在点前缀目录里),必需字段只有 `$schema` + `name``name` 限定 `[a-z0-9.-]`164 字符,不能有连续 `-`/`.`),`skills/` 目录下每个直接子目录含 `SKILL.md` 即被识别为一个技能。规范本身禁止在 `mcp.json` 里内嵌密钥,所以带 Token 的插件不打包 `mcp.json`MCP 配置走 README 里各插件小节的手动指引。新增/修改 Hermes 相关内容后,同步维护 [`packs/`](./packs) 里对应的 pack manifest`ref` 手动 bump 到最新 commit SHA)。
## 更新记录
见 [CHANGELOG.md](./CHANGELOG.md)。
Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

+19
View File
@@ -0,0 +1,19 @@
name: yixiong-claude-marketplace-all
description: 一次性安装蚁熊技能市场全部五个插件(huanxi / huanxi-admin / memcore-hermes / obsidian / zentao)。想选装单个插件请用同目录下对应的单插件 pack 文件。
version: 1.0.0
plugins:
- repo: https://gitea.rk-health.com/yixiong/yixiong-claude-marketplace.git
ref: aaf43e1990aa121c95d039c862cf4441947cb0bf
subdir: plugins/huanxi
- repo: https://gitea.rk-health.com/yixiong/yixiong-claude-marketplace.git
ref: aaf43e1990aa121c95d039c862cf4441947cb0bf
subdir: plugins/huanxi-admin
- repo: https://gitea.rk-health.com/yixiong/yixiong-claude-marketplace.git
ref: aaf43e1990aa121c95d039c862cf4441947cb0bf
subdir: plugins/memcore-hermes
- repo: https://gitea.rk-health.com/yixiong/yixiong-claude-marketplace.git
ref: aaf43e1990aa121c95d039c862cf4441947cb0bf
subdir: plugins/obsidian
- repo: https://gitea.rk-health.com/yixiong/yixiong-claude-marketplace.git
ref: aaf43e1990aa121c95d039c862cf4441947cb0bf
subdir: plugins/zentao
+7
View File
@@ -0,0 +1,7 @@
name: huanxi-admin
description: 寰汐企业管理系统 · 管理端(4 技能),需管理员发放 hxa_ Token。装完后需在 ~/.hermes/config.yaml 里手动配置 MCP Token,见仓库 README「Hermes Agent」一节。
version: 1.0.0
plugins:
- repo: https://gitea.rk-health.com/yixiong/yixiong-claude-marketplace.git
ref: aaf43e1990aa121c95d039c862cf4441947cb0bf
subdir: plugins/huanxi-admin
+7
View File
@@ -0,0 +1,7 @@
name: huanxi
description: 寰汐企业管理系统 · 个人端(7 技能)。装完后需在 ~/.hermes/config.yaml 里手动配置 MCP Token,见仓库 README「Hermes Agent」一节。
version: 1.0.0
plugins:
- repo: https://gitea.rk-health.com/yixiong/yixiong-claude-marketplace.git
ref: aaf43e1990aa121c95d039c862cf4441947cb0bf
subdir: plugins/huanxi
+7
View File
@@ -0,0 +1,7 @@
name: memcore-hermes
description: 项目本地记忆体系核心引擎(memcore-shared/memory-sync/memory-lint/memory-update)。无需任何配置,安装即用。
version: 1.0.0
plugins:
- repo: https://gitea.rk-health.com/yixiong/yixiong-claude-marketplace.git
ref: aaf43e1990aa121c95d039c862cf4441947cb0bf
subdir: plugins/memcore-hermes
+7
View File
@@ -0,0 +1,7 @@
name: obsidian
description: Obsidian 知识库 AI 协作插件族(10 技能)。无 MCP,无需任何配置,安装即用。
version: 1.0.0
plugins:
- repo: https://gitea.rk-health.com/yixiong/yixiong-claude-marketplace.git
ref: aaf43e1990aa121c95d039c862cf4441947cb0bf
subdir: plugins/obsidian
+7
View File
@@ -0,0 +1,7 @@
name: zentao
description: 禅道项目管理系统(8 技能)。装完后需在 ~/.hermes/config.yaml 里手动配置 MCP Token,见仓库 README「Hermes Agent」一节。
version: 1.0.0
plugins:
- repo: https://gitea.rk-health.com/yixiong/yixiong-claude-marketplace.git
ref: aaf43e1990aa121c95d039c862cf4441947cb0bf
subdir: plugins/zentao
@@ -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,19 @@
{
"name": "huanxi-admin",
"version": "1.0.0",
"description": "寰汐企业管理系统 · 管理端插件,全量视角,含汇报盘点、模块与成员配置、运维简报三个工作流技能。需要管理员发放的 hxa_ Token,高危操作(账号启停/提权/删除)不在此端点。",
"author": {
"name": "姜顺志"
},
"skills": "./skills",
"mcpServers": "./.mcp.json",
"interface": {
"displayName": "寰汐 · 管理端",
"shortDescription": "寰汐管理端汇报/模块/运维工作流",
"longDescription": "寰汐企业管理系统管理端插件,全量管理视角,跳过模块角色过滤。覆盖汇报盘点、模块与成员配置、运维简报三个工作流技能。需要后台管理员在「系统 → Admin Token」生成 hxa_ 开头的 Token 并配置为环境变量 HUANXI_ADMIN_TOKEN;普通员工无需安装本插件。账号启停、提权、删除等高危操作不在本端点,需去网页后台操作。",
"developerName": "蚁熊团队",
"category": "Productivity",
"capabilities": ["Interactive", "Write"],
"defaultPrompt": "帮我看一下本周的汇报盘点情况"
}
}
+9
View File
@@ -0,0 +1,9 @@
{
"mcpServers": {
"huanxi-admin": {
"type": "http",
"url": "https://huanxi.office.yixiong-tech.com/admin-mcp/",
"bearer_token_env_var": "HUANXI_ADMIN_TOKEN"
}
}
}
+11
View File
@@ -0,0 +1,11 @@
{
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
"name": "huanxi-admin",
"version": "1.0.0",
"description": "寰汐企业管理系统 · 管理端。全量视角,含汇报盘点、模块与成员配置、运维简报三个工作流技能。需要管理员发放的 hxa_ Token,高危操作(账号启停/提权/删除)不在此端点。MCP Token 需手动配置,详见仓库 README。",
"author": {
"name": "姜顺志"
},
"license": "MIT",
"keywords": ["huanxi", "productivity", "project-management", "admin"]
}
@@ -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,97 @@
---
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`)已随 M16 身份体系替换下线——公司改用蚁熊通行证,
> 它不提供部门信息。
`user_query` 比个人端多两个维度:`status`active 在职 / observation 交接观察期 /
inactive 已停用)与 `has_backend_permission`。用于盘点「谁在观察期」「谁有后台权限」。
**只读**——账号启停与权限授予见上文。
---
## 缓存
缓存根 `~/.claude/huanxi-cache/`,管理端用 `admin/` 子目录,与个人端隔离——
两边看到的模块范围不同,混用会把不该展示的内容展示出去。
| 类别 | 策略 |
|---|---|
| 身份 `admin/me.json` | 永久 |
| 配置字典 `dict/*.json` | **`dict_version` 比对** + 24h 兜底 |
| 人员与模块 `admin/all-modules.json` | 24h |
| 工作日 `dict/workdays.json` | 按日期 key 永久 |
| **业务数据**(汇报/任务/会议/议题) | **一律不缓存** |
字典为什么不能只靠 TTL:状态选项可能被停用,拿过期 ID 去写会**直接报错**——
失败方向是「操作失败」而非「看到旧数据」,值得比对一次。`dict_get` 的返回自带
`versions` 字段,连内容一起存即可,不要分两次调。
---
## 全局约定
1. **有副作用的写操作先确认**`module_set_members`(替换语义,会移除名单外的人)、
`module_update` 切「已取消」(级联取消该模块全部未完成任务并通知成员)。
2. **盘点类查询直接给结论**:用户问「谁没交」,答案是名单,不是让他自己看原始数据。
3. **先解析 ID 再操作**,不要凭名字猜。
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "huanxi",
"description": "寰汐企业管理系统 Claude Code 插件。集成日报、负责人日报、周报、任务管理、组织查询六大工作流技能,并自动配置寰汐 MCP Server 连接(Bearer Token 直连模式)。",
"description": "寰汐企业管理系统 · 个人端。以你本人的身份操作,权限与网页端一致。含日报、负责人日报、任务、议题、会议、组织检索六个工作流技能,并自动配置 MCP 连接。",
"author": {
"name": "姜顺志"
},
@@ -8,7 +8,7 @@
"token": {
"type": "string",
"title": "寰汐 Personal Token",
"description": "在寰汐系统后台「设置 → Personal Token」生成,hxp_ 前缀",
"description": "在寰汐「个人中心 → MCP Token 管理」自助生成,hxp_ 前缀",
"sensitive": true
}
},
+19
View File
@@ -0,0 +1,19 @@
{
"name": "huanxi",
"version": "1.0.0",
"description": "寰汐企业管理系统 · 个人端插件,含日报、负责人日报、任务、议题、会议、组织检索七个工作流技能,自动配置个人端 MCP 连接。",
"author": {
"name": "姜顺志"
},
"skills": "./skills",
"mcpServers": "./.mcp.json",
"interface": {
"displayName": "寰汐 · 个人端",
"shortDescription": "寰汐日报/任务/议题/会议工作流",
"longDescription": "寰汐企业管理系统个人端插件:以你本人身份操作,权限与网页端一致。覆盖日报、负责人日报、任务管理、议题跟踪、会议纪要、组织检索七个工作流技能。安装后需在寰汐「个人中心 → MCP Token 管理」自助生成 hxp_ 开头的 Token,并配置为环境变量 HUANXI_TOKEN。",
"developerName": "蚁熊团队",
"category": "Productivity",
"capabilities": ["Interactive", "Write"],
"defaultPrompt": "帮我看看今天有哪些任务和待办"
}
}
+9
View File
@@ -0,0 +1,9 @@
{
"mcpServers": {
"huanxi": {
"type": "http",
"url": "https://huanxi.office.yixiong-tech.com/mcp/",
"bearer_token_env_var": "HUANXI_TOKEN"
}
}
}
+11
View File
@@ -0,0 +1,11 @@
{
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
"name": "huanxi",
"version": "1.0.0",
"description": "寰汐企业管理系统 · 个人端。以你本人的身份操作,权限与网页端一致。含日报、负责人日报、任务、议题、会议、组织检索六个工作流技能。MCP Token 需手动配置,详见仓库 README。",
"author": {
"name": "姜顺志"
},
"license": "MIT",
"keywords": ["huanxi", "productivity", "project-management"]
}
@@ -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`
+32 -70
View File
@@ -1,101 +1,63 @@
---
name: huanxi-leader
description: "寰汐负责人日报工作流:查看下属汇报情况(+check)、AI 生成并保存草稿(+draft)、提交负责人日报(+submit)、撤回(+withdraw)。当用户说"查看下属汇报"、"写负责人日报"、"汇总下属情况"、"负责人日报"时触发。"
description: "寰汐负责人日报:查看下属汇报情况、起草模块汇总、批量提交。当用户说「写负责人日报」「模块汇总」「我下属今天报了什么」「谁还没交」时使用。"
---
# 寰汐负责人日报
**前置条件:先 Read `../huanxi-shared/SKILL.md`(缓存规则 + TTL 策略)**
**前置:先读 `huanxi-shared`。**
> ⚠️ **工具调用规范**:执行任何 `mcp__huanxi__*` 调用前,以工具实际注册的参数名和类型为准,本文档示例仅供工作流引导(见 shared 全局约定第 6 条)。
与员工日报是两件事:员工日报是「我做了什么」的条目列表,负责人日报是「我这个模块
整体怎么样」的一段整体内容,**结构不同、接口不同,不要混用**。
---
## 标准工作流(完整流程
## 标准流程
```
Step 0: 确认身份和负责的模块
→ Read ~/.claude/huanxi-cache/me.json(永久缓存)
→ Read ~/.claude/huanxi-cache/modules.json24h 缓存
→ 筛选 my_role == 'leader' 的模块
→ 若有多个 leader 模块,询问用户选择哪个(或所有)
Step 1 leader_report_get(date?, module_ids?)
↓ 一次拿全每个模块的:进度、我这条汇总的现状、**未提交成员名单**、
以及成员们当天各自报了什么(member_reports
↓ 起草素材全在这里,不需要再调别的工具取
Step 1: 获取并展示下属汇报汇总
→ 单模块:mcp__huanxi__leader_report_get_subordinates(date=今日, module_id)
→ 多模块:mcp__huanxi__leader_report_get_batch(date=今日, module_ids=[...])
再按模块逐一展示
→ 展示结构化汇总:
✅ 已提交(N人):[姓名] + 汇报内容摘要
⏳ 未提交(M人):[姓名]
→ 若有未提交成员:告知用户(供参考,不强制等待)
Step 2 基于 member_reports 归纳,为每个模块起草一段汇总
↓ 归纳而非罗列——把「三个人各自做了什么」写成「这个模块本周推进到哪」
↓ 有 pending_members 时提醒用户:这几位还没交,汇总可能不完整
Step 2: 询问是否 AI 汇总
→ 展示已提交成员的汇报内容后,询问:
"是否需要 AI 根据以上下属汇报自动生成今日负责人日报?"
→ 用户同意 → mcp__huanxi__llm_generate_leader_summary(module_id, date=今日)
→ 展示 AI 生成的汇总报告,供用户审阅和修改
→ 用户拒绝 → 引导用户手动填写报告内容
Step 3 leader_report_save(entries=[{module_id, content}, ...])
Step 3: 保存草稿
→ 详见 references/leader-summary.md
→ mcp__huanxi__leader_report_save(report_date, content=<确认后内容>, module_id)
Step 4 ⏸ 展示全部草稿,等待用户明确确认
Step 4: 确认并提交
→ 展示最终内容,等待用户明确确认("确认"/"提交"/"好的"等
→ ⚠️ 未收到确认前,禁止调用 leader_report_submit
→ mcp__huanxi__leader_report_submit(report_date, module_id)
Step 5 leader_report_submit(module_ids=[...])
↓ 不传 module_ids 则提交我负责的全部(自动跳过已提交与内容为空的
```
---
## Shortcuts
## 「谁还没交」
| 指令 | 说明 |
|------|------|
| `+check` | 查看指定日期下属提交情况 |
| [`+draft`](references/leader-summary.md) | AI 生成草稿并保存(需用户确认内容) |
| `+submit` | 提交负责人日报(必须先确认) |
| `+withdraw` | 撤回已提交负责人日报 |
这是最高频的单点问题,`leader_report_get``pending_members` 直接回答,
不需要遍历成员逐个查。
想看全公司范围而不只是我负责的模块,那是管理端的 `report_pending`(见
`huanxi-admin`),个人端拿不到。
---
## +check:查看下属汇报
## 撤回
```
1. 确定模块(从 modules.json 缓存中取 leader 身份的模块)
2. mcp__huanxi__leader_report_get_subordinates(date, module_id)
3. 展示:
✅ 已提交(N人):张三、李四、...
⏳ 未提交(M人):王五、...
(非工作日时:提示"今日非工作日,成员无需强制提交")
leader_report_withdraw(module_ids=[...]) → 变回草稿,仅当天可撤
```
---
## +withdraw:撤回负责人日报
## 几条容易踩的
```
1. 确认当前已提交状态
2. 告知撤回影响,等待用户确认
3. mcp__huanxi__leader_report_withdraw(report_date, module_id)
```
---
## 多模块处理
若用户有多个 leader 模块:
```
- 默认展示全部模块的下属情况(+check)
- 提交时需逐模块操作:每个模块单独调用 leader_report_save + submit
- 可用 leader_report_get_batch(date, module_ids) 批量拉取数据
```
---
## 关键约束
- **禁止自动提交**`leader_report_submit(report_date, module_id)` 前必须展示内容并等待用户确认
- **成员未提交不阻塞**:负责人日报不依赖所有成员提交,可随时填写
- 若当前用户不是任何模块的 leader,告知用户并建议使用 `/huanxi-report` 填写员工日报
- **一个模块一条**`module_id` 是主键的一部分,同一模块当天只有一条汇总,
重复保存是覆盖不是新增。
- **内容为空不能提交**:批量提交会静默跳过空内容的模块并在返回里说明,
不要以为「提交成功」就等于每个模块都交了——看返回的 `skipped_empty_count`
- **不要前置校验下属是否交齐**:负责人日报不依赖员工日报的提交状态,
下属没交也能交自己的汇总(这是有意设计,避免一个人拖住整条链)。
- 只有 `leader` 角色的模块才会出现在这里;`reviewer` 不写负责人日报。
@@ -1,85 +0,0 @@
# 负责人日报草稿(+draft
> ⚠️ 参数细节以 MCP `leader_report_save` / `llm_generate_leader_summary` 的 docstring 为准,本文档仅做工作流引导。
## 两种草稿模式
### 模式 AAI 自动生成
```
1. mcp__huanxi__llm_generate_leader_summary(module_id=<模块ID>, date=<日期>)
2. 展示 AI 生成的草稿内容给用户审阅
3. 询问用户:"是否采用此草稿?或需要修改?"
4. 用户确认/修改完成后 → 执行保存步骤
```
### 模式 B:用户手动撰写
```
1. 展示下属汇报摘要(来自 leader_report_get_subordinates 结果)
2. 基于摘要,引导用户填写:
- 本模块今日整体进展
- 遇到的问题与风险
- 明日计划
3. 拼合用户输入内容 → 执行保存步骤
```
---
## 保存草稿
```
mcp__huanxi__leader_report_save(
report_date = "YYYY-MM-DD", ← 日期格式
scope_type = "module", ← 默认 "module";组织维度填 "org"
module_id = "<模块ID>", ← scope_type="module" 时必填,从 modules.json 缓存取
# org_id = "<组织ID>", ← scope_type="org" 时必填,与 module_id 互斥
content = "<正文内容>", ← 支持 Markdown,三段式(今日进展/问题与风险/明日重点)
# progress_corrections = [ ← 可选:手动修正模块进度
# { "module_id": "<id>", "new_progress": 75 }
# ]
)
```
**返回值**:保存成功后返回草稿 ID,告知用户已保存,询问是否立即提交。
**注意**
- 同一用户同一日期同一 scope 只有一条记录(重复调用是更新)
- 默认走 module 维度;只有组织负责人需要 org 维度时才传 `scope_type="org"` + `org_id`
---
## 多模块批量操作
若用户负责多个模块:
```
1. mcp__huanxi__leader_report_get_batch(date, module_ids=[...])
→ 一次获取所有模块的下属汇报情况
2. 逐模块调用 llm_generate_leader_summary 生成草稿
3. 逐模块调用 leader_report_save 保存
4. 统一确认后逐模块提交
```
---
## 内容格式建议(供 AI 生成参考)
```markdown
## 今日进展
- [任务A] 完成 XX 功能开发,进度 80%
- [任务B] 完成接口联调,已提测
## 问题与风险
- 暂无阻塞性问题
## 明日计划
- 继续推进 [任务C]
- 协助 [成员] 解决 XX 问题
```
@@ -0,0 +1,86 @@
---
name: huanxi-lookup
description: "寰汐人员与检索:查人、全局搜索、按标签反查、团队任务看板。当用户说「XX是谁」「搜一下」「有哪些人」「团队在忙什么」时使用。"
---
# 寰汐人员与检索
**前置:先读 `huanxi-shared`。**
本技能主要有两个职责:**把名字解析成 ID** 供其他技能使用,以及**维护缓存**。
---
## 解析 ID
几乎所有写操作都要 ID。顺序是:先读缓存,未命中再调工具,拿到后写回缓存。
```
user_search(q="冯普") 姓名模糊搜 → 拿 id
user_search(ids=[...]) 已知 id 批量取详情
module_query(role?) 我参与的模块(带 my_role)
```
> 组织架构树(`org_tree`)已随 M16 身份体系替换下线——公司改用蚁熊通行证,
> 它不提供部门信息。要按「一组人」找人,用 `user_search` 按姓名搜,
> 或到网页后台看用户标签。
`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 |
用户说「刷新一下」「组织变了」时,删掉对应文件重新拉取即可。
@@ -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` 要传**完整**的条目顺序列表,不是只传要移动的那几个。
-137
View File
@@ -1,137 +0,0 @@
---
name: huanxi-org
description: "寰汐组织/模块/人员查询。当用户说"我有哪些模块"、"查一下某人账号/ID"、"刷新一下缓存"、"看组织架构"、"谁在哪个模块"、"帮我找一下XXX的用户ID"时触发。提供名字→ID 解析(+resolve)、缓存刷新(+sync)、当前用户(+me)、模块列表(+modules)、组织树(+tree)。"
---
# 寰汐组织与人员查询
**前置条件:先 Read `../huanxi-shared/SKILL.md`(缓存规则 + TTL 策略)**
> ⚠️ **工具调用规范**:执行任何 `mcp__huanxi__*` 调用前,以工具实际注册的参数名和类型为准,本文档示例仅供工作流引导(见 shared 全局约定第 6 条)。
---
## 核心能力
本技能提供「名字 → ID」解析能力,是所有其他 huanxi-* 技能的依赖。所有操作**缓存优先**。
---
## Shortcuts
| 指令 | 说明 |
|------|------|
| [`+me`](references/resolve-ids.md#me) | 查看当前用户身份(读 me.json,缓存永久) |
| [`+modules`](references/resolve-ids.md#modules) | 列出我参与的所有模块(24h 缓存) |
| [`+resolve`](references/resolve-ids.md) | 把模块名/人员名解析为 ID |
| [`+tree`](#org-tree) | 展示完整组织架构树(实时查询,不缓存) |
| [`+sync`](#sync) | 强制刷新 modules.json + users.json 缓存 |
---
## +me:查看当前用户身份 {#me}
```
Step 1: Read ~/.claude/huanxi-cache/me.json
→ 若存在且有 data 字段:直接展示(永久缓存,无需检查 TTL)
→ 若不存在:执行 Step 2
Step 2: mcp__huanxi__user_get_me()
Step 3: Write ~/.claude/huanxi-cache/me.json:
{ "cached_at": "<ISO8601>", "data": <返回值> }
Step 4: 展示用户信息(name, feishu_user_id, 角色等)
```
---
## +modules:列出参与模块 {#modules}
```
Step 1: Read ~/.claude/huanxi-cache/modules.json → 检查 TTL24h
→ 未过期:直接展示
→ 过期或不存在:执行 Step 2
Step 2: mcp__huanxi__module_list()
Step 3: Write ~/.claude/huanxi-cache/modules.json:
{ "cached_at": "<ISO8601>", "data": <返回值> }
Step 4: 展示模块列表(id, name, my_role
```
---
## +resolve:名字 → ID 解析
详细流程见 [references/resolve-ids.md](references/resolve-ids.md)。
**快速规则:**
- 模块名 → 先查 `modules.json`,未命中则拉 `module_list()`
- 人员名 → 先查 `users.json`,未命中则调 `user_list(name=xxx)`,结果追加写入缓存
- 模糊匹配时若有多个结果,列出候选项让用户选择
---
## +tree:组织架构树 {#org-tree}
```
Step 1: mcp__huanxi__org_get_tree()(不缓存,实时查询)
Step 2: 以树形结构展示组织架构
```
> 组织架构变动相对频繁(人员入离职),不缓存,每次实时查询。
---
## +sync:强制刷新缓存 {#sync}
```
Step 1: mcp__huanxi__module_list()
→ Write ~/.claude/huanxi-cache/modules.json(强制覆盖)
Step 2: mcp__huanxi__user_list()(拉全量用户)
→ Write ~/.claude/huanxi-cache/users.json(强制覆盖)
Step 3: 告知用户:缓存已刷新(模块 N 个,用户 M 人)
```
> **何时需要 +sync**:添加新模块成员后、有新员工入职后、模块结构调整后。
>
> ⚠️ **Token 变更时**:若切换了寰汐账号(修改了 MCP Bearer Token),`me.json` 是永久缓存,+sync 不会更新它。需手动删除 `~/.claude/huanxi-cache/me.json`,再执行 `/huanxi-org +me` 重新获取新身份。
---
## 缓存文件结构参考
**me.json**
```json
{
"cached_at": "2026-04-13T09:00:00+08:00",
"data": {
"id": "123",
"name": "张三",
"feishu_user_id": "ou_xxx"
}
}
```
> ⚠️ 用户身份的系统内部 ID 字段名是 `id`(与后端 `user_get_me` / `user_list` 返回结构一致),不是 `user_id`。
**modules.json**
```json
{
"cached_at": "2026-04-13T09:00:00+08:00",
"data": [
{ "id": "mod_001", "name": "前端开发", "my_role": "member" },
{ "id": "mod_002", "name": "后端API", "my_role": "leader" }
]
}
```
**users.json**
```json
{
"cached_at": "2026-04-13T09:00:00+08:00",
"data": [
{ "id": "456", "name": "李四", "feishu_user_id": "ou_yyy" }
]
}
```
@@ -1,81 +0,0 @@
# 名字 → ID 解析
> ⚠️ 参数细节以 MCP `module_list` / `user_list` / `user_get_me` 的 docstring 为准,本文档仅做工作流引导。
本文件详细说明如何将模块名、人员名解析为系统 ID,所有步骤均**缓存优先**。
**字段名约定**:用户/模块的系统内部 ID 字段名统一为 `id`(与后端返回结构一致),不要写成 `user_id`/`module_id` 作为 JSON 字段名。`module_id`/`user_id` 仅在传入 MCP 工具参数时使用。
---
## 模块名 → 模块 ID {#modules}
```
1. Read ~/.claude/huanxi-cache/modules.json
→ 检查 cached_at,若 age < 24h → 进入匹配逻辑
→ 过期或不存在 → 调用 mcp__huanxi__module_list() 并写入缓存
2. 匹配逻辑:
a. 精确匹配 name == 输入 → 返回 id
b. 精确匹配失败 → 模糊匹配(name.includes(输入) 或 输入.includes(name)
c. 模糊匹配唯一命中 → 确认并返回 id
d. 多个候选 → 列出候选项,让用户选择
e. 零命中 → 告知用户,建议运行 +sync 刷新缓存
```
**示例:**
- 用户说"前端模块" → 从缓存匹配到 `{ id: "mod_001", name: "前端开发" }` → 返回 `mod_001`
- 用户说"API" → 匹配到 `后端API` → 返回 `mod_002`
- 匹配到多个 → 展示候选列表
---
## 人员名 → 用户 ID {#users}
```
1. Read ~/.claude/huanxi-cache/users.json
→ 检查 cached_at,若 age < 24h → 在 data 数组中查找
2. 查找逻辑:
a. name 精确匹配 → 返回 user.id
b. name 包含输入 → 列出候选
c. 未找到 → 执行 Step 3
3. 缓存未命中时:
a. 调用 mcp__huanxi__user_list(name=<输入>)
b. 将结果追加(合并去重)写入 users.json(不覆盖已有缓存)
c. 重新执行 Step 2 匹配逻辑
4. 仍未找到 → 告知用户姓名不存在,建议确认拼写或运行 +sync
```
**特别注意:**
- 用户的系统内部 ID 字段名是 `id`(后端 `user_list` 返回结构),`≠ feishu_user_id`
- `feishu_user_id` 是飞书通讻录的 user_id`on_` 前缀),`feishu_open_id` 是飞书 open_id`ou_` 前缀);两者是**不同字段**,不要混用
- 设置任务执行人时,MCP 工具的参数名叫 `assignee_ids`,传入的值是 user.id(系统内部 UUID 列表)
- 飞书消息通知由 MCP 服务端内部处理,调用工具时只需传系统内部 user.id 即可
---
## 自动 ID 解析流程(综合示例)
当用户说"创建任务,负责人是李四,模块是前端开发"时:
```
1. 解析模块 → read modules.json → 匹配"前端开发" → mod_001
2. 解析人员 → read users.json → 匹配"李四" → id: 456
3. 若任一缓存未命中:先拉 MCP,写缓存,再继续
4. 两个 ID 都拿到后 → 调用 task_create(module_id="mod_001", ...)
5. 创建完成后 → task_set_assignees(task_id, ["456"])
```
---
## 常见错误处理
| 情况 | 处理 |
|------|------|
| 多个同名用户 | 展示完整名单(含部门/角色),让用户指定 |
| 模块名拼写不完整 | 模糊匹配,确认后继续 |
| 缓存文件损坏(JSON 解析失败)| 忽略缓存,直接调 MCP,重建文件 |
| MCP 返回空列表 | 告知用户,建议检查 Token 权限或联系管理员 |
+56 -84
View File
@@ -1,106 +1,78 @@
---
name: huanxi-report
description: "寰汐员工日报工作流:查看今日日报状态(+check)、保存草稿(+draft)、提交日报(+submit)、撤回日报(+withdraw。当用户说"帮我写日报"、"填日报"、"提交日报"、"查看今日汇报情况"时触发。"
description: "寰汐员工日报:查看今日状态、填写并提交日报、撤回修改。当用户说帮我写日报」「填日报」「提交日报」「今天要报什么」时使用。"
---
# 寰汐员工日报
**前置条件:先 Read `../huanxi-shared/SKILL.md`(缓存规则 + TTL 策略)**
> ⚠️ **工具调用规范**:执行任何 `mcp__huanxi__*` 调用前,以工具实际注册的参数名和类型为准,本文档示例仅供工作流引导(见 shared 全局约定第 6 条)。
**前置:先读 `huanxi-shared`(缓存策略、状态模型、确认约定)。**
---
## 标准工作流(完整流程
## 标准流程
```
Step 0: 确认身份
→ Read ~/.claude/huanxi-cache/me.json(永久缓存)
→ 若 me.json 为空:mcp__huanxi__user_get_me() → 写入缓存
Step 1 report_get_context(date?)
↓ 一次拿全:是否工作日、是否免报、整体状态、按模块分组的待汇报条目
↓ 非工作日 → 告知并询问是否仍要填(不中断)
↓ 整体状态已是 submitted → 转「修改已提交内容」分支
↓ (submitted 只代表提交过至少一条,不代表当天候选任务都处理完了——
↓ draft_count 可能仍大于 0,展示时提醒用户还有几条没写)
↓ 免报日 → 告知无需提交,询问是否仍要记录
Step 1: 检查是否工作日
→ 查 workdays.json["今日日期"]
→ 未缓存:mcp__huanxi__system_get_workday() → 追加写入 workdays.json
→ 非工作日:告知用户,询问"是否仍要填写?"(不强制中断)
Step 2 展示待汇报任务,引导用户逐条说今天做了什么
↓ 每条记住 task_id(后续提交要用)
↓ 用户说不清的任务,可用 task_get 补上下文,不要替他编
Step 2: 查看今日日报状态
→ mcp__huanxi__report_get_today()
→ submitted → 告知"今日已提交",询问是否撤回
→ draft/empty → 继续 Step 3
Step 3 (可选)润色
↓ 你自己润色即可,**不要找工具**——你就是那个语言模型
↓ 展示润色前后,让用户选
Step 3: 获取待汇报任务并收集内容
→ mcp__huanxi__report_get_tasks_to_report()
→ 返回的每个任务条目含:idtask_id)、title、module_id、module_name、progress 等
→ 展示待汇报任务列表(任务名、模块、当前进度)
→ 引导用户逐一填写今日进展和完成百分比
→ 详见 references/report-draft.md
Step 4 report_save_draft(items=[...])
↓ 存草稿,此时还没提交
↓ 今天不报某条 → 该项加 dismissed=true;恢复 → restore=true
Step 4: 保存草稿并展示初稿
→ mcp__huanxi__report_save_draft(items=[...])
→ ⚠️ items 字段以 MCP docstring 为准;每条必须带 module_id(取自 Step 3 任务条目)
→ 展示完整初稿内容供用户预览
Step 5 ⏸ 展示完整初稿,等待用户明确确认
Step 5: 询问是否 AI 润色
→ 询问用户:"是否需要 AI 润色优化表达?"
→ 用户同意 → mcp__huanxi__llm_polish_report(content=<初稿内容>)
→ 展示润色后版本,与初稿对比
→ 用户选择采用润色版或保留原版
→ 若采用润色版:mcp__huanxi__report_save_draft(items=[...]) 更新草稿
→ 用户拒绝 → 直接进入 Step 6
Step 6 report_submit(task_ids=[...])
↓ 只提交确认过的那些;不传 task_ids 则提交全部草稿
```
Step 6: 确认并提交
→ 展示最终内容,等待用户明确确认("确认"/"提交"/"好的"等)
→ ⚠️ 未收到确认前,禁止调用 report_submit_item
→ 用户确认后:
a. mcp__huanxi__report_get_today() → 获取各条目的 item_id
b. 对每个需提交的草稿条目 → mcp__huanxi__report_submit_item(item_id)
c. 逐条提交,不影响其他条目
→ 详见 references/report-submit.md
**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=...)
某个任务被谁在哪天报过什么
```
---
## Shortcuts
## 几条容易踩的
| 指令 | 说明 |
|------|------|
| [`+check`](#check) | 查看今日日报状态(已提交/草稿/空) |
| [`+draft`](references/report-draft.md) | 读取待报任务并保存草稿 |
| [`+submit`](references/report-submit.md) | 提交当天日报(必须先确认) |
| `+withdraw` | 撤回已提交日报(询问确认) |
---
## +check:查看今日状态 {#check}
```
1. mcp__huanxi__report_get_today()
2. 展示:
- 提交状态(submitted / draft / 未填)
- 已填任务列表及内容摘要
- 未填/dismissed 任务
3. 若已提交:询问"是否需要撤回修改?"
4. 若草稿:询问"是否继续编辑并提交?"
```
---
## +withdraw:撤回日报
```
1. mcp__huanxi__report_get_today() → 获取各条目状态和 item_id
2. 展示已提交的条目列表,询问用户要撤回哪条(可多选)
3. 等待用户确认(撤回后该条目变为草稿,其他已提交条目不受影响)
4. 对用户选择的每条 → mcp__huanxi__report_withdraw_item(item_id)
5. 告知撤回成功,可重新编辑后用 report_submit_item 重新提交
```
---
## 关键约束
- **禁止自动提交**:Step 6 必须展示内容并等待用户明确确认("确认"/"提交"/"好的"等),不得自动调用 `report_submit_item`
- **逐条操作,不做全量**:提交/撤回必须使用 `report_submit_item` / `report_withdraw_item`(需传 item_id),禁止批量操作所有条目,除非用户明确要求"全部提交/撤回"
- **dismissed 状态**:用户主动标记"今天不汇报该任务",dismiss 的条目不计入汇报,不要提示用户补填
- **非工作日**:检测到非工作日时,明确告知但不中断,询问用户意愿
- **已提交则不重复操作**:Step 2 发现已提交时,不继续 Step 3-6,改为询问是否撤回
- **条目用 `task_id` 定位**,不是条目自身的 id。`report_get_context` 返回里的
`task_id` 就是后续 save/submit/withdraw 都要传的那个。
- **空内容不能提交**:服务端会拒。要么写点内容,要么标 `dismissed`
- **模块杂记**`is_module_misc`)承载零散工作,可以报也可以不报,但它**不计入
「未提交」统计**——用户只写了杂记不算完成当天汇报,提醒他还有别的任务没写。
- **`progress_update` 是任务进度**(0-100),不是完成度描述。填了它会真的改任务进度。
- 免报日(`is_exempt`)不产生未提交统计,也不必催。
@@ -1,64 +0,0 @@
# 保存日报草稿(+draft
> ⚠️ 参数细节以 MCP `report_save_draft` 的 docstring 为准,本文档仅做工作流引导。
## 前置
已通过 `report_get_tasks_to_report()` 获取待汇报任务列表。返回的每个任务条目至少含 `id`task_id)、`title``module_name`**以及 module_id 字段**(保存草稿必需)。
---
## items 字段(与后端签名一致)
| 字段 | 必填 | 类型 | 说明 |
|------|------|------|------|
| `module_id` | ✅ **必填** | string (UUID) | 任务所属模块 ID,从 `report_get_tasks_to_report()` 返回的任务条目里取(不要从任务名推断) |
| `task_id` | 可选 | string (UUID) | 任务 ID;不传则为模块级汇报 |
| `content` | ✅ **必填** | string | 汇报内容(今日进展),支持 Markdown,可为空字符串 |
| `progress_update` | 可选 | int (0-100) | 任务进度百分比(字段名是 `progress_update`,不是 `progress` |
⚠️ **历史踩坑**:曾用错的字段名 `progress``status`,以及遗漏 `module_id`,会触发"参数缺失"错误。
---
## 执行步骤
```
Step 1: 展示待汇报任务列表,引导用户逐一填写内容
格式示例:
┌─────────────────────────────────────────
│ 任务: [前端开发] 完成登录页面 UI 优化
│ 当前进度: 60%
│ 今日进展(请输入): ___
│ 完成百分比(0-100: ___
└─────────────────────────────────────────
Step 2: 收集所有填写内容,构建 items 数组
⚠️ 每个 item 必须含 module_id(来自 Step 0 的任务条目)
Step 3: [可选] 若用户请求 AI 辅助 → mcp__huanxi__llm_polish_report(content)
将润色建议展示给用户,由用户确认采用哪个版本
Step 4: mcp__huanxi__report_save_draft(items=[
{
module_id: "<从任务条目取>",
task_id: "<从任务条目取>",
content: "今日完成 ...",
progress_update: 80
},
...
])
Step 5: 告知保存结果:
"已保存草稿,共 N 个任务条目。是否现在提交?"
```
---
## 注意事项
- `progress_update`**整数百分比**(0-100),不是小数;字段名末尾必须是 `_update`
- 用户未填写 `content` 的任务:询问是否 dismiss(今天不汇报)还是暂时跳过
- `report_save_draft` 是 upsert 操作,多次调用不会重复创建
- 草稿保存成功后,下次调用 `report_get_today()` 可看到 draft 状态
@@ -1,56 +0,0 @@
# 提交日报(+submit
> ⚠️ 参数细节以 MCP `report_submit_item` / `report_get_today` 的 docstring 为准,本文档仅做工作流引导。
## 前置条件
- 草稿已通过 `report_save_draft()` 保存
- 用户已查看并确认内容
---
## 执行步骤
```
Step 1: mcp__huanxi__report_get_today() → 获取最新草稿内容
Step 2: 展示完整草稿给用户审阅:
┌─────────────────────────────────────────
│ 📋 今日日报预览(2026-04-13
│ ✅ 完成登录页面 UI 优化(进度 80%)
│ 今日进展:完成了头部导航栏的响应式改造...
│ 🔄 接口联调(进度 50%)
│ 今日进展:与后端对接了 3 个接口...
└─────────────────────────────────────────
Step 3: 等待用户明确确认("确认"/"提交"/"好的"/"ok"等)
⚠️ 未收到确认前,禁止调用 report_submit_item
Step 4: 对每个需提交的草稿条目(item.status == "draft"):
mcp__huanxi__report_submit_item(item_id=<item.id>)
逐条提交,不影响其他条目状态
Step 5: 告知提交结果:
"✅ 日报已提交!共 N 个任务条目。"
```
---
## 提交失败处理
| 错误 | 处理方式 |
|------|---------|
| 草稿为空 | 提示用户先填写内容(+draft) |
| 已提交 | 告知已提交,询问是否撤回 |
| 网络错误 | 告知用户,建议稍后重试 |
---
## 重要约束
**禁止自动提交**:无论何种情况,`report_submit_item()` 调用前必须经过用户明确确认。
这是强制规则,不得因为"用户已经填好了"或"工作流要求"而跳过确认步骤。
**逐条提交,不做全量**:需先从 `report_get_today()` 获取各条目的 `item_id`,再逐条调用 `report_submit_item(item_id)`,不得批量提交所有条目(除非用户明确要求"全部提交")。
+112 -106
View File
@@ -1,142 +1,148 @@
---
name: huanxi-shared
description: "寰汐 MCP 共享基础:本地缓存策略(me/modules/users/workdays)、TTL 规则、缓存读写伪代码、MCP 工具索引。所有 huanxi-* 技能必须先 Read 本文件,再执行各自工作流。"
description: "寰汐 MCP 共享基础:工具命名约定、本地缓存策略与过期检查、状态两层模型、全局确认约定。所有 huanxi-* 技能必须先读本文件。"
---
# 寰汐 MCP 共享规则
本技能是所有 `huanxi-*` 技能的**必读前置**,定义缓存策略、工具索引和全局约定
所有 `huanxi-*` 技能的**必读前置**。
---
## 必读声明
## 一条最重要的约定:参数以工具自身的说明为准
**所有 huanxi-* 技能开头都必须先 `Read` 本文件(`../huanxi-shared/SKILL.md`),再执行各自工作流。**
**本文件与各技能文档都不重画参数表。** 每个工具的参数名、必填项、取值范围以它在 MCP
里注册的 docstring 为唯一真相;技能只描述**调用顺序、ID 如何传递、哪里必须停下来等用户
确认**。
> 这条不是洁癖。上一代技能包重画过参数表,结果字段名、枚举值、必填项四类漂移覆盖了
> 全部六个技能——用户侧表现为频繁的「参数缺失」报错。工具签名变了而文档没跟上,
> 是必然发生而非可能发生的事。
---
## 本地缓存机制
## 工具命名
缓存文件统一存放在 `~/.claude/huanxi-cache/`
Claude Code / Claude Desktop 里工具名带前缀:`mcp__huanxi__task_query`(个人端)、
`mcp__huanxi-admin__report_pending`(管理端)。其他平台通常是裸名 `task_query`
本文档统一写**裸名**,实际调用时按你所在平台的约定加前缀。
### 缓存文件清单
两个端点信任边界不同:
| 文件 | 内容 | TTL | 刷新方式 |
|------|------|-----|---------|
| `me.json` | 当前用户身份(id, name, feishu_user_id;注意字段名是 `id` 而不是 `user_id` | 永久 | 手动删除文件 |
| `modules.json` | 我参与的模块列表(id, name, my_role | 24h | 过期自动重拉 或 `/huanxi-org +sync` |
| `users.json` | 组织用户搜索结果(name/feishu_user_id 索引) | 24h | 过期自动重拉 或 `/huanxi-org +sync` |
| `workdays.json` | 工作日查询结果(date → bool 的 KV 字典) | 永久(按日期 key) | 已有日期不重新查 |
| | 个人端 | 管理端 |
|---|---|---|
| Token | `hxp_` 开头 | `hxa_` 开头 |
| 身份 | 你本人,权限与网页端一致 | Token 创建人的管理员身份 |
| 视角 | 我参与的 | 全量,不受角色过滤 |
### 缓存读写伪代码
---
**读缓存(每次使用 MCP 数据前执行此逻辑):**
## 状态是可配置的两层模型(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/`**按通道隔离**
```
function read_cache(file, ttl_hours):
1. Read ~/.claude/huanxi-cache/{file}.json
2. 若文件不存在 → cache_miss
3. 读取 cached_at 字段,计算 age = now - cached_at(小时
4. 若 ttl_hours = Infinity 或 age < ttl_hours → 返回 data 字段(cache_hit
5. 否则 → cache_miss
~/.claude/huanxi-cache/
├── personal/ hxp_ 视角:me.json / my-modules.json / users.json
├── admin/ hxa_ 视角:all-modules.json
└── dict/ 与身份无关的配置字典(两个通道共享
```
function cache_miss_handler(tool_name, params):
1. 调用 MCP 工具:mcp__huanxi__{tool_name}(params)
2. Write ~/.claude/huanxi-cache/{file}.json:
{ "cached_at": "<当前 ISO8601 时间>", "data": <MCP 返回值> }
隔离是必须的:管理端看到的是全量模块,个人端只有我参与的——混用会让你把不该展示的
东西展示给用户。
### 分层 TTL
| 类别 | 文件 | 策略 |
|---|---|---|
| 身份 | `personal/me.json` | 永久(身份不变) |
| **配置字典** | `dict/*.json` | **版本戳比对** + 24h 兜底 |
| 人员与模块 | `users.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 缓存):**
```
function get_workday(date):
1. Read workdays.json → 得到 { "2026-04-14": true, ... }
2. 若 date 已在 dict 中 → 直接返回
3. 否则 → 调用 mcp__huanxi__system_get_workday(date)
4. 将 {date: result} 追加写入 workdays.json
```
### TTL 快速参考
```
me.json → Infinity(永久,身份不变)
modules.json → 24h
users.json → 24h
workdays.json → Infinity(按 date key,已查过的不再查)
```
`workdays.json` 特殊:按日期 key `{ "2026-08-06": true }`,已查过的日期不再查。
---
## MCP 工具索引
## 站内消息(M12
寰汐 MCP 工具前缀:`mcp__huanxi__`
寰汐的全部系统通知(任务分配、@提及、报告发布、模块变更…)都落在站内消息中心,
`notification_query` 是它的读入口。
### 用户与认证
| 工具 | 用途 | 缓存 |
|------|------|------|
| `user_get_me()` | 获取当前 Token 代表的用户 | → `me.json`(永久)|
**什么时候主动用它**:用户问「我错过了什么」「有没有人 @ 我」「最近有什么新任务」时。
不要在每次对话开头都拉一遍——那是噪音,用户没问就别塞。
### 模块与组织
| 工具 | 用途 | 缓存 |
|------|------|------|
| `module_list(my_role?)` | 列出我参与的模块 | → `modules.json`24h|
| `module_get(module_id)` | 获取模块详情(含成员) | 不缓存 |
| `user_list(name?, department_id?, is_active?, limit?)` | 搜索组织用户 | → `users.json`24h|
| `org_get_tree()` | 获取组织架构树 | 不缓存 |
| `people_get_board(user_id?, module_id?, date?)` | 人员任务看板(不传则全员;传 user_id 只看该人) | 不缓存 |
```
notification_query(unread_only=True) # 只看未读
notification_query(scene="comment_mentioned") # 只看 @提及
```
### 任务管理
| 工具 | 用途 | 缓存 |
|------|------|------|
| `task_list_mine(status?, module_id?, priority?, snapshot_active?)` | 我认领的任务 | 不缓存 |
| `task_list_by_module(module_id)` | 模块下所有任务 | 不缓存 |
| `task_get(task_id)` | 任务详情 | 不缓存 |
| `task_create(...)` | 创建任务 | — |
| `task_update(task_id, ...)` | 更新任务 | — |
| `task_set_assignees(task_id, assignee_ids)` | 设置执行人(幂等) | — |
返回里的 `related` 给出关联实体(`{"type": "task", "id": "..."}`),可直接拿去调
对应的 `task_get` / `module_get` 看详情——**不要**把 body 里的名字拿去重新搜索。
### 员工日报
| 工具 | 用途 |
|------|------|
| `report_get_today(date?)` | 获取指定日期日报 |
| `report_get_tasks_to_report()` | 获取今日待汇报任务 |
| `report_save_draft(items=[...])` | 批量保存草稿(upsert|
| `report_submit_item(item_id, date?)` | 提交单条日报条目 |
| `report_withdraw_item(item_id, date?)` | 撤回单条已提交日报条目 |
**标记已读要用户明示**`notification_mark_read()` 不传 id 是**全部已读**
这是个不可逆的批量动作,跟提交类操作一样先确认再调。
用户说「都看过了」再全清;只是让你念一遍未读的话,不要顺手清掉。
### 负责人日报
| 工具 | 用途 |
|------|------|
| `leader_report_get_subordinates(date, module_id)` | 查看下属汇报情况 |
| `leader_report_save(report_date, content, module_id?)` | 保存负责人日报草稿 |
| `leader_report_submit(report_date, module_id)` | 提交负责人日报 |
| `leader_report_withdraw(report_date, module_id)` | 撤回负责人日报 |
| `leader_report_get_batch(date, module_ids)` | 批量获取多模块日报 |
### 周报
| 工具 | 用途 |
|------|------|
| `weekly_report_get(year, week)` | 获取指定 ISO 周的周报 |
| `weekly_report_get_batch(year, week, module_ids)` | 批量获取多模块周报 |
| `weekly_report_save(module_id, year, week_number, content?, next_week_plan?)` | 保存周报草稿 |
| `weekly_report_submit(module_id, year?, week_number?)` | 提交周报(不传 year/week_number 默认提交当周) |
| `weekly_report_withdraw(module_id, year?, week_number?)` | 撤回周报 |
### 系统与 LLM
| 工具 | 用途 | 缓存 |
|------|------|------|
| `system_get_workday(date?)` | 查询是否工作日 | → `workdays.json`(永久)|
| `llm_polish_report(content)` | AI 润色日报内容 | — |
| `llm_generate_leader_summary(module_id, date)` | AI 生成负责人日报草稿 | — |
---
> 这里标的是**站内已读**。用户在飞书点了卡片按钮不算站内已读,两者有意分开——
> 「在飞书看了但站内还是未读」与「误触就被标已读」都是要避免的别扭。
## 全局约定
1. **提交必须确认**`report_submit_item``leader_report_submit``weekly_report_submit` 执行前必须向用户展示内容并等待明确确认,禁止自动提交。
2. **非工作日不强制**:检测到非工作日时,告知用户并询问是否仍要填写,不得直接中断流程
3. **缓存优先**:执行任何需要 module_id / user_id 的操作前,先读缓存;缓存未命中或过期才调 MCP
4. **ISO 周数**:周报的 `year` 字段存 ISO year`date.isocalendar()[0]`),不是日历年。12 月底 / 1 月初注意跨年。
5. **task_set_assignees 幂等**:设置执行人使用此工具(幂等),不要用 task_update 的 assignee 字段追加
6. **工具调用以 MCP 定义为准**:调用任何 `mcp__huanxi__*` 工具前,**必须以该工具在 MCP Server 中实际注册的参数名和类型为准**,本文档及各 skill 中的调用示例仅供工作流引导,不得作为参数的唯一依据。如果示例与工具实际定义有出入,以工具定义优先。
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. **批量优先**:工具的过滤维度基本都收列表,一次查多个比循环调用快得多,也更省上下文。
+54 -66
View File
@@ -1,102 +1,90 @@
---
name: huanxi-task
description: "寰汐任务管理:创建任务(+create)、更新任务状态/进度(+update)、查看任务看板(+board)、设置执行人(+assign)。当用户说"创建任务"、"新建任务"、"更新任务"、"看任务板"、"任务分配"时触发。"
description: "寰汐任务管理:查任务、建任务、改状态进度、分配执行人、认领。当用户说「我有什么任务」「建个任务」「把这个标成完成」「派给谁」时使用。"
---
# 寰汐任务管理
**前置条件:先 Read `../huanxi-shared/SKILL.md`(缓存规则 + TTL 策略)**
> ⚠️ **工具调用规范**:执行任何 `mcp__huanxi__*` 调用前,以工具实际注册的参数名和类型为准,本文档示例仅供工作流引导(见 shared 全局约定第 6 条)。
**前置:先读 `huanxi-shared`(尤其「状态是可配置的两层模型」一节)。**
---
## Shortcuts
## ID 传递链
| 指令 | 说明 |
|------|------|
| [`+create`](references/task-create.md) | 创建新任务(引导式填写) |
| `+update` | 更新任务状态/进度/截止日 |
| [`+board`](references/task-kanban.md) | 查看我的任务看板 |
| `+assign` | 设置/变更任务执行人 |
| `+get` | 查看单个任务详情 |
任务操作几乎都是这条链,**中间结果要展示给用户**,不要一路闷头做到底:
---
## +create:创建任务
详见 [references/task-create.md](references/task-create.md)
**快速概览:**
```
1. 确定所属模块(从 modules.json 缓存解析名字 → ID
2. 收集任务信息(标题、描述、截止日、优先级)
3. mcp__huanxi__task_create(module_id, title, ...)
4. [可选] 设置执行人 → mcp__huanxi__task_set_assignees(task_id, [user_id])
module_query() → module_id
task_query(module_ids=[...]) → task_id[] ← 展示给用户看
↓ ⏸ 用户指明改哪些
task_update(updates=[{id, ...}])
```
---
## +update:更新任务
> ⚠️ 参数细节以 MCP `task_update` 的 docstring 为准,本节仅做工作流引导。
##
```
Step 1: 确认任务 ID
→ 若用户已提供 task_id:直接使用
→ 若用户描述了任务名称:
a. mcp__huanxi__task_list_mine() 获取我的任务列表
b. 按标题关键词模糊匹配,列出候选任务供用户选择
c. 仍未找到(可能属于他人或已归档)→ 告知用户提供精确 task_id
Step 2: 展示当前任务状态,引导用户填写要修改的字段
Step 3: mcp__huanxi__task_update(task_id, {
title? : "新标题",
description? : "新描述",
progress? : 80, ← 0-100 整数
progress_before? : 60, ← 修改 progress 时必传当前值(乐观锁,防并发覆盖)
status? : "not_started" | "in_progress" | "done" | "cancelled" | "on_hold",
end_date? : "YYYY-MM-DD", ← 字段名是 end_date,不是 due_date
priority? : "low" | "medium" | "high" | "critical"
})
Step 4: 告知更新结果
task_query(scope="mine") 我负责执行的(默认)
task_query(scope="all", module_ids=[...]) 某几个模块的全部任务
task_query(q="关键词") 标题模糊搜
task_get(task_ids=[...]) 详情:描述 + 层级路径
```
⚠️ **历史踩坑**
- 字段名 `due_date` 错误,后端为 `end_date`
- 状态值 `todo` 错误,后端为 `not_started`
- priority 缺 `critical`,没有 `urgent`
- 改 progress 不传 `progress_before` 会 409 冲突
过滤维度都收列表,一次查多个模块比循环调用好。
---
## +assign:设置执行人
## 改状态与进度
**先 `dict_get` 取 task 类型的状态选项**,拿到 `status_option_id` 再传:
```
Step 1: 确认任务 ID
Step 2: 解析执行人名字 → user_id(查 users.json 缓存)
→ 详见 huanxi-org references/resolve-ids.md
Step 3: mcp__huanxi__task_set_assignees(task_id, assignee_ids=[user_id, ...])
(此操作幂等:传完整列表,不是追加)
Step 4: 告知设置结果
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 的那些,进度是子任务
聚合出来的,硬设会被拒绝。要推进它,去改它的子任务。
---
## +get:查看任务详情
## 建任务
```
Step 1: mcp__huanxi__task_get(task_id)
Step 2: 展示完整任务信息(标题/描述/状态/进度/执行人/截止日/评论数)
task_create(module_id=..., tasks=[{title, description?, priority?, end_date?,
parent_id?, milestone_id?, assignee_ids?}])
```
- 建子任务传 `parent_id`,**最多三级**(任务 / 子任务 / 孙任务)
- 需要是该模块的成员或负责人
- `priority` 的取值以工具说明为准——**不要凭直觉写**,这个字段有 DB 级约束,写错直接报错
---
## 关键约束
## 执行人
- **任务创建后不自动认领**`task_create` 不会自动设置执行人,需要单独调用 `task_set_assignees`
- **执行人是完整列表**`task_set_assignees` 传入的是完整执行人 ID 列表(幂等替换),不是追加
- **progress 是整数**:0-100 的整数,不是小数或百分比字符串
- **模块创建权限**:用户必须是模块成员(任意角色)才能在该模块创建任务,否则返回 403
```
task_set_assignees(task_id=..., user_ids=[...]) 整组覆盖,传空即清空
task_claim(task_ids=[...], claim=true/false) 认领 / 取消认领(只动自己)
```
**`task_set_assignees` 是替换不是追加。** 想加一个人,要先 `task_get` 拿到现有名单,
把新人拼进去再整组传回——直接传一个人会把其余执行人全部踢掉。这是最容易出错的地方,
覆盖前把「改完会变成谁」说给用户听。
被指派的人若不是模块成员,会自动加入该模块;新增执行人会收到飞书通知。
---
## 不在工具里的操作
删除任务、跨模块转移任务**不在 MCP**,请引导用户去网页端——这两个动作作用于整棵子树
且不可逆,需要看清楚影响范围再点。
@@ -1,86 +0,0 @@
# 创建任务(+create
> ⚠️ 参数细节以 MCP `task_create` 的 docstring 为准,本文档仅做工作流引导。
## 必填信息收集
在调用 `task_create` 前,引导用户提供:
| 字段 | 必填 | 说明 |
|------|------|------|
| `module_id` | ✅ | 所属模块 UUID(从缓存解析名字 → ID) |
| `title` | ✅ | 任务标题(简洁明了)|
| `description` | 可选 | 任务详情、背景、验收标准(Markdown) |
| `end_date` | 可选 | 截止日期(YYYY-MM-DD 格式,**字段名是 end_date,不是 due_date** |
| `priority` | 可选 | `low` / `medium` / `high` / `critical`,默认 `medium`**没有 urgent** |
| `status` | 可选 | `not_started`(默认)/ `in_progress` |
| `parent_task_id` | 可选 | 父任务 UUID,传此字段即为子任务 |
| `assignee_ids` | 可选 | 执行人 user_id 列表,**可在创建时一并传入**(无需再单独调 `task_set_assignees` |
---
## 执行步骤
```
Step 1: 解析模块名 → module_id
→ Read ~/.claude/huanxi-cache/modules.json
→ 模糊匹配模块名(详见 huanxi-org resolve-ids.md
Step 2: [若用户提到执行人] 解析人名 → user_id(user 对象的 id 字段)
→ Read ~/.claude/huanxi-cache/users.json
→ 未命中 → mcp__huanxi__user_list(name=<人名>) → 追加写缓存
Step 3: 创建任务(推荐一次性把执行人也带上)
→ mcp__huanxi__task_create(
module_id = "<模块ID>",
title = "任务标题",
description = "...", ← 可选
end_date = "YYYY-MM-DD", ← 可选;字段名 end_date
priority = "medium", ← 可选;low/medium/high/critical
status = "not_started", ← 可选;默认 not_started
assignee_ids = ["<user_id>"] ← 可选;若 Step 2 有解析到,建议一并传入
)
→ 返回:task_id
Step 4: [仅当 Step 3 未传 assignee_ids 时] 单独设置执行人
→ mcp__huanxi__task_set_assignees(
task_id = "<刚创建的 task_id>",
assignee_ids = ["<user_id>"]
)
Step 5: 告知创建结果
→ 展示:任务标题、所属模块、执行人、截止日、task_id
→ 询问:"是否需要进一步调整?"
```
---
## 权限说明
用户必须是所属模块的成员(任意角色)才能创建任务。若返回 403:
- 可能未加入该模块
- 建议联系模块负责人添加成员,或请管理员使用 Admin MCP 操作
---
## 子任务支持
若需创建子任务:
```
mcp__huanxi__task_create(
module_id = "<模块ID>",
title = "子任务标题",
parent_task_id = "<父任务ID>" ← 传此字段即为子任务
)
```
---
## 字段名速查(避免漂移)
| 概念 | 正确字段名 | 错误写法 |
|------|----------|---------|
| 截止日期 | `end_date` | ~~due_date~~ |
| 紧急优先级 | `critical` | ~~urgent~~ |
| 未开始状态 | `not_started` | ~~todo~~ |
| 父任务 ID | `parent_task_id` | ~~parent_id~~(后端 body 内是 parent_id,但 MCP 参数是 parent_task_id |
@@ -1,56 +0,0 @@
# 任务看板(+board
> ⚠️ 参数细节以 MCP `task_list_mine` / `task_list_by_module` / `people_get_board` 的 docstring 为准,本文档仅做工作流引导。
## 查看我的任务
```
Step 1: mcp__huanxi__task_list_mine()
→ 返回我认领的所有任务(跨模块)
→ 每条含:id / title / status / priority / progress / module_name / end_date / assignees
Step 2: 按状态分组展示(状态值与后端枚举一致):
────────────────────────────────────
📋 未开始(not_started
· [前端开发] 完成登录页面 UI 优化 ← end_date: 04-15
· [后端API] 接口文档更新 ← 无截止日
🔄 进行中(in_progress
· [前端开发] 接口联调 60% ← end_date: 04-20
✅ 已完成(done)
· [前端开发] 初始化项目结构 100%
⏸️ 已挂起(on_hold / ❌ 已取消(cancelled)— 默认折叠
────────────────────────────────────
```
## 查看模块看板
```
Step 1: 确认模块(从 modules.json 缓存解析)
Step 2: mcp__huanxi__task_list_by_module(module_id)
→ 返回该模块所有任务(含其他成员的任务)
Step 3: 按状态分组展示,标注每个任务的执行人
```
## 人员任务看板(管理视角)
```
Step 1: mcp__huanxi__people_get_board()
→ 返回团队所有成员的任务分布(数量统计)
Step 2: 展示每人的任务负载情况(适合分配任务前参考)
```
---
## 快速过滤
用户常见需求:
| 场景 | 做法 |
|------|------|
| "我今天要做什么" | task_list_mine() → 过滤 status=in_progress + 截止日临近 |
| "某个模块的任务" | task_list_by_module(module_id) |
| "即将到期的任务" | task_list_mine() → 筛选 end_date ≤ 今日+3天 |
| "团队任务分布" | people_get_board() |
@@ -1,133 +0,0 @@
---
name: huanxi-weekly
description: "寰汐周报工作流(仅限模块负责人):查看本周周报状态(+check)、基于本周负责人日报 AI 汇总草稿(+draft)、提交周报(+submit)、撤回(+withdraw)。当用户说"写周报"、"提交周报"、"本周总结"、"周报进度"时触发。"
---
# 寰汐周报(仅限模块负责人)
**前置条件:先 Read `../huanxi-shared/SKILL.md`(缓存规则 + TTL 策略)**
> ⚠️ **工具调用规范**:执行任何 `mcp__huanxi__*` 调用前,以工具实际注册的参数名和类型为准,本文档示例仅供工作流引导(见 shared 全局约定第 6 条)。
---
## 权限说明
**周报只有模块负责人(`my_role == 'leader'`)才需要提交。**
若用户不是任何模块的负责人:
- 告知:"您目前不是任何模块的负责人,无需提交周报。"
- 建议:若有疑问,可联系管理员确认模块角色。
---
## ISO 周数规范(重要)
寰汐周报使用 **ISO 8601 标准**
- `year` 字段存 **ISO year**(不是日历年)
- 12月底/1月初可能跨年:如 2025-12-29 的 ISO year = 2026(第1周)
- Python 获取:`date.isocalendar()``(iso_year, week, weekday)`
**当前日期 → ISO 周号计算示例:**
- 2026-04-13(周一)→ year=2026, week=16
---
## 标准工作流
```
Step 0: 确认负责人身份和模块
→ Read ~/.claude/huanxi-cache/modules.json24h 缓存)
→ 若过期:mcp__huanxi__module_list() → 更新缓存
→ 筛选 my_role == 'leader' 的模块列表
→ 若列表为空:告知用户无需提交周报,流程终止
→ 若有多个 leader 模块:询问"要提交哪些模块的周报?"
Step 1: 确定当前 ISO 周号
→ 根据今日日期计算 (iso_year, iso_week)
→ 告知:第 iso_week 周(周一 ~ 周日 日期范围)
Step 2: 批量拉取周报草稿
→ mcp__huanxi__weekly_report_get_batch(
year=iso_year,
week=iso_week,
module_ids=[<leader 模块的 ID 列表>]
)
→ 返回:各模块的现有草稿状态
Step 3: 逐日拉取本周负责人日报
→ 计算本周日期范围(周一到今日,YYYY-MM-DD 格式列表)
→ 对每个日期逐一调用:
mcp__huanxi__leader_report_get_batch(
date=<单个日期>,
module_ids=[<leader 模块的 ID 列表>]
)
→ 汇总所有日期的返回数据
→ 展示:本周每日负责人日报记录(含各日进展摘要 + 下属提交情况)
Step 4: 询问是否 AI 汇总
→ 展示本周负责人日报数据后,询问:
"是否需要 AI 根据本周负责人日报自动生成周报草稿?"
→ 用户同意 → AI 基于 leader_report_batch 起草:
· content:本周模块整体进展总结
· next_week_plan:下周模块工作计划
→ 展示草稿,供用户审阅和修改
→ 用户拒绝 → 引导用户手动填写本周总结和下周计划
Step 5: 逐模块保存草稿
→ 详见 references/weekly-draft.md
→ mcp__huanxi__weekly_report_save(module_id, year, week_number, content, next_week_plan)
Step 6: 确认并提交
→ 展示所有模块最终内容,等待用户明确确认("确认"/"提交"/"好的"等)
→ ⚠️ 未收到确认前,禁止调用 weekly_report_submit
→ mcp__huanxi__weekly_report_submit(module_id)
```
---
## Shortcuts
| 指令 | 说明 |
|------|------|
| `+check` | 查看本周周报状态(草稿/已提交) |
| [`+draft`](references/weekly-draft.md) | 基于本周负责人日报 AI 生成草稿 |
| `+submit` | 提交周报(必须先确认) |
| `+withdraw` | 撤回已提交周报 |
---
## +check:查看本周状态
```
1. 确认 leader 模块列表(同 Step 0
2. 若无 leader 模块:告知无需提交周报
3. mcp__huanxi__weekly_report_get_batch(year, week, module_ids)
4. 展示各模块周报状态:
- submitted:已提交,展示摘要
- draft:草稿中,展示已填内容
- empty:未填,建议运行 +draft
```
---
## +withdraw:撤回周报
```
1. 确认 leader 模块(从 modules.json 缓存中取)
2. 若有多个 leader 模块,询问要撤回哪个模块的周报
3. 告知撤回影响(状态变为草稿,可重新编辑),等待用户确认
4. mcp__huanxi__weekly_report_withdraw(module_id)
(默认撤回当周;如需撤回历史周:传 year + week_number
5. 告知成功,可重新编辑后再次提交
```
---
## 关键约束
- **仅负责人可提交**:首先检查 `my_role == 'leader'`,非负责人直接告知无需操作
- **禁止自动提交**`weekly_report_submit(module_id)` 前必须展示全部内容并等待用户确认
- **year 存 ISO year**:高频出错点,必须使用 `isocalendar()[0]`,不要用 `date.year`
- 每个模块独立提交,有多个模块时逐一处理
- 撤回后可重新编辑,不影响当前状态
@@ -1,99 +0,0 @@
# 周报草稿(+draft,仅限模块负责人)
> ⚠️ 参数细节以 MCP `weekly_report_save` 的 docstring 为准,本文档仅做工作流引导。
## 数据来源
周报草稿基于**本周负责人日报汇总**(`leader_report_get_batch` 返回值),而非员工个人日报。
| 数据 | 来源 | 说明 |
|------|------|------|
| 本周每日负责人日报 | `leader_report_get_batch(date列表, module_ids)` | 含各日的模块进展 + 下属提交情况摘要 |
| 现有周报草稿 | `weekly_report_get_batch(year, week, module_ids)` | 已填写的草稿(若有) |
---
## 草稿生成步骤
```
Step 1: 解析本周负责人日报数据
→ 按日期排列,提取每日:
· 模块整体进展
· 团队成员提交情况
· 遇到的问题与风险
Step 2: AI 基于负责人日报起草 content(本周总结):
- 提炼本周模块核心进展(任务推进 + 里程碑)
- 汇总团队整体情况
- 列出本周识别的问题与应对
Step 3: AI 起草 next_week_plan(下周计划):
- 基于本周未完成项和下周目标
- 结合用户补充的计划
Step 4: 展示草稿给用户审阅修改
Step 5: 用户确认后逐模块保存:
mcp__huanxi__weekly_report_save(
module_id = "<模块ID>",
year = <ISO year>, ← 注意:ISO year,不是日历年
week_number = <ISO week>, ← 后端字段名是 week_number,不是 week
content = "<本周总结>",
next_week_plan = "<下周计划>"
)
```
---
## 内容格式建议(负责人视角)
**content(本周总结):**
```markdown
## 本周模块进展
- **[任务A]** 完成 XX 功能开发,进度推进至 80%(负责人:张三)
- **[任务B]** 完成接口联调,已提测(负责人:李四)
## 团队提交情况
本周全员提交日报,无缺报。
## 问题与风险
- [周三] 第三方接口超时问题,已升级厂商处理,预计周一恢复
## 本周总体评估
整体按计划推进,无阻塞性风险。
```
**next_week_plan(下周计划):**
```markdown
- [任务A] 目标完成剩余 20% 并提测
- [任务B] 协助测试团队完成验收
- 启动 [新需求] 的技术调研
```
---
## 已有草稿处理
`weekly_report_get_batch()` 中该模块已有草稿(非 empty):
- 展示现有草稿内容
- 询问:"是在此基础上修改,还是基于本周负责人日报重新生成?"
- 基于用户选择执行对应操作
---
## 多模块处理
```
for module in leader_modules:
1. 提取该模块的 leader_report_batch(本周各日记录)
2. AI 生成草稿(content + next_week_plan
3. 展示给用户确认/修改
4. weekly_report_save(module_id=module.id, year, week_number, ...)
5. 告知:模块 "{module.name}" 草稿已保存 ✅
所有模块草稿完成后:统一展示,询问是否提交
```
@@ -0,0 +1,18 @@
{
"name": "memcore",
"version": "1.0.0",
"description": "Codex 记忆体系核心引擎。提供 memcore-shared(内部共享约定)+ memory-sync(全量同步编排)+ memory-update(增量写入)+ memory-lint(健康校验)。Codex 版本不使用远程记忆,记忆只落在当前仓库/项目目录内。",
"author": {
"name": "姜顺志"
},
"skills": "./skills",
"interface": {
"displayName": "Memcore",
"shortDescription": "项目本地记忆体系核心引擎",
"longDescription": "给 Codex 加一套跨会话持久的项目本地记忆引擎:memory-sync 做完整同步周期(Git 检查 → 读取现有记忆 → 增量更新 → 健康校验 → 维护 AGENTS.md 启动引导),memory-update 做增量写入,memory-lint 做健康校验(孤儿/幽灵检测、双向引用、内容矛盾、按提交速度分档的过期检测)。不依赖 MCP,纯技能实现;不使用远程记忆,也不读写 Codex 原生 Memories。",
"developerName": "蚁熊团队",
"category": "Productivity",
"capabilities": ["Interactive", "Write"],
"defaultPrompt": "帮我同步一下这个项目的本地记忆"
}
}
@@ -0,0 +1,74 @@
---
name: memcore-shared
description: "memcore 内部共享约定:记忆目录选择优先级、会话入口术语、禁止触碰的路径、synthesis/过期检测阈值常量。仅供 memory-sync、memory-update、memory-lint 三个技能在 Phase 0 内部 Read 引用,不用于直接回答用户问题或独立执行任务。"
---
# memcore-shared
三个主技能(memory-sync / memory-update / memory-lint)的内部共享 include。**用户不会直接调用本技能**,三个主技能在开始执行前必须先 Read 本文件载入以下约束。
---
## 统一术语
- `SESSION_GUIDE_FILE``AGENTS.md`,Codex 项目的会话启动入口锚点。
- `PROJECT_MEMORY_DIR`:项目内唯一记忆目录,取 `.claude/memory``.codex/memory`(选择规则见下)。
- `MEMORY_INDEX``PROJECT_MEMORY_DIR/MEMORY.md`
修改 `SESSION_GUIDE_FILE``MEMORY_INDEX` 或任何记忆文件时,优先使用小范围补丁,不要整文件重写。记忆变更和代码变更必须分开说明、分开确认。
---
## PROJECT_MEMORY_DIR 选择优先级
三个主技能执行前都必须先按以下优先级确定唯一记忆目录:
1.`AGENTS.md` 已含记忆体系区块,优先读取该区块中记录的记忆目录;目录存在则使用它。
2.`$PROJECT_DIR/.claude/memory/` 存在,使用它——视为复用现有 Claude 项目记忆。
3.`$PROJECT_DIR/CLAUDE.md` 存在但 `.claude/memory/` 不存在,先读取 `CLAUDE.md` 中与记忆体系相关的说明;只在用户明确要求建立结构化记忆目录时才创建 `.codex/memory/`
4.`$PROJECT_DIR/.codex/memory/` 存在,使用它。
5. 以上都不存在,需要创建记忆时使用 `$PROJECT_DIR/.codex/memory/`,但创建前必须向用户说明将建立的目录结构和基础文件,并等待确认。
关键规则:
- `AGENTS.md` 是会话入口锚点,不是记忆目录本身。
- 已有 `CLAUDE.md``.claude/memory/` 时直接引用现有内容,不重复添加同类记忆引导。
- 不把 `.claude/memory/` 复制到 `.codex/memory/`,也不反向复制——两者只能存在一个作为 `PROJECT_MEMORY_DIR`
---
## 禁止触碰的路径
| 路径 | 原因 |
|---|---|
| `~/.claude/projects/*/memory/` | Claude 侧系统 auto memory 路径。Codex 版本不使用远程记忆,不维护跨机器镜像,严禁读写 |
| `~/.codex/memories/` | Codex 原生 Memories,是个人本地召回层,不是团队可审查的项目事实来源,不作为本套记忆体系的后端 |
| `$PROJECT_DIR` 之外任何其他路径 | 跨项目污染 |
必须可审查、可协作、可复现的项目事实一律写入 `AGENTS.md``CLAUDE.md``.claude/memory/``.codex/memory/`,不写入上表任何路径。
---
## 全局常量
| 常量 | 值 | 含义 | 使用位置 |
|---|---|---|---|
| `SYNTHESIS_THRESHOLD` | `3` | 跨文件引用数 ≥ 此值即为 synthesis 升级候选 | memory-update Phase 3、memory-lint Phase 3 & 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 |
子技能引用常量时使用上述名称,调整阈值只需修改本文件单一来源。可由 `MEMORY.md` 头部 `<!-- lint-stale-warn: N -->` 覆盖 `LINT_STALE_MIN_DAYS`
---
## 引用约定
子技能开头标准引用句:
```markdown
**前置约束:先 Read `../memcore-shared/SKILL.md`(记忆目录选择优先级 + 禁止路径 + 常量)**
```
读取后,子技能内所有出现的 `$PROJECT_DIR``PROJECT_MEMORY_DIR``MEMORY_INDEX``SESSION_GUIDE_FILE` 及上述常量均按本文件定义执行。
@@ -0,0 +1,6 @@
interface:
display_name: "Memcore Shared"
short_description: "memcore 内部共享约定(不直接调用)"
policy:
allow_implicit_invocation: false
@@ -0,0 +1,304 @@
---
name: memory-lint
description: 检查仓库/项目本地记忆目录的健康状况,修复结构性问题并生成 lint_report.md。用于校验 MEMORY.md 索引、孤儿/幽灵文件、双向引用、内容矛盾、按提交速度分档的过期检测和可推断内容污染。Codex 版本只读写项目本地记忆;若仓库已有 CLAUDE.md 或 .claude/memory/,直接引用现有 Claude 记忆内容,不重复创建。
---
# memory-lint
健康检查项目本地记忆目录。会话目录视为 `$PROJECT_DIR`
**前置约束:先 Read `../memcore-shared/SKILL.md`**(记忆目录选择优先级 + 禁止路径 + 常量),其约束在本技能全程生效。
修改 `MEMORY_INDEX``lint_report.md` 或任何记忆文件时,优先使用小范围补丁;不要整文件重写。记忆变更和代码变更必须分开说明、分开确认。
若目标记忆目录不存在,输出缺失说明并建议先执行 `memory-sync``memory-update` 初始化。
## Phase 0 - 读取状态
读取:
- `MEMORY.md`
- 记忆目录内全部 `*.md`
- `Base commit`
- `Last synced`
提取索引文件集合 `$INDEX_FILES` 和磁盘文件集合 `$DISK_FILES`
## Phase 1-2 - 孤儿与幽灵检测
| 检查 | 定义 | 级别 | AUTO-FIX |
| --- | --- | --- | --- |
| 孤儿 | 索引有,磁盘无 | ERROR | 从 `MEMORY.md` 删除该条目 |
| 幽灵 | 磁盘有,索引无 | WARN | 补入索引 |
幽灵类型推断(按优先级匹配):
- `synonyms.md`(精确匹配) → reference
- `user_*` → user
- `project_*``decisions.md` → project
- `feedback*` → feedback
- `reference*` → reference
- `synthesis_*` → synthesis
- 其他默认 project
排除 `MEMORY.md``lint_report.md`
## Phase 3 - 交叉引用完整性
### 3A 存在性检测 + 引用计数构建
扫描所有 `[[filename.md#section]]`,构建:
- 引用表:`源文件#源章节 -> 目标文件#目标章节`
- 文件级被引用计数 `$REF_COUNT`(按源文件去重)→ Phase 7 写入 MEMORY.md「引用」列
- decisions 和 feedback 条目级引用计数 `$ITEM_REF_COUNT`(按源文件去重)→ Phase 8 写入 lint_report.md,供 `memory-update` 反向触发消费
| 情况 | 级别 | 动作 |
| --- | --- | --- |
| 目标文件不存在 | ERROR | NEED-HUMAN |
| 目标章节缺失,且存在高相似标题 | WARN | AUTO-FIX 更新引用 |
| 目标章节缺失,且无相似项 | WARN | NEED-HUMAN |
### 3B 对称性检测(双链闭环)
复用 3A 引用表,对每条 `A#x -> B#y` 检查 B 的 `## y` 是否含任意 `[[A` 引用(不要求精确章节)。
- 级别:WARN
- AUTO-FIX:B 的目标章节末尾追加 `**See Also** [[A#x]]`
- 边界:`lint_report.md` 不参与;B 整文件无对 A 任何引用 → AUTO-FIX;B 有引用但不在目标章节 → 仅 WARN 不自动修改
双链 AUTO-FIX 阈值:缺失反链不超过 5 条且涉及文件不超过 3 个时可以自动补齐;超过阈值、跨多个主题、或将触碰 `user_profile.md` / `synthesis_*.md` 时不自动修改,写入 `lint_report.md` 等待确认。
## Phase 4-pre - 等价表述加载
矛盾检测前先加载 `$PROJECT_MEMORY_DIR/synonyms.md`(可选文件):
```bash
[ -f "$PROJECT_MEMORY_DIR/synonyms.md" ] && \
grep -v "^#\|^---\|^$\|^name:\|^description:\|^type:" \
"$PROJECT_MEMORY_DIR/synonyms.md"
# 输出每行一个等价组(逗号分隔),大小写不敏感,存入 $SYNONYMS_GROUPS
```
`synonyms.md` 格式(用户自行在项目内创建和维护):
```markdown
---
name: 等价表述清单
description: 矛盾检测等价词表,同组词视为相同概念
type: reference
---
# 等价表述清单
> 每行一组,逗号分隔,大小写不敏感
PostgreSQL, PG, Postgres, postgresql
JWT, JSON Web Token
```
判定规则:两处描述中出现的技术术语若属同一等价组,跳过,不纳入矛盾候选。无 `synonyms.md` 时,仅检测直接数值/版本冲突,对措辞差异不报告。
## Phase 4 - 内容矛盾
| 维度 | 检查 |
| --- | --- |
| decisions vs feedback | 决策与协作规范是否冲突 |
| decisions vs 架构/依赖文件 | 是否与当前依赖清单(如 `package.json``requirements.txt``pom.xml`)实际内容冲突 |
| 多个 feedback 文件 | 是否重复或矛盾 |
| synthesis vs decisions | 归档结论是否抵触现有决策 |
| 合并残留标记 | 是否含 `<!-- merge-conflict -->` |
矛盾判定门槛(过 synonyms.md 等价检查后):
| 情况 | 处理 |
| --- | --- |
| 同主题,等价组内术语不同 | 跳过,不报告 |
| 同主题,结论相反 | WARN → NEED-HUMAN |
| 同主题,数值或版本直接冲突 | ERROR → NEED-HUMAN |
| 仅措辞不同,无直接逻辑冲突 | 跳过(宁漏报不误报) |
合并残留标记的 NEED-HUMAN 条目必须包含:
- 位置:文件名、章节标题、标记内容。
- Checklist:Q1 当前本地版本是否正确?Q2 另一版本是否有当前版本没有的有效信息?Q3 两者是否可以合并为单一表述?
- 决策矩阵:Q2 否 → 删除 `[合并待审]` 或分歧段落和标记;Q2 是 + Q3 是 → 合并为单一表述后删除标记;Q2 是 + Q3 否 → 保留两段内容,但清除 HTML 标记并说明适用边界。
## Phase 5 - 过期检测(提交速度分档)
不用固定天数二级阈值,改用「自 `last_updated` 以来的全仓库提交速度」判断过期风险的严重程度:高频迭代项目下 7 天未同步就可能已经漂移,低活跃项目下 180 天未动也可能仍然准确。阈值常量由 `memcore-shared` 定义。
```bash
# days_sincelast_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 | 绝对兜底,防止彻底沉寂的记忆永不复查 |
不要只因为日期老就自动刷新 `last_updated`。若内容仍有效,写入 NEED-HUMAN 让用户确认是否仅刷新日期;若内容与项目推进不符,标记为语义过时并给出证据位置。
## Phase 6 - 可推断内容污染
污染特征:大量具体文件路径、类名、方法签名、git 流水账、可从依赖文件直接读取的版本号列表。
**边界**:架构层级描述("认证模块提供 JWT + OAuth2 双协议")保留;具体类名/方法/路径列表删除或建议改写。
## Phase 7 - 执行 AUTO-FIX
只允许修复结构性问题:
1. 移除索引孤儿。
2. 补入索引幽灵。
3. 更新高置信断链引用。
4. 在阈值内补齐双向链接;超过阈值则写入 NEED-HUMAN。
5. 刷新 `MEMORY.md` 的「引用」列(基于 `$REF_COUNT`):表格统一 5 列 `| 文件 | 描述 | 类型 | 引用 | Commit |`;「引用」值 ≥ `SYNTHESIS_THRESHOLD``*`(如 `5*`),否则显示数字;按引用次数倒序排列,同次数按类型序: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_MEMORY_DIR/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)`;若 `id``RESOLVED_IDS` 中则跳过(用户已标记 resolved,本次不再列出);否则写入 `lint_report.md`,并在条目末尾附 `<!-- id: {id} -->`
**用户如何使用**:在 `lint_report.md` 中某个 NEED-HUMAN 条目末尾、`<!-- id: ... -->` 同段内,追加:
```markdown
<!-- resolved: 2026-06-12, 决定保留两者作为历史对比 -->
```
下次 lint 跑到时,发现该 id 在 `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] 更新断链:`[[feedback.md#旧标题]]``[[feedback.md#新标题]]`
- [x] MEMORY.md「引用」列已刷新(N 文件,倒序)
---
## 条目级高频引用 Top(供 memory-update 消费)
跨 ≥ `SYNTHESIS_THRESHOLD` 个不同源文件被引用的 decisions/feedback 条目。无候选时保留标题 + "无候选"。
| 条目 | 跨文件次数 | 建议 |
| --- | --- | --- |
| `decisions.md#示例决策标题` | 4 | 升级为 synthesis_xxx.md |
---
## NEED-HUMAN 待处理清单
每项附 3 问 yes/no checklist + 决策矩阵,避免模糊判断,末尾附 `<!-- id: xxxxxxxx -->`
### [ERROR] 引用断链 — 目标文件不存在
- **位置**`decisions.md → ## 数据库选型``[[synthesis_arch_xxx.md]]`
- **Checklist**Q1 内容是否真实归档过?Q2 git history 能否找到删除/重命名证据?Q3 该引用是「锦上添花」还是「核心支撑」?
- **矩阵**:Q1+Q2 是 → 恢复文件;Q1 是 + Q2 否 → 重新归档;Q1 否 → 删引用;Q3 核心 → 必须二选一不允许保留断链
<!-- id: a1b2c3d4 -->
### [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 -->
```
## Phase 9 - 输出摘要
`memory-sync` 调用:
```
🔍 memory-lintAUTO-FIX N 项,NEED-HUMAN N 项(历史 resolved 跳过 M 项,详见 lint_report.md
```
独立调用:扩展输出已修复 / 待处理清单 + 报告路径;全通过则输出「记忆体系健康,已更新执行时间」。
发现矛盾候选且 `synonyms.md` 不存在时,额外提示:创建 `.claude/memory/synonyms.md`(或对应的 `.codex/memory/synonyms.md`)可将等价术语预先排除出矛盾检测,降低误报率。
每次执行必须更新 `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` 再判矛盾;措辞不一致 ≠ 矛盾,宁漏报不误报。
5. 污染检测边界(重申)— 架构层级保留 / 具体类名路径删除。
6. 使用 `.claude/memory/` 时只复用现有 Claude 项目记忆,不复制到 `.codex/memory/`
7. 不访问远程记忆路径,不维护任何跨机器镜像;不 lint Codex 原生 Memories。
8.`memory-sync` 调用时返回简短摘要;独立调用时输出已修复和待处理清单。
9. 记忆变更和代码变更分开执行;不要把用户未确认的代码修改混入 lint 修复。
@@ -0,0 +1,7 @@
interface:
display_name: "Memory Lint"
short_description: "检查并整理项目记忆健康度"
default_prompt: "Use $memory-lint to check and repair project-local memory health."
policy:
allow_implicit_invocation: true
@@ -0,0 +1,158 @@
---
name: memory-sync
description: 编排 Codex 项目本地记忆同步流程:识别现有 CLAUDE.md/.claude/memory,确定唯一记忆目录,执行 memory-update 和 memory-lint,维护项目记忆索引和 AGENTS.md 启动引导。用于完整刷新仓库记忆体系。Codex 版本不使用远程记忆;若已有 Claude 记忆内容则直接引用,不重复添加。
---
# memory-sync
执行项目本地记忆体系的完整同步周期。会话目录视为 `$PROJECT_DIR`
**前置约束:先 Read `../memcore-shared/SKILL.md`**(记忆目录选择优先级 + 禁止路径 + 常量),其约束在本技能全程生效。
## 总流程
```text
Phase 0 确定 PROJECT_MEMORY_DIR(按 memcore-shared 优先级)
Phase 1 Git 和记忆冲突检查
Phase 2 读取现有 Claude/Codex 记忆
Phase 3 计算 diff 或全量审查范围
Phase 4 调用 memory-update
Phase 5 调用 memory-lint
Phase 6 维护 AGENTS.md 启动引导
Phase 7 完成报告
```
## Phase 0 - 确定 PROJECT_MEMORY_DIR
`memcore-shared` 的选择优先级确定 `PROJECT_MEMORY_DIR`。若最终落在「需要创建 `.codex/memory/`」的分支,向用户说明目录结构并等待确认后再继续。
## Phase 1 - Git 和记忆冲突检查
若项目是 git 仓库,先读取:
```bash
git status --short
git rev-parse --show-toplevel
git rev-parse --short HEAD
```
存在未解决冲突时,优先处理记忆目录内的冲突文件。不要自动提交用户未确认的非记忆变更。
非 git 仓库继续执行,commit 字段填 `N/A`
记忆文件冲突采用语义合并,限于 `PROJECT_MEMORY_DIR`
| 冲突类型 | 处理方式 |
| --- | --- |
| frontmatter `last_updated` | 取两者较新日期 |
| frontmatter `commit` | 取当前 HEAD 或本地工作区对应值 |
| `## Section` 两边内容相同 | 保留一份 |
| `## Section` 仅一边存在 | 保留或追加到文件末尾 |
| `## Section` 两边都存在但内容不同 | 保留当前本地版本,将另一版本追加为 `## [合并待审] Section`,标注 `<!-- merge-conflict: YYYY-MM-DD -->` |
| `MEMORY.md` 索引冲突 | 不手工合并,保留当前版本,交给 `memory-lint` 重建索引 |
| `user_profile.md``synthesis_*.md` | 不自动合并,在文件头标注 `<!-- merge-conflict: YYYY-MM-DD, NEED-HUMAN -->` |
合并前应备份冲突文件,备份文件不要提交。完成后提示用户审查 `<!-- merge-conflict -->` 标记,并由 `memory-lint` 写入 NEED-HUMAN。
## Phase 2 - 读取现有记忆
若存在 `MEMORY.md`,先读取索引,再按需加载文件:
- 必读:`decisions.md``feedback*.md``project_progress.md``project_overview.md` 中由索引标为 project 或 feedback 的文件。
- 按需:`user_profile.md``reference.md``synthesis_*.md``lint_report.md`
若只有 `CLAUDE.md`,读取其中与项目约定、记忆体系、开发流程有关的章节,并避免重复生成同类内容。
## Phase 3 - 计算审查范围
`MEMORY.md` 头部读取 `Base commit`。有锚点时使用:
```bash
git diff --name-only $ANCHOR_COMMIT..HEAD
```
无锚点、非 git 仓库或首次初始化时执行全量审查。
## Phase 4 - 调用 memory-update
`memory-update` 的规则增量写入本地记忆文件和 `MEMORY.md` 索引。
要求:
- 只更新本次变化涉及的维度。
- 以 Why、约束、边界和协作规范为主。
- 不记录可从代码直接恢复的明细。
- 若使用 `.claude/memory/`,保持原目录,不创建重复的 `.codex/memory/`
## Phase 5 - 调用 memory-lint
`memory-lint` 的规则执行健康检查:
- 修复索引孤儿、幽灵、断链和缺失反向链接。
- 刷新引用计数。
- 生成或更新 `lint_report.md`
- 将内容矛盾、过期、污染和合并残留写入 NEED-HUMAN。
## Phase 6 - 维护 AGENTS.md 启动引导
Codex 项目的启动引导优先写入 `AGENTS.md`,避免新会话或上下文压缩后漏读权威项目记忆。
处理顺序:
1. 若项目已有 `AGENTS.md`,检查是否存在 `## 记忆体系(会话启动必读)` 区块。
2. 若区块存在且仍与 `MEMORY.md` 一致,只引用,不重复追加。
3. 若区块缺失或过期,先向用户说明将更新的内容,确认后再修改;提取区块内已记录的 commit 锚点(若有),据此判断哪些子章节需要针对性调整,而不是整块重写。
4. 若项目没有 `AGENTS.md` 但已有 `CLAUDE.md``.claude/memory/`,默认只引用现有 Claude 记忆;需要 Codex 启动引导时,询问用户是否创建 `AGENTS.md`,不要把 `.claude/memory/` 复制到 `.codex/memory/`
5. 若项目没有 `AGENTS.md``CLAUDE.md``.claude/memory/`,需要项目级 Codex 引导时创建 `AGENTS.md`,并指向 `.codex/memory/`
6. 不为了 Codex 强制创建或改写 `CLAUDE.md`
`AGENTS.md` 记忆体系区块模板:
```markdown
## 记忆体系(会话启动必读)
> 新会话或上下文压缩后,必须先读记忆目录的 `MEMORY.md` 索引,再按需加载文件。代码事实与项目记忆冲突时,以代码事实为准并更新项目记忆。
### 读取流程
1. 读取 `{MEMORY_DIR}/MEMORY.md` 获取文件清单、类型和引用计数。
2. **必读锚点**{REQUIRED_MEMORY_FILES}
3. **选读锚点**{OPTIONAL_MEMORY_FILES}
4. 若仓库使用 `.claude/memory/`,直接读取该目录;不要复制到 `.codex/memory/`
### 权威优先级
1. 当前代码、配置、测试和真实文件状态。
2. 仓库内项目记忆:`AGENTS.md``CLAUDE.md``.claude/memory/``.codex/memory/`
3. Codex 原生 Memories(个人本地召回层,仅作辅助上下文)。
```
区块生成规则:
- `{MEMORY_DIR}` 必须替换为实际目录:`.claude/memory``.codex/memory`
- `{REQUIRED_MEMORY_FILES}` 必须来自 `MEMORY.md` 中实际存在的 project/feedback 类型文件,通常包括 `decisions.md``feedback*.md``project_progress.md``project_overview.md`
- `{OPTIONAL_MEMORY_FILES}` 必须来自 `MEMORY.md` 中实际存在的 user/reference/synthesis/lint 类型文件,通常包括 `user_profile.md``reference.md``synthesis_*.md``lint_report.md`
- 已有 `CLAUDE.md` 记忆引导时,`AGENTS.md` 可以指向相同记忆目录,但不要复制正文。
- 任何写入 `AGENTS.md``CLAUDE.md``MEMORY.md` 或记忆文件的动作,都必须先说明变更并等待用户确认。
## Phase 7 - 完成报告
报告包括:
- 使用的记忆目录。
- 是否复用了 `CLAUDE.md``.claude/memory/`
- `memory-update` 更新文件数量。
- `memory-lint` AUTO-FIX 和 NEED-HUMAN 数量(含历史已 `<!-- resolved -->` 跳过的数量)。
- 高频引用条目候选 synthesis 升级,来自 `lint_report.md` 的「条目级高频引用 Top」;无候选时写明无候选。
- 是否更新了 `AGENTS.md` 启动引导。
- 未执行项或跳过项,例如未初始化 `.codex/memory/`、未更新 `AGENTS.md`、存在 NEED-HUMAN 待处理、跳过 synthesis 创建。
- 当前 `Base commit`
## 执行约束
1. 项目本地记忆是唯一来源。
2. 不访问或模拟 Claude 远程记忆。
3. 已有 Claude 项目记忆时复用,不复制、不重复生成。
4. 不读写 Codex 原生 Memories;它们是个人召回层,不是本套项目记忆的后端。
5. `memory-update` 必须先于 `memory-lint`
6. Codex 启动引导优先维护 `AGENTS.md`;不要为了 Codex 强制创建或改写 `CLAUDE.md`
7. 修改 `AGENTS.md``CLAUDE.md``MEMORY.md` 或记忆文件前,先说明变更并取得用户确认。
8. 记忆变更和代码变更分开执行;不要把用户未确认的代码修改混入记忆同步。
@@ -0,0 +1,7 @@
interface:
display_name: "Memory Sync"
short_description: "编排项目本地记忆同步流程"
default_prompt: "Use $memory-sync to synchronize and refresh project-local memory."
policy:
allow_implicit_invocation: true
@@ -0,0 +1,199 @@
---
name: memory-update
description: 根据 git diff 或当前任务上下文,增量更新仓库/项目本地记忆目录和 MEMORY.md 索引。用于把代码变更、架构决策、协作反馈、外部参考和用户偏好沉淀到项目记忆中。Codex 版本不使用远程记忆;若仓库已有 CLAUDE.md 或 .claude/memory/,直接引用现有 Claude 记忆内容,不重复创建或复制;否则使用 .codex/memory/。
---
# memory-update
按增量范围更新项目本地记忆。会话目录视为 `$PROJECT_DIR`
**前置约束:先 Read `../memcore-shared/SKILL.md`**(记忆目录选择优先级 + 禁止路径 + 常量),其约束在本技能全程生效。
修改 `MEMORY_INDEX` 或任何记忆文件时,优先使用小范围补丁;不要整文件重写。记忆变更和代码变更必须分开说明、分开确认。
## Phase 1 - 读取增量锚点
```bash
# 主锚点:MEMORY.md 头部 _Last synced: DATE | Base commit: `HASH`_ → $ANCHOR_COMMIT
ANCHOR_COMMIT=$(grep -oE 'Base commit: `[^`]+`' "$PROJECT_MEMORY_DIR/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_MEMORY_DIR/"*.md 2>/dev/null \
| awk '{print $2}' | sort -u)
if [ -n "$FALLBACK" ]; then
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:` 字段取**最旧值**,确保覆盖所有真实改动而不误判为无差别全量。
`ANCHOR_COMMIT`(含兜底命中)时以该提交作为差量起点;仍为空、非 git 仓库或首次初始化时执行全量审查。
## Phase 2 - 计算变更范围
```bash
[ -n "$ANCHOR_COMMIT" ] && git diff --name-only $ANCHOR_COMMIT..HEAD # → $CHANGED_FILES
```
无锚点时审查当前项目结构、依赖文件、现有记忆文件和本次会话明确产生的信息。
## Phase 3 - 更新记忆文件
### 维度路由($CHANGED_FILES → 目标文件)
| 变更内容 | 写入到 |
| --- | --- |
| 业务代码、模块边界、架构形态 | `project_overview.md``decisions.md` |
| 依赖文件、运行方式、工具链 | `project_overview.md` |
| 进度信号、阶段状态、待办 | `project_progress.md` |
| 用户纠正、协作规范、风格偏好 | `feedback.md``feedback_{topic}.md` |
| 外部 URL、第三方约束 | `reference.md` |
| 用户长期偏好 | `user_profile.md` |
| 高价值分析归档 | `synthesis_{type}_{topic}.md` |
### 文件职责边界
| 文件 | 类型 | 写入 | 不写入 |
| --- | --- | --- | --- |
| `user_profile.md` | user | 角色、背景、长期偏好 | 任务进度 |
| `project_overview.md` | project | 技术栈、架构、目录、约定 | 可从代码直接 grep 的明细 |
| `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
---
```
`type` 可选值包含 `lint``memory-update` 通常不生成 `lint_report.md`,但更新索引时必须能识别 `lint` 类型。
`decisions.md``feedback*.md` 条目格式:
```markdown
## 标题
**结论:** xxx
**Why** 背景、约束、历史教训
**How to apply** 何时适用、边界
**See Also** [[file.md#标题]]
```
`synthesis_*.md` 使用完整文件格式,至少包含 `## 背景``## 分析过程``## 结论``## See Also`
feedback 拆分规则:当同一主题的协作规范超过 5 条,拆分到 `feedback_{topic}.md`,并在原 `feedback.md` 中保留索引或 See Also 引用。一次性修复、临时提醒和已经由代码体现的偏好不要沉淀为 feedback。
### Phase 3A - 交叉引用
新增 decisions 或 feedback 条目时:
1. 扫描记忆目录内其他 Markdown 标题。
2. 主题相关时,在新条目末尾追加 `[[file.md#标题]]`
3. 反向补链:被引用条目也追加对新条目的引用。
### Phase 3B - synthesis 三路触发
当某个 decisions 或 feedback 条目被 `SYNTHESIS_THRESHOLD`(默认 3)个以上不同文件引用,且条目中没有 `**Synthesized:**` 或 30 天内的 `<!-- synthesis-decline: YYYY-MM-DD -->` 标记时,建议升级为 `synthesis_*.md`,并等待用户确认后创建。
1. **会话内主动触发**:出现技术选型对比、Bug 根因分析、架构演进、安全或性能分析时,建议归档为 `synthesis_{type}_{topic}.md`
2. **lint 反向触发**:读取 `lint_report.md` 的「条目级高频引用 Top」,跨 `SYNTHESIS_THRESHOLD` 个以上不同源文件被引用的 decisions/feedback 条目是候选。
3. **即时快扫触发**(见 Phase 3C):每次 update 后扫描 `decisions.md``feedback*.md` 条目引用数,不等待下一次完整 lint。
synthesis 判重和免打扰:
- 条目已有 `**Synthesized:** [[xxx.md]]` 时,视为已升级,不重复创建。
- 条目已有 `<!-- synthesis-decline: YYYY-MM-DD -->` 且未超过 30 天时,不再提醒。
- 用户拒绝单个候选时,在原条目末尾追加 decline 标记。
- 用户选择 `skip-all` 时,本次 update 不再继续建议 synthesis。
- 创建 synthesis 后,在原条目末尾追加 `**Synthesized:** [[synthesis_xxx.md]]`
### Phase 3C - 即时引用计数快扫(不依赖 lint)
每次执行 Phase 3 末尾**强制运行**。目的:在短会话或任务型对话中,不依赖 lint 的延迟触发,直接检测 synthesis 升级候选。
```bash
SYNTHESIS_THRESHOLD=3 # 与 memcore-shared 全局常量保持一致
for entry_file in "$PROJECT_MEMORY_DIR/decisions.md" "$PROJECT_MEMORY_DIR/feedback"*.md; do
[ -f "$entry_file" ] || continue
fn=$(basename "$entry_file")
while IFS= read -r title; do
# 使用 grep -Ffixed string)避免 [[ ]] 在正则中的歧义;-- 防止 title 以 - 开头被误解为选项
count=$(grep -rlF -- "[[${fn}#${title}]]" \
"$PROJECT_MEMORY_DIR/" --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 含中文 / 空格 / 标点时不会破坏匹配。
- 单文件中同标题多次引用按 `-l` 仅记一次(按文件去重)。
对每条输出候选(`count|file#title`):
1. 读原条目内是否含 `**Synthesized:**` → 已升级,跳过。
2. 读原条目内是否含 `<!-- synthesis-decline: YYYY-MM-DD -->` → 30 天内,跳过。
3. 以上均无 → 触发提议(同 Phase 3B step 流程)。
**与 lint 的分工**
- Phase 3C(快扫):每次 memory-update 必跑,判据为「存在引用行数」,适合即时触发。
- lint Phase 3(精扫):按源文件去重的精确计数,健康检查时运行。
- 两者以 `**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` 刷新。
- `引用` 值大于等于 `SYNTHESIS_THRESHOLD` 时加 `*`,例如 `5*`
## 执行约束
1. 最小化更新,只写本次确认的变化维度。
2. 不记录可推断内容,例如完整文件路径列表、方法签名、git 流水账。
3. feedback 同主题超过 5 条时拆分到主题文件。
4. 追加为主,除非内容明确过时或冲突。
5. 如果使用的是 `.claude/memory/`,视为复用现有 Claude 项目记忆;不要迁移、复制或生成重复的 `.codex/memory/`
6. 不把 Codex 原生 Memories 当作可编辑后端;需要跨会话保留的项目事实必须写入仓库/项目内记忆。
7.`memory-sync` 调用时只返回简短摘要;独立调用时输出完整更新摘要。
8. 记忆变更和代码变更分开执行;不要把用户未确认的代码修改混入记忆更新。
@@ -0,0 +1,7 @@
interface:
display_name: "Memory Update"
short_description: "按变更增量更新项目记忆"
default_prompt: "Use $memory-update to update project-local memory from recent changes."
policy:
allow_implicit_invocation: true
+11
View File
@@ -0,0 +1,11 @@
{
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
"name": "memcore-hermes",
"version": "1.0.0",
"description": "Hermes Agent 记忆体系核心引擎。提供 memcore-shared(内部共享约定)+ memory-sync(全量同步编排)+ memory-update(增量写入)+ memory-lint(健康校验)。项目记忆目录复用 .claude/memory 或 .codex/memory,都不存在时新建 .agents/memory;不读写 Hermes 原生全局 MEMORY.md/USER.md,也不使用任何远程记忆。",
"author": {
"name": "蚁熊团队"
},
"license": "MIT",
"keywords": ["memory", "productivity", "project-memory"]
}
@@ -0,0 +1,86 @@
---
name: memcore-shared
description: "memcore 内部共享约定:记忆目录选择优先级、会话入口术语、禁止触碰的路径、synthesis/过期检测阈值常量、Hermes 全局记忆避让规则。仅供 memory-sync、memory-update、memory-lint 三个技能在 Phase 0 内部 Read 引用,不用于直接回答用户问题或独立执行任务。"
---
# memcore-shared
三个主技能(memory-sync / memory-update / memory-lint)的内部共享 include。**用户不会直接调用本技能**,三个主技能在开始执行前必须先 Read 本文件载入以下约束。
---
## 统一术语
- `SESSION_GUIDE_FILE``AGENTS.md`Hermes(及 Codex)共用的会话启动入口锚点。
- `PROJECT_MEMORY_DIR`:项目内唯一记忆目录,取 `.claude/memory``.codex/memory``.agents/memory`(选择规则见下)。
- `MEMORY_INDEX``PROJECT_MEMORY_DIR/MEMORY.md`
修改 `SESSION_GUIDE_FILE``MEMORY_INDEX` 或任何记忆文件时,优先使用小范围补丁,不要整文件重写。记忆变更和代码变更必须分开说明、分开确认。
---
## PROJECT_MEMORY_DIR 选择优先级
三个主技能执行前都必须先按以下优先级确定唯一记忆目录:
1.`AGENTS.md` 已含记忆体系区块,优先读取该区块中记录的记忆目录;目录存在则使用它(这条规则天然让 memcore-hermes 与 memcore-codex 共存于同一项目时不会各建一份)。
2.`$PROJECT_DIR/.claude/memory/` 存在,使用它——视为复用现有 Claude 项目记忆。
3.`$PROJECT_DIR/.codex/memory/` 存在,使用它——视为复用现有 Codex 项目记忆。
4.`$PROJECT_DIR/CLAUDE.md` 存在但以上两个目录都不存在,先读取 `CLAUDE.md` 中与记忆体系相关的说明;只在用户明确要求建立结构化记忆目录时才创建 `.agents/memory/`
5. 以上都不存在,需要创建记忆时使用 `$PROJECT_DIR/.agents/memory/`,但创建前必须向用户说明将建立的目录结构和基础文件,并等待确认。
关键规则:
- `AGENTS.md` 是会话入口锚点,不是记忆目录本身。
- 已有 `CLAUDE.md``.claude/memory/``.codex/memory/` 时直接引用现有内容,不重复添加同类记忆引导。
- 不在 `.claude/memory/``.codex/memory/``.agents/memory/` 三者之间互相复制——只能存在一个作为 `PROJECT_MEMORY_DIR`
-`.agents/memory/` 而不是 `.hermes/memory/`:这个目录名不绑定单一工具,未来若有第三个工具也想复用项目级记忆,可以按同样的选择优先级接入,不必再新造一个工具专属目录名。
---
## 禁止触碰的路径
| 路径 | 原因 |
|---|---|
| `~/.hermes/memories/``MEMORY.md`/`USER.md`) | Hermes 原生全局记忆,按 profile 隔离、跨项目共享,是个人召回层,不是团队可审查的项目事实来源,不作为本套记忆体系的后端,也不得读取后原样复制进项目记忆 |
| `~/.hermes/mcp-tokens/``~/.hermes/.env``~/.hermes/config.yaml` 中的密钥字段 | 凭证与本地配置,与项目记忆无关,严禁读写或摘录 |
| `~/.claude/projects/*/memory/` | Claude 侧系统 auto memory 路径,与本套记忆体系无关,严禁读写 |
| `$PROJECT_DIR` 之外任何其他路径 | 跨项目污染 |
必须可审查、可协作、可复现的项目事实一律写入 `AGENTS.md``CLAUDE.md``.claude/memory/``.codex/memory/``.agents/memory/`,不写入上表任何路径。
---
## Hermes 全局记忆避让规则(不重复记录)
Hermes 会自动把它认为值得记住的内容写入 `~/.hermes/memories/MEMORY.md`agent 笔记)与 `USER.md`(用户档案),这个行为是**自主触发、默认开启**的,不受本套技能控制。三个主技能在执行时必须显式提醒(写入报告/摘要即可,不需要修改 Hermes 配置):
> `PROJECT_MEMORY_DIR` 是本项目事实的权威来源;Hermes 自己的全局 `MEMORY.md`/`USER.md` 属于跨项目的个人记忆层,不应该收录本项目特有的架构决策、协作规范、进度信息——这些统一沉淀在 `PROJECT_MEMORY_DIR`,避免同一份事实在两处漂移出不一致的版本。
这条规则本身不是"技术拦截"memcore 没有能力阻止 Hermes 自动写全局记忆),而是**写入 memory-sync/memory-update 的 Phase 0 提醒文案**,让用户知道两套记忆的边界在哪,出现内容重复或冲突时知道以哪一份为准(答案:`PROJECT_MEMORY_DIR`)。
---
## 全局常量
| 常量 | 值 | 含义 | 使用位置 |
|---|---|---|---|
| `SYNTHESIS_THRESHOLD` | `3` | 跨文件引用数 ≥ 此值即为 synthesis 升级候选 | memory-update Phase 3、memory-lint Phase 3 & 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 |
子技能引用常量时使用上述名称,调整阈值只需修改本文件单一来源。可由 `MEMORY.md` 头部 `<!-- lint-stale-warn: N -->` 覆盖 `LINT_STALE_MIN_DAYS`
---
## 引用约定
子技能开头标准引用句:
```markdown
**前置约束:先 Read `../memcore-shared/SKILL.md`(记忆目录选择优先级 + 禁止路径 + Hermes 全局记忆避让规则 + 常量)**
```
读取后,子技能内所有出现的 `$PROJECT_DIR``PROJECT_MEMORY_DIR``MEMORY_INDEX``SESSION_GUIDE_FILE` 及上述常量均按本文件定义执行。
@@ -0,0 +1,304 @@
---
name: memory-lint
description: 检查仓库/项目本地记忆目录的健康状况,修复结构性问题并生成 lint_report.md。用于校验 MEMORY.md 索引、孤儿/幽灵文件、双向引用、内容矛盾、按提交速度分档的过期检测和可推断内容污染。Hermes 版本只读写项目本地记忆;若仓库已有 CLAUDE.md/.claude/memory/ 或 AGENTS.md/.codex/memory/,直接引用现有记忆内容,不重复创建。
---
# memory-lint
健康检查项目本地记忆目录。会话目录视为 `$PROJECT_DIR`
**前置约束:先 Read `../memcore-shared/SKILL.md`**(记忆目录选择优先级 + 禁止路径 + Hermes 全局记忆避让规则 + 常量),其约束在本技能全程生效。
修改 `MEMORY_INDEX``lint_report.md` 或任何记忆文件时,优先使用小范围补丁;不要整文件重写。记忆变更和代码变更必须分开说明、分开确认。
若目标记忆目录不存在,输出缺失说明并建议先执行 `memory-sync``memory-update` 初始化。
## Phase 0 - 读取状态
读取:
- `MEMORY.md`
- 记忆目录内全部 `*.md`
- `Base commit`
- `Last synced`
提取索引文件集合 `$INDEX_FILES` 和磁盘文件集合 `$DISK_FILES`
## Phase 1-2 - 孤儿与幽灵检测
| 检查 | 定义 | 级别 | AUTO-FIX |
| --- | --- | --- | --- |
| 孤儿 | 索引有,磁盘无 | ERROR | 从 `MEMORY.md` 删除该条目 |
| 幽灵 | 磁盘有,索引无 | WARN | 补入索引 |
幽灵类型推断(按优先级匹配):
- `synonyms.md`(精确匹配) → reference
- `user_*` → user
- `project_*``decisions.md` → project
- `feedback*` → feedback
- `reference*` → reference
- `synthesis_*` → synthesis
- 其他默认 project
排除 `MEMORY.md``lint_report.md`
## Phase 3 - 交叉引用完整性
### 3A 存在性检测 + 引用计数构建
扫描所有 `[[filename.md#section]]`,构建:
- 引用表:`源文件#源章节 -> 目标文件#目标章节`
- 文件级被引用计数 `$REF_COUNT`(按源文件去重)→ Phase 7 写入 MEMORY.md「引用」列
- decisions 和 feedback 条目级引用计数 `$ITEM_REF_COUNT`(按源文件去重)→ Phase 8 写入 lint_report.md,供 `memory-update` 反向触发消费
| 情况 | 级别 | 动作 |
| --- | --- | --- |
| 目标文件不存在 | ERROR | NEED-HUMAN |
| 目标章节缺失,且存在高相似标题 | WARN | AUTO-FIX 更新引用 |
| 目标章节缺失,且无相似项 | WARN | NEED-HUMAN |
### 3B 对称性检测(双链闭环)
复用 3A 引用表,对每条 `A#x -> B#y` 检查 B 的 `## y` 是否含任意 `[[A` 引用(不要求精确章节)。
- 级别:WARN
- AUTO-FIX:B 的目标章节末尾追加 `**See Also** [[A#x]]`
- 边界:`lint_report.md` 不参与;B 整文件无对 A 任何引用 → AUTO-FIX;B 有引用但不在目标章节 → 仅 WARN 不自动修改
双链 AUTO-FIX 阈值:缺失反链不超过 5 条且涉及文件不超过 3 个时可以自动补齐;超过阈值、跨多个主题、或将触碰 `user_profile.md` / `synthesis_*.md` 时不自动修改,写入 `lint_report.md` 等待确认。
## Phase 4-pre - 等价表述加载
矛盾检测前先加载 `$PROJECT_MEMORY_DIR/synonyms.md`(可选文件):
```bash
[ -f "$PROJECT_MEMORY_DIR/synonyms.md" ] && \
grep -v "^#\|^---\|^$\|^name:\|^description:\|^type:" \
"$PROJECT_MEMORY_DIR/synonyms.md"
# 输出每行一个等价组(逗号分隔),大小写不敏感,存入 $SYNONYMS_GROUPS
```
`synonyms.md` 格式(用户自行在项目内创建和维护):
```markdown
---
name: 等价表述清单
description: 矛盾检测等价词表,同组词视为相同概念
type: reference
---
# 等价表述清单
> 每行一组,逗号分隔,大小写不敏感
PostgreSQL, PG, Postgres, postgresql
JWT, JSON Web Token
```
判定规则:两处描述中出现的技术术语若属同一等价组,跳过,不纳入矛盾候选。无 `synonyms.md` 时,仅检测直接数值/版本冲突,对措辞差异不报告。
## Phase 4 - 内容矛盾
| 维度 | 检查 |
| --- | --- |
| decisions vs feedback | 决策与协作规范是否冲突 |
| decisions vs 架构/依赖文件 | 是否与当前依赖清单(如 `package.json``requirements.txt``pom.xml`)实际内容冲突 |
| 多个 feedback 文件 | 是否重复或矛盾 |
| synthesis vs decisions | 归档结论是否抵触现有决策 |
| 合并残留标记 | 是否含 `<!-- merge-conflict -->` |
矛盾判定门槛(过 synonyms.md 等价检查后):
| 情况 | 处理 |
| --- | --- |
| 同主题,等价组内术语不同 | 跳过,不报告 |
| 同主题,结论相反 | WARN → NEED-HUMAN |
| 同主题,数值或版本直接冲突 | ERROR → NEED-HUMAN |
| 仅措辞不同,无直接逻辑冲突 | 跳过(宁漏报不误报) |
合并残留标记的 NEED-HUMAN 条目必须包含:
- 位置:文件名、章节标题、标记内容。
- Checklist:Q1 当前本地版本是否正确?Q2 另一版本是否有当前版本没有的有效信息?Q3 两者是否可以合并为单一表述?
- 决策矩阵:Q2 否 → 删除 `[合并待审]` 或分歧段落和标记;Q2 是 + Q3 是 → 合并为单一表述后删除标记;Q2 是 + Q3 否 → 保留两段内容,但清除 HTML 标记并说明适用边界。
## Phase 5 - 过期检测(提交速度分档)
不用固定天数二级阈值,改用「自 `last_updated` 以来的全仓库提交速度」判断过期风险的严重程度:高频迭代项目下 7 天未同步就可能已经漂移,低活跃项目下 180 天未动也可能仍然准确。阈值常量由 `memcore-shared` 定义。
```bash
# days_sincelast_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 | 绝对兜底,防止彻底沉寂的记忆永不复查 |
不要只因为日期老就自动刷新 `last_updated`。若内容仍有效,写入 NEED-HUMAN 让用户确认是否仅刷新日期;若内容与项目推进不符,标记为语义过时并给出证据位置。
## Phase 6 - 可推断内容污染
污染特征:大量具体文件路径、类名、方法签名、git 流水账、可从依赖文件直接读取的版本号列表。
**边界**:架构层级描述("认证模块提供 JWT + OAuth2 双协议")保留;具体类名/方法/路径列表删除或建议改写。
## Phase 7 - 执行 AUTO-FIX
只允许修复结构性问题:
1. 移除索引孤儿。
2. 补入索引幽灵。
3. 更新高置信断链引用。
4. 在阈值内补齐双向链接;超过阈值则写入 NEED-HUMAN。
5. 刷新 `MEMORY.md` 的「引用」列(基于 `$REF_COUNT`):表格统一 5 列 `| 文件 | 描述 | 类型 | 引用 | Commit |`;「引用」值 ≥ `SYNTHESIS_THRESHOLD``*`(如 `5*`),否则显示数字;按引用次数倒序排列,同次数按类型序: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_MEMORY_DIR/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)`;若 `id``RESOLVED_IDS` 中则跳过(用户已标记 resolved,本次不再列出);否则写入 `lint_report.md`,并在条目末尾附 `<!-- id: {id} -->`
**用户如何使用**:在 `lint_report.md` 中某个 NEED-HUMAN 条目末尾、`<!-- id: ... -->` 同段内,追加:
```markdown
<!-- resolved: 2026-06-12, 决定保留两者作为历史对比 -->
```
下次 lint 跑到时,发现该 id 在 `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] 更新断链:`[[feedback.md#旧标题]]``[[feedback.md#新标题]]`
- [x] MEMORY.md「引用」列已刷新(N 文件,倒序)
---
## 条目级高频引用 Top(供 memory-update 消费)
跨 ≥ `SYNTHESIS_THRESHOLD` 个不同源文件被引用的 decisions/feedback 条目。无候选时保留标题 + "无候选"。
| 条目 | 跨文件次数 | 建议 |
| --- | --- | --- |
| `decisions.md#示例决策标题` | 4 | 升级为 synthesis_xxx.md |
---
## NEED-HUMAN 待处理清单
每项附 3 问 yes/no checklist + 决策矩阵,避免模糊判断,末尾附 `<!-- id: xxxxxxxx -->`
### [ERROR] 引用断链 — 目标文件不存在
- **位置**`decisions.md → ## 数据库选型``[[synthesis_arch_xxx.md]]`
- **Checklist**Q1 内容是否真实归档过?Q2 git history 能否找到删除/重命名证据?Q3 该引用是「锦上添花」还是「核心支撑」?
- **矩阵**:Q1+Q2 是 → 恢复文件;Q1 是 + Q2 否 → 重新归档;Q1 否 → 删引用;Q3 核心 → 必须二选一不允许保留断链
<!-- id: a1b2c3d4 -->
### [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 -->
```
## Phase 9 - 输出摘要
`memory-sync` 调用:
```
🔍 memory-lintAUTO-FIX N 项,NEED-HUMAN N 项(历史 resolved 跳过 M 项,详见 lint_report.md
```
独立调用:扩展输出已修复 / 待处理清单 + 报告路径;全通过则输出「记忆体系健康,已更新执行时间」。
发现矛盾候选且 `synonyms.md` 不存在时,额外提示:创建 `.claude/memory/synonyms.md`(或对应的 `.codex/memory/synonyms.md``.agents/memory/synonyms.md`)可将等价术语预先排除出矛盾检测,降低误报率。
每次执行必须更新 `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` 再判矛盾;措辞不一致 ≠ 矛盾,宁漏报不误报。
5. 污染检测边界(重申)— 架构层级保留 / 具体类名路径删除。
6. 使用 `.claude/memory/``.codex/memory/` 时只复用现有项目记忆,不复制到 `.agents/memory/`
7. 不访问远程记忆路径,不维护任何跨机器镜像;不 lint Hermes 原生全局记忆(`~/.hermes/memories/`)。
8.`memory-sync` 调用时返回简短摘要;独立调用时输出已修复和待处理清单。
9. 记忆变更和代码变更分开执行;不要把用户未确认的代码修改混入 lint 修复。
@@ -0,0 +1,160 @@
---
name: memory-sync
description: 编排 Hermes 项目本地记忆同步流程:识别现有 CLAUDE.md/.claude/memory 或 AGENTS.md/.codex/memory,确定唯一记忆目录,执行 memory-update 和 memory-lint,维护项目记忆索引和 AGENTS.md 启动引导。用于完整刷新仓库记忆体系。Hermes 版本不使用远程记忆,也不读写 Hermes 原生全局 MEMORY.md/USER.md;若已有 Claude/Codex 记忆内容则直接引用,不重复添加。
---
# memory-sync
执行项目本地记忆体系的完整同步周期。会话目录视为 `$PROJECT_DIR`
**前置约束:先 Read `../memcore-shared/SKILL.md`**(记忆目录选择优先级 + 禁止路径 + Hermes 全局记忆避让规则 + 常量),其约束在本技能全程生效。
## 总流程
```text
Phase 0 确定 PROJECT_MEMORY_DIR(按 memcore-shared 优先级)+ 提醒 Hermes 全局记忆避让规则
Phase 1 Git 和记忆冲突检查
Phase 2 读取现有 Claude/Codex/Hermes 项目记忆
Phase 3 计算 diff 或全量审查范围
Phase 4 调用 memory-update
Phase 5 调用 memory-lint
Phase 6 维护 AGENTS.md 启动引导
Phase 7 完成报告
```
## Phase 0 - 确定 PROJECT_MEMORY_DIR
`memcore-shared` 的选择优先级确定 `PROJECT_MEMORY_DIR`。若最终落在「需要创建 `.agents/memory/`」的分支,向用户说明目录结构并等待确认后再继续。
同时提醒一次(不需要用户回应,写进本次交流即可):本项目事实统一沉淀在 `PROJECT_MEMORY_DIR`Hermes 自己的全局 `~/.hermes/memories/MEMORY.md`/`USER.md` 是跨项目个人记忆层,两者不是一回事,出现内容重复以 `PROJECT_MEMORY_DIR` 为准。
## Phase 1 - Git 和记忆冲突检查
若项目是 git 仓库,先读取:
```bash
git status --short
git rev-parse --show-toplevel
git rev-parse --short HEAD
```
存在未解决冲突时,优先处理记忆目录内的冲突文件。不要自动提交用户未确认的非记忆变更。
非 git 仓库继续执行,commit 字段填 `N/A`
记忆文件冲突采用语义合并,限于 `PROJECT_MEMORY_DIR`
| 冲突类型 | 处理方式 |
| --- | --- |
| frontmatter `last_updated` | 取两者较新日期 |
| frontmatter `commit` | 取当前 HEAD 或本地工作区对应值 |
| `## Section` 两边内容相同 | 保留一份 |
| `## Section` 仅一边存在 | 保留或追加到文件末尾 |
| `## Section` 两边都存在但内容不同 | 保留当前本地版本,将另一版本追加为 `## [合并待审] Section`,标注 `<!-- merge-conflict: YYYY-MM-DD -->` |
| `MEMORY.md` 索引冲突 | 不手工合并,保留当前版本,交给 `memory-lint` 重建索引 |
| `user_profile.md``synthesis_*.md` | 不自动合并,在文件头标注 `<!-- merge-conflict: YYYY-MM-DD, NEED-HUMAN -->` |
合并前应备份冲突文件,备份文件不要提交。完成后提示用户审查 `<!-- merge-conflict -->` 标记,并由 `memory-lint` 写入 NEED-HUMAN。
## Phase 2 - 读取现有记忆
若存在 `MEMORY.md`,先读取索引,再按需加载文件:
- 必读:`decisions.md``feedback*.md``project_progress.md``project_overview.md` 中由索引标为 project 或 feedback 的文件。
- 按需:`user_profile.md``reference.md``synthesis_*.md``lint_report.md`
若只有 `CLAUDE.md`,读取其中与项目约定、记忆体系、开发流程有关的章节,并避免重复生成同类内容。
## Phase 3 - 计算审查范围
`MEMORY.md` 头部读取 `Base commit`。有锚点时使用:
```bash
git diff --name-only $ANCHOR_COMMIT..HEAD
```
无锚点、非 git 仓库或首次初始化时执行全量审查。
## Phase 4 - 调用 memory-update
`memory-update` 的规则增量写入本地记忆文件和 `MEMORY.md` 索引。
要求:
- 只更新本次变化涉及的维度。
- 以 Why、约束、边界和协作规范为主。
- 不记录可从代码直接恢复的明细。
- 若使用 `.claude/memory/``.codex/memory/`,保持原目录,不创建重复的 `.agents/memory/`
## Phase 5 - 调用 memory-lint
`memory-lint` 的规则执行健康检查:
- 修复索引孤儿、幽灵、断链和缺失反向链接。
- 刷新引用计数。
- 生成或更新 `lint_report.md`
- 将内容矛盾、过期、污染和合并残留写入 NEED-HUMAN。
## Phase 6 - 维护 AGENTS.md 启动引导
Hermes 项目的启动引导优先写入 `AGENTS.md`——这也是 Codex 版本共用的同一个文件,两个工具在同一项目下不会各写一份。
处理顺序:
1. 若项目已有 `AGENTS.md`,检查是否存在 `## 记忆体系(会话启动必读)` 区块。
2. 若区块存在且仍与 `MEMORY.md` 一致,只引用,不重复追加。
3. 若区块缺失或过期,先向用户说明将更新的内容,确认后再修改;提取区块内已记录的 commit 锚点(若有),据此判断哪些子章节需要针对性调整,而不是整块重写。
4. 若项目没有 `AGENTS.md` 但已有 `CLAUDE.md``.claude/memory/``.codex/memory/`,默认只引用现有记忆;需要 Hermes 启动引导时,询问用户是否创建 `AGENTS.md`,不要把已有记忆目录复制到 `.agents/memory/`
5. 若项目没有 `AGENTS.md``CLAUDE.md``.claude/memory/``.codex/memory/`,需要项目级 Hermes 引导时创建 `AGENTS.md`,并指向 `.agents/memory/`
6. 不为了 Hermes 强制创建或改写 `CLAUDE.md`
`AGENTS.md` 记忆体系区块模板:
```markdown
## 记忆体系(会话启动必读)
> 新会话或上下文压缩后,必须先读记忆目录的 `MEMORY.md` 索引,再按需加载文件。代码事实与项目记忆冲突时,以代码事实为准并更新项目记忆。
### 读取流程
1. 读取 `{MEMORY_DIR}/MEMORY.md` 获取文件清单、类型和引用计数。
2. **必读锚点**{REQUIRED_MEMORY_FILES}
3. **选读锚点**{OPTIONAL_MEMORY_FILES}
4. 若仓库使用 `.claude/memory/``.codex/memory/`,直接读取该目录;不要复制到 `.agents/memory/`
### 权威优先级
1. 当前代码、配置、测试和真实文件状态。
2. 仓库内项目记忆:`AGENTS.md``CLAUDE.md``.claude/memory/``.codex/memory/``.agents/memory/`
3. Hermes 原生全局 `~/.hermes/memories/`(按 profile 隔离的个人跨项目记忆层,仅作辅助上下文,不是本项目事实来源)。
```
区块生成规则:
- `{MEMORY_DIR}` 必须替换为实际目录:`.claude/memory``.codex/memory``.agents/memory`
- `{REQUIRED_MEMORY_FILES}` 必须来自 `MEMORY.md` 中实际存在的 project/feedback 类型文件,通常包括 `decisions.md``feedback*.md``project_progress.md``project_overview.md`
- `{OPTIONAL_MEMORY_FILES}` 必须来自 `MEMORY.md` 中实际存在的 user/reference/synthesis/lint 类型文件,通常包括 `user_profile.md``reference.md``synthesis_*.md``lint_report.md`
- 已有 `CLAUDE.md` 记忆引导时,`AGENTS.md` 可以指向相同记忆目录,但不要复制正文。
- 任何写入 `AGENTS.md``CLAUDE.md``MEMORY.md` 或记忆文件的动作,都必须先说明变更并等待用户确认。
## Phase 7 - 完成报告
报告包括:
- 使用的记忆目录。
- 是否复用了 `CLAUDE.md``.claude/memory/``.codex/memory/`
- `memory-update` 更新文件数量。
- `memory-lint` AUTO-FIX 和 NEED-HUMAN 数量(含历史已 `<!-- resolved -->` 跳过的数量)。
- 高频引用条目候选 synthesis 升级,来自 `lint_report.md` 的「条目级高频引用 Top」;无候选时写明无候选。
- 是否更新了 `AGENTS.md` 启动引导。
- 未执行项或跳过项,例如未初始化 `.agents/memory/`、未更新 `AGENTS.md`、存在 NEED-HUMAN 待处理、跳过 synthesis 创建。
- 当前 `Base commit`
## 执行约束
1. 项目本地记忆是唯一来源。
2. 不访问或模拟 Claude 远程记忆。
3. 已有 Claude/Codex 项目记忆时复用,不复制、不重复生成。
4. 不读写 Hermes 原生全局 `~/.hermes/memories/`;它们是按 profile 隔离的个人召回层,不是本套项目记忆的后端,也不摘录进项目记忆。
5. `memory-update` 必须先于 `memory-lint`
6. Hermes 启动引导优先维护 `AGENTS.md`;不要为了 Hermes 强制创建或改写 `CLAUDE.md`
7. 修改 `AGENTS.md``CLAUDE.md``MEMORY.md` 或记忆文件前,先说明变更并取得用户确认。
8. 记忆变更和代码变更分开执行;不要把用户未确认的代码修改混入记忆同步。
@@ -0,0 +1,199 @@
---
name: memory-update
description: 根据 git diff 或当前任务上下文,增量更新仓库/项目本地记忆目录和 MEMORY.md 索引。用于把代码变更、架构决策、协作反馈、外部参考和用户偏好沉淀到项目记忆中。Hermes 版本不使用远程记忆,也不写入 Hermes 原生全局 MEMORY.md/USER.md;若仓库已有 CLAUDE.md/.claude/memory/ 或 AGENTS.md/.codex/memory/,直接引用现有记忆内容,不重复创建或复制;否则使用 .agents/memory/。
---
# memory-update
按增量范围更新项目本地记忆。会话目录视为 `$PROJECT_DIR`
**前置约束:先 Read `../memcore-shared/SKILL.md`**(记忆目录选择优先级 + 禁止路径 + Hermes 全局记忆避让规则 + 常量),其约束在本技能全程生效。
修改 `MEMORY_INDEX` 或任何记忆文件时,优先使用小范围补丁;不要整文件重写。记忆变更和代码变更必须分开说明、分开确认。
## Phase 1 - 读取增量锚点
```bash
# 主锚点:MEMORY.md 头部 _Last synced: DATE | Base commit: `HASH`_ → $ANCHOR_COMMIT
ANCHOR_COMMIT=$(grep -oE 'Base commit: `[^`]+`' "$PROJECT_MEMORY_DIR/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_MEMORY_DIR/"*.md 2>/dev/null \
| awk '{print $2}' | sort -u)
if [ -n "$FALLBACK" ]; then
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:` 字段取**最旧值**,确保覆盖所有真实改动而不误判为无差别全量。
`ANCHOR_COMMIT`(含兜底命中)时以该提交作为差量起点;仍为空、非 git 仓库或首次初始化时执行全量审查。
## Phase 2 - 计算变更范围
```bash
[ -n "$ANCHOR_COMMIT" ] && git diff --name-only $ANCHOR_COMMIT..HEAD # → $CHANGED_FILES
```
无锚点时审查当前项目结构、依赖文件、现有记忆文件和本次会话明确产生的信息。
## Phase 3 - 更新记忆文件
### 维度路由($CHANGED_FILES → 目标文件)
| 变更内容 | 写入到 |
| --- | --- |
| 业务代码、模块边界、架构形态 | `project_overview.md``decisions.md` |
| 依赖文件、运行方式、工具链 | `project_overview.md` |
| 进度信号、阶段状态、待办 | `project_progress.md` |
| 用户纠正、协作规范、风格偏好 | `feedback.md``feedback_{topic}.md` |
| 外部 URL、第三方约束 | `reference.md` |
| 用户长期偏好 | `user_profile.md` |
| 高价值分析归档 | `synthesis_{type}_{topic}.md` |
### 文件职责边界
| 文件 | 类型 | 写入 | 不写入 |
| --- | --- | --- | --- |
| `user_profile.md` | user | 角色、背景、长期偏好 | 任务进度 |
| `project_overview.md` | project | 技术栈、架构、目录、约定 | 可从代码直接 grep 的明细 |
| `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
---
```
`type` 可选值包含 `lint``memory-update` 通常不生成 `lint_report.md`,但更新索引时必须能识别 `lint` 类型。
`decisions.md``feedback*.md` 条目格式:
```markdown
## 标题
**结论:** xxx
**Why** 背景、约束、历史教训
**How to apply** 何时适用、边界
**See Also** [[file.md#标题]]
```
`synthesis_*.md` 使用完整文件格式,至少包含 `## 背景``## 分析过程``## 结论``## See Also`
feedback 拆分规则:当同一主题的协作规范超过 5 条,拆分到 `feedback_{topic}.md`,并在原 `feedback.md` 中保留索引或 See Also 引用。一次性修复、临时提醒和已经由代码体现的偏好不要沉淀为 feedback。
### Phase 3A - 交叉引用
新增 decisions 或 feedback 条目时:
1. 扫描记忆目录内其他 Markdown 标题。
2. 主题相关时,在新条目末尾追加 `[[file.md#标题]]`
3. 反向补链:被引用条目也追加对新条目的引用。
### Phase 3B - synthesis 三路触发
当某个 decisions 或 feedback 条目被 `SYNTHESIS_THRESHOLD`(默认 3)个以上不同文件引用,且条目中没有 `**Synthesized:**` 或 30 天内的 `<!-- synthesis-decline: YYYY-MM-DD -->` 标记时,建议升级为 `synthesis_*.md`,并等待用户确认后创建。
1. **会话内主动触发**:出现技术选型对比、Bug 根因分析、架构演进、安全或性能分析时,建议归档为 `synthesis_{type}_{topic}.md`
2. **lint 反向触发**:读取 `lint_report.md` 的「条目级高频引用 Top」,跨 `SYNTHESIS_THRESHOLD` 个以上不同源文件被引用的 decisions/feedback 条目是候选。
3. **即时快扫触发**(见 Phase 3C):每次 update 后扫描 `decisions.md``feedback*.md` 条目引用数,不等待下一次完整 lint。
synthesis 判重和免打扰:
- 条目已有 `**Synthesized:** [[xxx.md]]` 时,视为已升级,不重复创建。
- 条目已有 `<!-- synthesis-decline: YYYY-MM-DD -->` 且未超过 30 天时,不再提醒。
- 用户拒绝单个候选时,在原条目末尾追加 decline 标记。
- 用户选择 `skip-all` 时,本次 update 不再继续建议 synthesis。
- 创建 synthesis 后,在原条目末尾追加 `**Synthesized:** [[synthesis_xxx.md]]`
### Phase 3C - 即时引用计数快扫(不依赖 lint)
每次执行 Phase 3 末尾**强制运行**。目的:在短会话或任务型对话中,不依赖 lint 的延迟触发,直接检测 synthesis 升级候选。
```bash
SYNTHESIS_THRESHOLD=3 # 与 memcore-shared 全局常量保持一致
for entry_file in "$PROJECT_MEMORY_DIR/decisions.md" "$PROJECT_MEMORY_DIR/feedback"*.md; do
[ -f "$entry_file" ] || continue
fn=$(basename "$entry_file")
while IFS= read -r title; do
# 使用 grep -Ffixed string)避免 [[ ]] 在正则中的歧义;-- 防止 title 以 - 开头被误解为选项
count=$(grep -rlF -- "[[${fn}#${title}]]" \
"$PROJECT_MEMORY_DIR/" --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 含中文 / 空格 / 标点时不会破坏匹配。
- 单文件中同标题多次引用按 `-l` 仅记一次(按文件去重)。
对每条输出候选(`count|file#title`):
1. 读原条目内是否含 `**Synthesized:**` → 已升级,跳过。
2. 读原条目内是否含 `<!-- synthesis-decline: YYYY-MM-DD -->` → 30 天内,跳过。
3. 以上均无 → 触发提议(同 Phase 3B step 流程)。
**与 lint 的分工**
- Phase 3C(快扫):每次 memory-update 必跑,判据为「存在引用行数」,适合即时触发。
- lint Phase 3(精扫):按源文件去重的精确计数,健康检查时运行。
- 两者以 `**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` 刷新。
- `引用` 值大于等于 `SYNTHESIS_THRESHOLD` 时加 `*`,例如 `5*`
## 执行约束
1. 最小化更新,只写本次确认的变化维度。
2. 不记录可推断内容,例如完整文件路径列表、方法签名、git 流水账。
3. feedback 同主题超过 5 条时拆分到主题文件。
4. 追加为主,除非内容明确过时或冲突。
5. 如果使用的是 `.claude/memory/``.codex/memory/`,视为复用现有项目记忆;不要迁移、复制或生成重复的 `.agents/memory/`
6. 不把 Hermes 原生全局记忆(`~/.hermes/memories/`)当作可编辑后端;需要跨会话保留的项目事实必须写入仓库/项目内记忆。
7.`memory-sync` 调用时只返回简短摘要;独立调用时输出完整更新摘要。
8. 记忆变更和代码变更分开执行;不要把用户未确认的代码修改混入记忆更新。
@@ -0,0 +1,18 @@
{
"name": "obsidian",
"version": "1.0.0",
"description": "Obsidian 知识库 AI 协作插件族。检测到 .obsidian/ 目录时自动激活全套技能:vault 管理、全文搜索与图谱、frontmatter 元数据、Markdown 任务与 GTD、每日笔记、Bases 数据库视图、Canvas 视觉层、版本历史与恢复、插件与环境配置、PKM 编排工作流共 10 个技能。",
"author": {
"name": "姜顺志"
},
"skills": "./skills",
"interface": {
"displayName": "Obsidian 知识库协作",
"shortDescription": "Obsidian vault 全套协作工作流",
"longDescription": "Obsidian 知识库 AI 协作插件族,检测到项目里的 .obsidian/ 目录后自动激活。覆盖 vault 管理(含 OFM 语法速查)、全文与图谱搜索、frontmatter 元数据、任务与 GTD、每日笔记、Bases 数据库视图、Canvas 视觉层(JSON Canvas 1.0)、版本历史与恢复、插件与环境配置、PKM 编排工作流(含 Web Clip 子流程)十个技能。",
"developerName": "蚁熊团队",
"category": "Productivity",
"capabilities": ["Interactive", "Write"],
"defaultPrompt": "帮我整理一下今天的每日笔记"
}
}
+11
View File
@@ -0,0 +1,11 @@
{
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
"name": "obsidian",
"version": "1.0.0",
"description": "Obsidian 知识库 AI 协作插件族,共十个技能:vault 管理(obsidian,含 OFM 语法速查)、全文搜索与图谱(obsidian-search)、frontmatter 元数据(obsidian-meta)、Markdown 任务与 GTDobsidian-tasks)、每日笔记(obsidian-daily)、Bases 数据库视图(obsidian-bases)、Canvas 视觉层(obsidian-canvas)、版本历史与恢复(obsidian-history)、插件与环境配置(obsidian-plugins)、PKM 编排工作流(obsidian-workflow-pkm)。纯技能,无 MCP,无需任何配置。",
"author": {
"name": "姜顺志"
},
"license": "MIT",
"keywords": ["obsidian", "pkm", "knowledge-management"]
}
@@ -630,7 +630,7 @@ graph TD
| 现象 | 原因 | 对策 |
|------|------|------|
| 工作流中途失败导致状态不一致 | 没有事务 | 先 git checkpoint;失败后从 checkpoint 恢复 |
| Agent 在决策点没等用户 | 没实现交互 | 脚本用 `read -p`Claude Code AskUserQuestion |
| Agent 在决策点没等用户 | 没实现交互 | 脚本用 `read -p`交互式 agent(如 Claude Code AskUserQuestion)用其原生询问机制 |
| 批量处理把同一笔记处理两次 | 没用 idempotent 标记 | 处理完在 frontmatter 加 `processed_by: inbox_workflow` |
| MOC 构建召回漏掉笔记 | 关键词单一 | 用 3~5 个扩展词 + 标签 + 出/反链三路召回 |
| 周报漏数据 | daily note 没写 | 先跑 `obsidian files folder=90-Daily` 检查覆盖 |
+24
View File
@@ -0,0 +1,24 @@
{
"name": "zentao",
"description": "禅道项目管理系统:项目集/产品/项目/执行、需求(story/epic/requirement)、Bug、任务、测试、计划与发布、反馈工单等工作流技能,自动配置 MCP 连接。",
"author": {
"name": "蚁熊团队"
},
"userConfig": {
"token": {
"type": "string",
"title": "禅道 API Token",
"description": "在禅道「个人中心 → 获取凭证」自助生成,14 天有效期,到期需重新生成",
"sensitive": true
}
},
"mcpServers": {
"zentao": {
"type": "http",
"url": "https://pm.ops.yixiong-tech.com/mcp",
"headers": {
"token": "${user_config.token}"
}
}
}
}
+19
View File
@@ -0,0 +1,19 @@
{
"name": "zentao",
"version": "1.0.0",
"description": "禅道项目管理系统插件,含项目集/产品/项目/执行、需求、Bug、任务、测试、计划与发布、反馈工单八个工作流技能,自动配置 MCP 连接。",
"author": {
"name": "蚁熊团队"
},
"skills": "./skills",
"mcpServers": "./.mcp.json",
"interface": {
"displayName": "禅道",
"shortDescription": "禅道项目/需求/Bug/任务/测试工作流",
"longDescription": "禅道项目管理系统插件:覆盖项目集、产品、项目、执行、需求(story/epic/requirement)、Bug、任务、测试用例与测试单、产品计划、版本、发布、反馈、工单等工作流技能。安装后需在禅道「个人中心 → 获取凭证」自助生成 14 天有效期的 Token,并配置为环境变量 ZENTAO_TOKEN。",
"developerName": "蚁熊团队",
"category": "Productivity",
"capabilities": ["Interactive", "Write"],
"defaultPrompt": "帮我看看我名下有哪些未解决的 Bug 和任务"
}
}
+9
View File
@@ -0,0 +1,9 @@
{
"mcpServers": {
"zentao": {
"type": "http",
"url": "https://pm.ops.yixiong-tech.com/mcp",
"bearer_token_env_var": "ZENTAO_TOKEN"
}
}
}
+11
View File
@@ -0,0 +1,11 @@
{
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
"name": "zentao",
"version": "1.0.0",
"description": "禅道项目管理系统:项目集/产品/项目/执行、需求(story/epic/requirement)、Bug、任务、测试、计划与发布、反馈工单等工作流技能。MCP Token 需手动配置,详见仓库 README。",
"author": {
"name": "蚁熊团队"
},
"license": "MIT",
"keywords": ["zentao", "productivity", "project-management"]
}
+96
View File
@@ -0,0 +1,96 @@
---
name: zentao-bug
description: "禅道 Bug 管理:创建、查询、解决、关闭、激活 Bug。当用户说「提个 bug」「这个 bug 修好了」「bug 关掉」「查一下未解决的 bug」时使用。"
---
# 禅道 Bug 管理
**前置:先读 `zentao-shared`(尤其"路径参数不出现在 inputSchema 里"一节)。**
---
## 状态机
```
激活(open) ──resolve 解决──▶ 已解决(resolved) ──close 关闭──▶ 已关闭(closed)
▲ │
└──────────────────── activate 激活(重新打开)────────────────┘
```
`close` 也可以直接对一个未解决的 bug 使用(跳过 resolve 直接关闭,比如确认不是真实
问题),但更常见的路径是先 resolve 再 close。
---
## 查
```
get_products_productID_bugs(productID, ...)
get_projects_projectID_bugs(projectID, ...)
get_executions_executionID_bugs(executionID, ...)
get_bugs_bugID(bugID) 详情
```
用户问"未解决的 bug"时先确认要看哪个维度(产品/项目/执行),三个列表接口过滤范围不同。
---
## 建
```
post_bugs({ payload: { productID, title, openedBuild, project?, execution?, severity?,
pri?, type?, steps?, story? } })
```
`productID`/`title`/`openedBuild` 三个必填——**`openedBuild`(影响版本)容易漏**
不是可选项,**是字符串数组**,元素是版本 ID,主干传 `["trunk"]`(不是单个字符串
`"trunk"`),可以同时关联多个版本。
`type`Bug 类型)受限枚举:`codeerror` 代码错误 | `config` 配置相关 | `install` 安装部署
| `security` 安全相关 | `performance` 性能问题 | `standard` 标准规范 | `automation` 测试脚本
| `designdefect` 设计缺陷 | `others` 其他。
`severity`(严重程度)/`pri`(优先级)不传默认都是 3。
`story` 字段可以关联一个相关需求(story ID)。
---
## 解决(resolve
```
put_bugs_bugID_resolve({ bugID, payload: { resolution, resolvedDate?, resolvedBuild?,
assignedTo?, comment? } })
```
`resolution` 必填,受限枚举:`fixed` 已解决 | `notrepro` 无法重现 | `bydesign` 设计如此 |
`duplicate` 重复Bug | `external` 外部原因 | `postponed` 延期处理 | `willnotfix` 不予解决 |
`tostory` 转为需求。
**先跟用户确认具体是哪种解决方式再调用**`zentao-shared` 全局约定:状态流转类操作先
确认)——`fixed``willnotfix`/`notrepro` 对提交者的观感完全不同,不要因为用户说
"这个处理一下"就默认填 `fixed``tostory` 这个选项比较特殊,选它意味着这个 bug 会被
转成一条需求,用之前跟用户确认清楚是不是真的要转。
---
## 关闭(close/ 激活(activate
```
put_bugs_bugID_close({ bugID, payload: { comment? } })
put_bugs_bugID_activate({ bugID, payload: { openedBuild?, assignedTo?, comment? } })
```
都没有必填字段。关闭前确认这个 bug 确实该关了(比如已经 resolve 过,或者提交者认可
不是真实问题);激活是把已关闭/已解决的 bug 重新打开,一般用于验证不通过要打回。
---
## 改 / 删
```
put_bugs_bugID({ bugID, payload: {...} })
delete_bugs_bugID({ bugID })
```
删除不可逆,执行前必须确认。
+101
View File
@@ -0,0 +1,101 @@
---
name: zentao-misc
description: "禅道反馈、工单、应用管理、附件改名。当用户说「提个反馈」「开个工单」「工单关掉」「建个应用」「改一下附件名字」时使用。"
---
# 禅道反馈 / 工单 / 应用 / 附件
**前置:先读 `zentao-shared`(尤其"路径参数不出现在 inputSchema 里"一节)。**
---
## 反馈(feedback
```
get_products_productID_feedbacks(productID, ...)
get_feedbacks_feedbackID(feedbackID)
post_feedbacks({ payload: { product, title, module?, type?, desc?, feedbackBy?, source? } })
put_feedbacks_feedbackID({ feedbackID, payload: {...} })
delete_feedbacks_feedbackID({ feedbackID })
put_feedbacks_feedbackID_close({ feedbackID, payload: { closedReason, comment? } })
put_feedbacks_feedbackID_activate({ feedbackID, payload: {...} })
```
**创建字段名注意:所属产品叫 `product`,不是 `productID`**(跟大多数其他实体不一致,
`zentao-plan` 的 build/release 也是这个坑)。
**"没有反馈/工单"和"参数传错"在这两个接口上长得一模一样**:实测发现某个产品下没有
反馈/工单记录时,后端返回的是 `HTTP 200` + **完全空的响应体**,跟 `zentao-shared` 里说的
"路径参数传漏/传错 → 静默返回空结果"是同一种表现。`zentao-shared` 那条"先怀疑参数
传漏了,再怀疑数据本身"的排查顺序在这两个接口上不管用——换任何一个真实存在的
`productID` 都可能一样是空的。真要鉴别,换个已知有数据的接口(比如 `get_products`
确认这个 productID 本身没写错,或者直接问用户这个产品下是否本来就没有反馈/工单。
`type`(反馈类型)受限枚举:`story` 需求 | `task` 任务 | `bug` Bug | `todo` 待办 |
`advice` 建议 | `issue` 问题 | `risk` 风险 | `opportunity` 机会——这个类型决定了反馈
可能被后续转化成对应的实体,跟用户确认清楚类型再提交。
`closedReason` 关闭必填,受限枚举:`commented` 已处理 | `repeat` 重复 | `refuse` 不予采纳。
关闭前按 `zentao-shared` 全局约定跟用户确认原因。
---
## 工单(ticket
```
get_products_productID_tickets(productID, ...)
get_tickets_ticketID(ticketID)
post_tickets({ payload: { product, title, module?, type?, desc?, assignedTo?, deadline?,
openedBuild? } })
put_tickets_ticketID({ ticketID, payload: {...} })
delete_tickets_ticketID({ ticketID })
put_tickets_ticketID_close({ ticketID, payload: { closedReason, comment } })
put_tickets_ticketID_activate({ ticketID, payload: {...} })
```
同样是 `product` 不是 `productID``type`(工单类型)受限枚举:`code` 程序报错 |
`data` 数据错误 | `stuck` 流程卡断 | `security` 安全问题 | `affair` 事务。
`openedBuild`(影响版本)**是字符串数组**,可以关联多个版本,不是单个 ID,跟 `zentao-bug`
`openedBuild` 的数组结构是同一个模式。
**关闭工单 `closedReason` 和 `comment` 都必填**(反馈关闭只要求 `closedReason`,工单
两个都要)——`closedReason` 枚举:`commented` 已处理 | `repeat` 重复 | `refuse` 不予处理。
---
## 应用(system
```
get_products_productID_systems(productID, ...)
post_systems({ payload: { productID, integrated, children, name, desc? } })
put_systems_systemID({ systemID, payload: {...} })
```
**没有查询单条应用详情、也没有删除应用的接口**(只有创建/修改),这跟其他实体都不一样,
需要删除或者查看单条详情要引导用户去网页端。
**`get_products_productID_systems` 实测对部分账号会返回 `HTTP 403 Access not allowed`**——
应用管理看起来受账号权限控制,不是所有 Token 都能查。403 时先怀疑是权限不够(提示用户
去禅道网页确认自己有没有应用管理权限),不要当成参数错误去排查。
四个必填字段里 `integrated`(是否集成应用:`0` 否 | `1` 是)和 `children`(集成应用需要
包含哪些其他应用的 ID 列表,非集成应用传空数组 `[]`)都容易漏传——创建前先问清楚这个
应用是不是"集成应用"(把多个子应用打包发布的那种),决定这两个字段怎么填。
---
## 附件改名(file
```
put_files_fileID({ fileID, payload: { fileName } })
```
**这套 MCP 工具里附件相关能力只有改名这一个**`zentao-shared` 已提过):上传新附件、
删除附件都不在工具列表里,需要引导用户去网页端操作。`fileName` 必填,改名会连带更新
附件的扩展名(如果新文件名里带了不同的后缀)。
@@ -0,0 +1,84 @@
---
name: zentao-plan
description: "禅道产品计划、版本(build)、发布(release)管理。当用户说「排个产品计划」「打个包」「建个版本」「发布上线」时使用。"
---
# 禅道产品计划 / 版本 / 发布
**前置:先读 `zentao-shared`(尤其"路径参数不出现在 inputSchema 里"一节)。**
---
## 三者关系
```
productplan 产品计划(做什么、什么时候做)
build 版本/构建(某次打包产出,挂在执行下)
release 发布(把某个/某几个 build 正式对外发布)
```
三者是独立管理的实体,不是严格的父子层级——`release` 通过 `build` 字段关联具体的构建,
`build` 通过 `executionID` 关联执行、`system` 关联应用,`productplan` 只挂产品,不关联
执行/构建。
---
## 产品计划(productplan
```
get_products_productID_productplans(productID, ...)
get_productplans_planID(planID) 详情——注意参数叫 planID,不是 productplanID
post_productplans({ payload: { productID, title, parent?, begin?, end?, branchID?, desc? } })
put_productplans_productplanID({ productplanID, payload: {...} }) # 改用的是 productplanID
delete_productplans_productplanID({ productplanID })
```
**详情接口和改/删接口的路径参数名不一样**`planID` vs `productplanID`),照抄各自工具
名对应的字面参数名。`productID`/`title` 必填,`parent` 可以挂一个父计划形成层级。
---
## 版本 / 构建(build
```
get_projects_projectID_builds(projectID, ...)
get_executions_executionID_builds(executionID, ...)
post_builds({ payload: { executionID, product, name, system, builder, date,
scmPath?, filePath?, desc? } })
put_builds_buildID({ buildID, payload: {...} })
delete_builds_buildID({ buildID })
```
必填字段比较多:`executionID`(注意是 `executionID` 不是 `execution`)、`product`
(注意是 `product` 不是 `productID`)、`name``system`(所属应用,需要先有
`zentao-misc` 里的应用 ID)、`builder`(构建者)、`date`(打包日期)——**字段名在不同
实体间不统一是这套 API 的通病**(`zentao-task` 也提过 name/title、executionID/execution
的不一致),创建前对照该工具自己的 inputSchema 逐个字段确认,不要照抄其他实体的字段名。
没有单条版本详情接口,从列表里过滤。
---
## 发布(release
```
get_products_productID_releases(productID, ...)
post_releases({ payload: { productID, system, name, build, date, status?, desc? } })
put_releases_releasID({ releasID, payload: {...} }) # 注意参数叫 releasID,不是 releaseID
delete_releases_releasID({ releasID })
```
必填:`productID`/`system`(所属应用)/`name`(应用版本号)/`build`(包含的构建,**是字符
串数组**,可以关联多个构建,不是单个 ID)/`date`(计划发布日期)。
`status` 受限枚举:`wait` 未开始 | `normal` 已发布 | `fail` 发布失败 | `terminate` 停止维护
——不像 bug/task 有专门的状态流转端点,发布状态直接在创建/修改时传 `status` 字段设置,
改状态就是 `put_releases_releasID({ releasID, payload: { status: "normal" } })`
**没有单条发布详情接口**,从 `get_products_productID_releases` 列表里过滤。
**参数名注意**:路径参数字面拼写是 `releasID`(缺一个 `e`),跟 testcase 的 `testcasID`
是同一类官方 API 拼写坑,照抄不要纠正。
@@ -0,0 +1,117 @@
---
name: zentao-project
description: "禅道项目集/产品/项目/执行管理:建项目集、建产品、建项目、建执行(迭代)、查层级关系。当用户说「建个产品」「开个新迭代」「这个项目集下有哪些产品」「项目状态」时使用。"
---
# 禅道项目集 / 产品 / 项目 / 执行
**前置:先读 `zentao-shared`(尤其"路径参数不出现在 inputSchema 里"和"ID 层级关系"两节)。**
---
## 层级与挂靠关系
```
program 项目集(可选层)
└─ product 产品(program 可选,可以不挂任何项目集独立存在)
└─ project 项目(products 关联字段可选,parent 挂项目集也可选)
└─ execution 执行/迭代(project 必填,execution 必须先有 project
```
**只有 execution 是强制要有上级的**`project` 字段必填);product 和 project 的上级
关联都是可选字段,不要假设"没传 program 就建不了产品"。
---
## 查
```
get_programs() 项目集列表
get_programs_programID_products(programID) 某项目集下的产品
get_programs_programID_projects(programID) 某项目集下的项目
get_products() 产品列表(全量)
get_products_productID(productID) 产品详情
get_projects() 项目列表(全量,无单条详情接口)
get_projects_projectID_executions(projectID) 某项目下的执行/迭代
get_executions() 执行列表(全量)
get_executions_executionID(executionID) 执行详情
```
**没有 `get_projects_projectID`**(项目详情接口不存在,见 `zentao-shared`),要看单个
项目信息从 `get_projects()` 列表里按 ID 过滤。
---
## 建项目集
```
post_programs({ payload: { name, begin, end, PM?, desc? } })
```
`name`/`begin`/`end` 必填,日期格式以字段说明为准(一般是 `YYYY-MM-DD`)。
---
## 建产品
```
post_products({ payload: { name, program?, line?, type?, PO?, QD?, RD?, reviewer?,
acl?, desc? } })
```
只有 `name` 必填。`type` 取值受限:`normal` 正常 | `branch` 多分支 | `platform` 多平台;
`acl``open` 公开 | `private` 私有——这两个字段写错值会被后端拒绝,不要凭直觉编。
---
## 建项目
```
post_projects({ payload: { name, model, begin, end, workflowGroup, products?, parent?, PM? } })
```
必填字段比产品多:`name`/`model`/`begin`/`end`/`workflowGroup`
`model`(项目管理方式)取值受限,创建前跟用户确认清楚要哪种:
`scrum` 敏捷 | `waterfall` 瀑布 | `kanban` 看板 | `agileplus` 融合敏捷 | `waterfallplus` 融合瀑布
`workflowGroup`(项目流程)是付费版功能,开源版可以不传/传空。
`parent` 是挂靠到哪个项目集(可选);`products` 是关联的产品(可选,接受多个)。
---
## 建执行(迭代)
```
post_executions({ payload: { project, name, begin, end, lifetime?, days?, products?,
plans?, PO?, QD?, PM?, RD?, acl? } })
```
`project`/`name`/`begin`/`end` 必填——**`project` 必填意味着建执行前必须先有一个项目
ID**,用 `get_projects()` 查出来给用户确认要挂在哪个项目下。
`lifetime`(执行类型)取值:`short` 短期 | `long` 长期 | `ops` 运维。
`plans`(关联计划)如果要传,格式是"产品 ID + 计划 ID"的二维数组,不是单纯的 ID 列表,
具体结构以工具 inputSchema 为准。
---
## 改 / 删
```
put_programs_programID({ programID, payload: {...} })
put_products_productID({ productID, payload: {...} })
put_projects_projectID({ projectID, payload: {...} })
put_executions_executionID({ executionID, payload: {...} })
delete_programs_programID({ programID }) # 删除前必须确认,不可逆
delete_products_productID({ productID })
delete_projects_projectID({ projectID })
delete_executions_executionID({ executionID })
```
删除任意一层,其下挂靠的产品/项目/执行/需求/任务等大概率会受影响(具体级联行为以
禅道后端实际处理为准,MCP 这层不做二次拦截)——删除前跟用户明确说清楚删的是哪一层、
可能影响下面挂了什么,参考 `zentao-shared` 的"删除是不可逆操作"约定。
@@ -0,0 +1,153 @@
---
name: zentao-shared
description: "禅道 MCP 共享基础:payload 包装约定、路径/查询参数规则、ID 层级关系、状态字段规则、确认约定。所有 zentao-* 技能必须先读本文件。"
---
# 禅道 MCP 共享规则
所有 `zentao-*` 技能的**必读前置**。
---
## 一条最重要的约定:参数以工具自身的 inputSchema 为准
**本文件与各技能文档都不重画完整字段表。** 每个工具的字段名、必填项、取值范围以它在 MCP
里注册的 `inputSchema`/`description` 为唯一真相;技能只描述**调用顺序、ID 如何传递、
payload 怎么包、哪里必须停下来等用户确认**。
> 上一代其他插件(寰汐)踩过这个坑:技能文档手画参数表,字段名/枚举值/必填项跟后端
> docstring 逐渐漂移,用户侧表现为频繁的「参数缺失」报错。工具签名变了而文档没跟上,
> 是必然发生而非可能发生的事——禅道这边直接不画表,从源头避免。
---
## 工具命名
Claude Code 里工具名带前缀:`mcp__zentao__post_bugs`;其他平台通常是裸名 `post_bugs`
本文档统一写**裸名**,实际调用时按你所在平台的约定加前缀。
命名规律是 `{method}_{路径按 / 拆分拼接}`,路径参数去掉冒号:
```
GET /bugs/:bugID → get_bugs_bugID
POST /bugs → post_bugs
PUT /tasks/:taskID/start → put_tasks_taskID_start
DELETE /stories/:storyID → delete_stories_storyID
GET /products/:productID/stories → get_products_productID_stories
```
---
## 路径参数完全不出现在 inputSchema 里(最隐蔽的坑)
**`inputSchema` 里只有 `payload`(有请求体的话)和 query 参数,路径参数(`bugID`/
`productID`/`taskID`……)不会被声明为任何属性**——用真实工具现场验证过:
`get_bugs_bugID`/`delete_bugs_bugID`/`get_products_productID``inputSchema.properties`
都是空的。想传路径参数,**必须自己从工具名最后一段解析出参数名**(`get_bugs_bugID`
要传 `bugID`),schema 本身看不出这个要求。
**更麻烦的是不传或传错不会报错**:现场测试 `get_bugs_bugID({})`(故意不传 `bugID`
返回的是 `HTTP 200`、内容为空字符串,跟正常"这个 ID 查不到东西"长得一样,非常容易被
误判成"这条数据不存在"而不是"参数传漏了"。调用返回空结果时,**先检查是不是路径参数
传漏了或传错了名字**,再怀疑数据本身。
**命名还有例外,不能全靠"猜工具名去掉动词就是参数名"**`get_epics_storyID` /
`get_requirements_storyID`(业务需求/用户需求详情)的路径参数**字面就叫 `storyID`**
不是更直觉的 `epicID`/`requirementID`——这是禅道官方 API 本身的历史命名,照抄字面
参数名,不要自己"纠正"。
---
## 参数结构:payload 包装约定
请求体字段也**不会摊平在 inputSchema 顶层**,而是统一包在一个 `payload` 对象里;
路径参数(上一节说的,虽然不在 schema 里但仍要传)和 query 参数才是顶层字段。三种形态:
```
POST(新建,无路径参数):
post_bugs({ payload: { productID: 2, title: "...", openedBuild: ["trunk"] } })
PUT(改,带路径参数):
put_bugs_bugID({ bugID: 123, payload: { title: "..." } })
put_tasks_taskID_start({ taskID: 456, payload: { realStarted: "2026-08-25" } })
GET(查,query 参数摊平在顶层,没有 payload——这类工具可选参数多,其余技能文档统一用
"函数签名速查"写法举例,不是真的按位置传参,仍然是每个字段按名字传):
get_products_productID_stories(productID: 2, browseType: "allstory", recPerPage: "50", pageID: "1")
DELETE(删,通常只有路径参数):
delete_bugs_bugID({ bugID: 123 })
```
**把 body 字段错误地摊平到顶层(不包 payload)是最常见的调用失败原因**,报错通常表现为
"参数缺失"——先检查是不是漏包了 `payload`
---
## 分页
**不是所有 GET 都分页**,列表类接口(约一半)才有,详情类没有。有的话固定是这两个参数:
- `recPerPage`:每页数量,不超过 1000
- `pageID`:页码,从第 1 页开始
**没有 `limit` 这个参数名**——传了不存在的参数名会被静默丢弃(不报错、不生效),日志里
`upstream_query_params` 会是空的,看起来"调用成功但没起作用",容易误判。默认页大小以
具体工具的 inputSchema 说明为准,不要凭经验假设。
---
## ID 层级关系
```
program 项目集(可选,product 不强制挂靠)
└─ product 产品(创建只需 name 必填,program/其他都可选)
├─ project 项目(创建必填 name/model/begin/end/workflowGroupmodel 取值受限:
│ scrum 敏捷 | waterfall 瀑布 | kanban 看板 | agileplus 融合敏捷 | waterfallplus 融合瀑布)
│ └─ execution 执行/迭代(创建必填 project,即 execution 必须先有 project 才能建,
│ 不能直接挂在 product 下)
├─ story 用户故事 / epic 业务需求 / requirement 用户需求(三条需求线,见 zentao-story
├─ bug
├─ testcase 测试用例 / testtask 测试单
├─ productplan 产品计划 / build 版本 / release 发布
├─ feedback 反馈 / ticket 工单 / system 应用
└─ task 任务(挂在 execution 下)
```
创建下级实体前,先查上级列表拿到 ID 展示给用户确认,不要凭名字猜 ID(`get_products`
`get_products_productID_stories` 这类"先列表后详情/子资源"的两步调用是常态)。
**没有 `GET /projects/:projectID` 单条项目详情接口**——只有 `get_projects` 列表,要看
某个项目的信息,从列表里按 ID 过滤,不要尝试拼一个不存在的详情工具名。
---
## 状态字段
**禅道各实体的状态是模块内固定的字符串常量**,不是可配置的两层模型——具体取值以对应
工具的字段说明为准(比如 story 是 `draft/active/closed/change`bug 是否 resolved/closed
各有专门的 `put_*_*ID_resolve` / `put_*_*ID_close` 端点)。**不要凭直觉写状态字符串**,
这些字段大多有 DB 级约束,写错直接报错,具体状态机在各自的 zentao-story/zentao-bug/
zentao-task 里有说明。
---
## 鉴权
MCP 连接用的 Token 在禅道网页「头像下拉菜单 → 获取凭证」自助生成,**14 天有效期**,到期
需要重新生成并更新插件配置里的 Token。如果调用突然全部 401,先怀疑 Token 过期。
---
## 全局确认约定
1. **状态流转类操作必须先确认**:关闭(close)、解决(resolve)、激活(activate)、
变更(change)这类端点,执行前把要提交的内容/目标状态展示给用户,等到明确确认
"确认"、"关闭它"、"好的")再调。不要因为用户说了"这个 bug 修完了"就顺手把
resolve 也做了——修复和标记解决是两个决定。
2. **删除是不可逆操作,必须先确认**:所有 `delete_*` 工具删的都是真实数据,没有回收站,
执行前明确告知会删除什么。
3. **先解析 ID 再操作**:需要 `productID`/`executionID`/`taskID` 这类 ID 的操作,先用
对应的 `get_*` 列表工具查出来给用户看,不要凭名字或印象猜 ID。
4. **附件目前只支持改名**`put_files_fileID` 只能改附件文件名(`fileName` 字段),
上传和删除附件不在这套 MCP 工具里,需要引导用户去网页端操作。
+129
View File
@@ -0,0 +1,129 @@
---
name: zentao-story
description: "禅道需求管理:用户故事(story)、业务需求(epic)、用户需求(requirement)三条需求线的创建、变更、关闭、激活。当用户说「提个需求」「这个需求变更一下」「需求关闭了」「史诗需求」时使用。"
---
# 禅道需求管理(story / epic / requirement
**前置:先读 `zentao-shared`(尤其"路径参数不出现在 inputSchema 里"一节——本技能的
`get_epics_storyID`/`get_requirements_storyID` 就是那条规则里点名的例外命名)。**
---
## 三条需求线是什么关系
禅道把"需求"拆成三种独立实体,**不是同一张表的三个状态**,是三套平行的 API:
| | 中文 | 路径前缀 | 典型用途 |
|---|---|---|---|
| story | 用户故事 | `/stories` | 敏捷开发里最常用的最小需求单元 |
| epic | 业务需求 | `/epics` | 更粗粒度、跨多个 story 的业务目标 |
| requirement | 用户需求 | `/requirements` | 来自用户侧的原始需求,未必等于最终交付的 story |
三者创建字段结构完全一样(`productID`/`title` 必填,`pri`/`module`/`parent`/`estimate`/
`spec`/`category`/`source`/`verify`/`assignedTo`/`reviewer` 可选),管理动作也对称
(改 / 变更 change / 关闭 close / 激活 activate / 删除),**用户说"需求"时先确认是要
哪一种**,不要默认都当 story 处理——三者互不包含,建错类型对方看不到。
---
## 详情接口的路径参数命名例外(必读)
```
get_stories_storyID(storyID) 需求详情
get_epics_storyID(storyID) 业务需求详情 —— 参数字面叫 storyID,不是 epicID
get_requirements_storyID(storyID) 用户需求详情 —— 参数字面叫 storyID,不是 requirementID
```
这是禅道官方 API 本身的命名(不是这个 MCP 网桥引入的),照抄传 `storyID` 就行,别自己
"纠正"成语义上更合理的名字,传错名字会静默返回空结果(见 `zentao-shared`)。
---
## 查
```
get_products_productID_stories(productID, browseType?, orderBy?, recPerPage?, pageID?)
get_projects_projectID_stories(projectID, ...)
get_executions_executionID_stories(executionID, ...)
get_products_productID_epics(productID, ...)
get_products_productID_requirements(productID, ...)
```
`browseType` 常见取值:`allstory` 全部 | `assignedtome` 指派给我 | `openedbyme` 我创建 |
`reviewbyme` 待我评审 | `draftstory` 草稿——不传默认是 `unclosed`(未关闭的)。
---
## 建
```
post_stories({ payload: { productID, title, pri?, module?, parent?, estimate?, spec?,
category?, source?, verify?, assignedTo?, reviewer?,
project?, execution? } })
post_epics({ payload: { productID, title, ... 同上(无 project/execution } })
post_requirements({ payload: { productID, title, ... 同上(无 project/execution } })
```
`productID`/`title` 必填,其余可选。`reviewer` 一旦设置,**该需求就必须经过评审**——
问清楚用户是否真的需要评审流程再决定填不填。`category`/`source` 是受限枚举(类别/来源),
取值以工具 description 为准,写错直接报错。
只有 story 能挂 `project`/`execution`(关联具体项目或迭代),epic/requirement 没有这两个字段。
---
## 变更(change
```
put_stories_storyID_change({ storyID, payload: { reviewer, title?, spec?, verify? } })
put_epics_epicID_change({ epicID, payload: { reviewer, title?, spec?, verify? } })
put_requirements_requirementID_change({ requirementID, payload: { title?, spec?, verify? } })
```
**`reviewer` 必填这条规则只对 story 和 epic 成立**——变更这两类需求必须指定评审人,
不能跳过评审直接改。**requirement 的变更接口没有 `reviewer` 这个参数,也没有任何必填
字段**,三者看起来对称,实际上 requirement 少一层评审约束,不要照搬 story/epic 的调用
方式给 requirement 传 `reviewer`(传了会被当成多余字段,不生效)。
注意这里改的路径参数名恢复正常(`epicID`/`requirementID`),跟上面"详情接口"那个
`storyID` 例外命名不是一回事,两套接口的路径参数名不一样,调用前对照工具名确认。
---
## 关闭(close
```
put_stories_storyID_close({ storyID, payload: { closedReason, comment? } })
```
`closedReason` 必填,受限枚举:`done` 已完成 | `subdivided` 已拆分 | `duplicate` 重复 |
`postponed` 延期 | `willnotdo` 不做 | `cancel` 已取消 | `bydesign` 设计如此。
**关闭前必须先跟用户确认关闭原因**`zentao-shared` 的全局约定:状态流转类操作先确认),
不要因为用户说"这个需求做完了"就自动挑一个理由关掉——`done` 和用户实际想表达的可能
不是一回事(比如其实是想选 `subdivided` 已拆成子需求)。
---
## 激活(activate
```
put_stories_storyID_activate({ storyID, payload: { assignedTo?, comment? } })
put_epics_epicID_activate({ epicID, payload: { assignedTo?, comment? } })
put_requirements_requirementID_activate({ requirementID, payload: { assignedTo?, comment? } })
```
三者字段结构一样,都没有必填字段,用于把已关闭/已拆分的需求重新打开。
---
## 删
```
delete_stories_storyID({ storyID })
delete_epics_epicID({ epicID })
delete_requirements_requirementID({ requirementID })
```
不可逆,删除前必须确认(`zentao-shared` 全局约定)。
+103
View File
@@ -0,0 +1,103 @@
---
name: zentao-task
description: "禅道任务管理:创建任务、启动、完成、关闭、激活,查执行下的任务列表。当用户说「建个任务」「这个任务开始做了」「任务做完了」「任务关掉」时使用。"
---
# 禅道任务管理
**前置:先读 `zentao-shared`(尤其"路径参数不出现在 inputSchema 里"一节)。**
---
## 状态机
```
未开始 ──start 启动──▶ 进行中 ──finish 完成──▶ 已完成
│ │
└──────── close 关闭 ─────┘(不做了/取消,跳过完成)
activate 激活(重新打开,从已完成/已关闭回到进行中)
```
---
## 字段名坑:跟 story/bug 不一致
**任务标题字段叫 `name`,不是 `title`**story/bug/epic/requirement 都是 `title`
只有 task 是 `name`,创建时容易写错)。
**创建任务时所属执行的字段叫 `executionID`**,不是 `execution`bug 创建时挂执行用的
`execution`)——同一个"所属执行"的语义,在不同实体的创建接口里字段名不统一,
调用前对照该工具自己的 inputSchema,不要照抄别的实体的字段名。
---
## 查
```
get_executions_executionID_tasks(executionID, ...) 某执行下的任务列表
get_tasks_taskID(taskID) 任务详情
```
任务只能按"所属执行"维度查列表,没有按产品/项目查任务的接口——要看某个产品下的任务,
先找到相关执行再查。
---
## 建
```
post_tasks({ payload: { name, executionID, type?, assignedTo?, estStarted?, deadline?,
pri?, estimate?, module?, story?, desc? } })
```
`name`/`executionID` 必填。`story` 字段可以关联到具体需求(story ID),常用于"这个
任务是为了实现哪个需求"。
---
## 启动(start
```
put_tasks_taskID_start({ taskID, payload: { realStarted, assignedTo?, consumed?, left?, comment? } })
```
`realStarted`(实际开始日期)必填。
---
## 完成(finish
```
put_tasks_taskID_finish({ taskID, payload: { currentConsumed, realStarted, finishedDate,
assignedTo?, consumed?, comment? } })
```
**三个必填字段**`currentConsumed`(本次消耗)、`realStarted`(实际开始,即使之前
`start` 过也要再传一次)、`finishedDate`(实际完成日期)。完成前把这三个数字/日期跟
用户确认清楚(`zentao-shared` 全局约定:状态流转类操作先确认),尤其 `currentConsumed`
容易被和"总计消耗 `consumed`"搞混——前者是这一次填报的增量工时,后者是累计总工时,
两个都传的话以工具说明为准判断二者关系,不要凭直觉认为两者相等。
---
## 关闭(close/ 激活(activate
```
put_tasks_taskID_close({ taskID, payload: { comment? } })
put_tasks_taskID_activate({ taskID, payload: { left?, assignedTo?, comment? } })
```
都没有必填字段。`close` 用于跳过完成流程直接终止任务(比如需求取消了);`activate`
把已完成/已关闭的任务重新打开,可以顺带更新预计剩余工时 `left`
---
## 改 / 删
```
put_tasks_taskID({ taskID, payload: {...} })
delete_tasks_taskID({ taskID })
```
删除不可逆,执行前必须确认。
+122
View File
@@ -0,0 +1,122 @@
---
name: zentao-test
description: "禅道测试管理:创建/查询/修改测试用例(含步骤设计)、创建测试单提测。当用户说「写个测试用例」「设计测试步骤」「提测」「建个测试单」「查测试用例」时使用。"
---
# 禅道测试管理(testcase / testtask
**前置:先读 `zentao-shared`(尤其"路径参数不出现在 inputSchema 里"一节)。**
测试相关是高频场景——测试同学写用例、开发/测试提测,这个技能覆盖得比其他业务域更细,
尤其是 testcase 的步骤结构,是全部 8 个技能里**唯一一处需要特别小心的嵌套/对应关系**。
---
## 测试用例(testcase
### 详情接口的路径参数命名例外(跟 zentao-story 的 storyID 是同类坑)
```
get_testcases_caseID(caseID) 详情:参数字面叫 caseID
put_testcases_testcasID(...) 修改:参数字面叫 testcasID(注意,是 testcasID 不是 testcaseID,少一个 e
delete_testcases_testcasID(...) 删除:同上
```
三个接口的路径参数名互相都不一样(`caseID` / `testcasID`),且 `testcasID` 是官方 API
的拼写(缺了一个 `e`),**照抄字面参数名,不要自己纠正拼写**,传错名字会静默返回空结果。
### 查
```
get_products_productID_testcases(productID, ...)
get_projects_projectID_testcases(projectID, ...)
get_executions_executionID_testcases(executionID, ...)
get_testcases_caseID(caseID) 详情
```
### 建——步骤是三个平行数组,靠索引位置对应
```
post_testcases({ payload: {
productID, title,
module?, story?, pri?, type?, precondition?,
steps?: string[], # 步骤描述,第 i 项
expects?: string[], # 第 i 项步骤的期望结果
stepType?: string[], # 第 i 项步骤的类型:step 步骤 | group 父级步骤(分组标题,无需期望结果)
project?, execution?
} })
```
**这不是一个"步骤对象数组"(不是 `[{step, expect, type}, ...]`),是三个独立的字符串
数组,`steps[i]`/`expects[i]`/`stepType[i]` 靠同一个下标 `i` 对应同一个步骤。** 三个
数组长度必须一致,写用例时先把步骤列成一个表格跟用户确认,再按顺序拆成三个数组传,
不要把某一步的期望结果错位对到别的步骤上——这种错位不会报错,只会在用例详情里显示
"驴唇不对马嘴",很难事后发现。
`stepType``group` 的行是分组标题(比如"登录流程"这种大标题),对应的 `expects[i]`
一般传空字符串。
举例——"登录"用例有一个分组、两个步骤:
```
steps = ["登录流程", "打开登录页,输入正确账号密码", "点击登录按钮"]
stepType = ["group", "step", "step"]
expects = ["", "账号密码输入框正常显示", "跳转到首页,显示欢迎语"]
```
`type`(用例类型)受限枚举:`unit` 单元测试 | `interface` 接口测试 | `feature` 功能测试 |
`install` 安装部署 | `config` 配置相关 | `performance` 性能测试 | `security` 安全相关 |
`other` 其他。
### 改 / 删
```
put_testcases_testcasID({ testcasID, payload: {...} }) # 改步骤同样是三个数组整体替换,不是增量
delete_testcases_testcasID({ testcasID })
```
改步骤时**传的是完整的三个新数组,不是"追加一步"**——想加一个步骤,要先 `get_testcases_caseID`
拿到现有的 steps/expects/stepType,在末尾追加后整体传回,跟 `huanxi-task`
`task_set_assignees` 整组覆盖是同一种坑,直接传一步会把其余步骤全部覆盖掉。
---
## 测试单(testtask,提测)
**没有单条测试单详情接口**(只有创建/修改/删除,没有 `get_testtasks_testtaskID`),要看
某个测试单的信息,从列表接口里按 ID 过滤。
### 查
```
get_products_productID_testtasks(productID, ...)
get_projects_projectID_testtasks(projectID, ...)
get_executions_executionID_testtasks(executionID, ...)
```
### 建
```
post_testtasks({ payload: { productID, name, build, begin, end, execution?, type?,
owner?, status?, desc? } })
```
`productID`/`name`/`build`(提测构建/版本)/`begin`/`end` 必填。
**`type`(测试类型)是字符串数组,不是单值**——一个测试单可以同时标多种测试类型,取值
受限:`integrate` 集成测试 | `system` 系统测试 | `acceptance` 验收测试 | `performance` 性能测试
| `safety` 安全测试。传的时候是 `type: ["integrate", "system"]` 这种数组形式,不要传成
单个字符串 `type: "integrate"`
**跟其他实体不同,测试单的状态不是靠专门的 activate/close 端点切换,而是创建/修改时
直接传 `status` 字段**`wait` 未开始 | `doing` 进行中 | `done` 已关闭 | `blocked` 被阻塞。
改状态就是 `put_testtasks_testtaskID({ testtaskID, payload: { status: "doing" } })`
### 改 / 删
```
put_testtasks_testtaskID({ testtaskID, payload: {...} })
delete_testtasks_testtaskID({ testtaskID })
```
删除不可逆,执行前必须确认。