--- name: huanxi-shared description: "寰汐 MCP 共享基础:工具命名约定、本地缓存策略与过期检查、状态两层模型、全局确认约定。所有 huanxi-* 技能必须先读本文件。" --- # 寰汐 MCP 共享规则 所有 `huanxi-*` 技能的**必读前置**。 --- ## 一条最重要的约定:参数以工具自身的说明为准 **本文件与各技能文档都不重画参数表。** 每个工具的参数名、必填项、取值范围以它在 MCP 里注册的 docstring 为唯一真相;技能只描述**调用顺序、ID 如何传递、哪里必须停下来等用户 确认**。 > 这条不是洁癖。上一代技能包重画过参数表,结果字段名、枚举值、必填项四类漂移覆盖了 > 全部六个技能——用户侧表现为频繁的「参数缺失」报错。工具签名变了而文档没跟上, > 是必然发生而非可能发生的事。 --- ## 工具命名 Claude Code / Claude Desktop 里工具名带前缀:`mcp__huanxi__task_query`(个人端)、 `mcp__huanxi-admin__report_pending`(管理端)。其他平台通常是裸名 `task_query`。 本文档统一写**裸名**,实际调用时按你所在平台的约定加前缀。 两个端点信任边界不同: | | 个人端 | 管理端 | |---|---|---| | Token | `hxp_` 开头 | `hxa_` 开头 | | 身份 | 你本人,权限与网页端一致 | Token 创建人的管理员身份 | | 视角 | 我参与的 | 全量,不受角色过滤 | --- ## 状态是可配置的两层模型(v2 起) **不要硬编码 `"in_progress"`、`"done"` 这类字面量。** 状态由后台配置,分两层: - `category`:四类固定语义 `not_started` / `in_progress` / `completed` / `cancelled`, 用于**判断**(这条算不算完成) - `status_option_id`:具体状态项的 UUID,用于**写入** 改任何实体状态前,先 `dict_get` 取该 `entity_type`(module/task/issue/meeting,**必须选对**) 下的选项,再传对应的 `status_option_id`。传旧值或错的 entity_type 会被直接拒绝。 --- ## 本地缓存 缓存根目录 `~/.claude/huanxi-cache/`,**按通道隔离**: ``` ~/.claude/huanxi-cache/ ├── personal/ hxp_ 视角:me.json / my-modules.json / users.json ├── admin/ hxa_ 视角:org-tree.json / all-modules.json └── dict/ 与身份无关的配置字典(两个通道共享) ``` 隔离是必须的:管理端看到的是全量模块,个人端只有我参与的——混用会让你把不该展示的 东西展示给用户。 ### 分层 TTL | 类别 | 文件 | 策略 | |---|---|---| | 身份 | `personal/me.json` | 永久(身份不变) | | **配置字典** | `dict/*.json` | **版本戳比对** + 24h 兜底 | | 组织 | `users.json` / `org-tree.json` / `my-modules.json` | 24h | | 日历 | `dict/workdays.json` | 按日期 key 永久(查过的不再查) | | **业务数据** | 任务 / 日报 / 会议 / 议题 / 公告 | **一律不缓存** | 最后一行是硬规则。业务数据随时在变,缓存它只会让你把过期状态当成现状汇报给用户。 ### 字典为什么要版本戳而不是只靠 TTL 其余缓存过期了最多是显示旧数据;字典不一样——状态选项可能被后台停用,你拿 24 小时前 的 ID 去改状态会**直接报错**。失败方向从「看到旧数据」变成「操作失败」,值得比对一次。 ``` 用字典前: 1. 调 dict_version() ← 极轻 2. 与 dict/versions.json 比对 3. 一致 → 用缓存;不一致 → 调 dict_get() 重取该类并更新缓存 ``` `dict_get` 的返回里**自带 versions 字段**,直接连内容一起存下来即可——不要分两次调用, 那中间字典若被改动,你会把新内容配上旧版本戳缓存起来,之后再也不会刷新。 ### 读缓存伪代码 ``` read(file, ttl): 1. 读 ~/.claude/huanxi-cache/{file} 2. 文件不存在 → miss 3. age = now - cached_at 4. ttl 为永久 或 age < ttl → 返回 data 5. 否则 → miss on_miss(tool, params): 1. 调用工具 2. 写入 { "cached_at": , "data": <返回值> } 3. 返回 data ``` `workdays.json` 特殊:按日期 key 存 `{ "2026-08-06": true }`,已查过的日期不再查。 --- ## 全局约定 1. **提交类操作必须先确认**:`report_submit` / `leader_report_submit` / `issue_close` 等, 执行前把最终内容展示给用户、等到明确确认(「确认」「提交」「好的」)再调。 不要因为用户说了「帮我写日报」就把提交也一并做了——写和交是两个决定。 2. **删除与指派同样需要确认**:`task_set_assignees` 是**替换**语义(传空即清空), 不是追加;覆盖别人的名单前先说清楚会变成什么样。 3. **非工作日不强行中断**:`workday_check` 显示非工作日时告知用户并询问是否仍要填写, 不要直接拒绝——补填、调休上班都是真实场景。 4. **先解析 ID 再操作**:需要 module_id / user_id 的操作,先查缓存,未命中再调 `module_query` / `user_search`。不要凭名字猜 ID。 5. **批量优先**:工具的过滤维度基本都收列表,一次查多个比循环调用快得多,也更省上下文。