| name | structured-handoff |
| description | 结构化交接+晋升门禁。上下文快满或 finishing 阶段触发。覆写 handoff.md 的唯一正路:归档→清账(待晋升暂存逐条裁决:上架/弃置/顺延/阻塞)→按模板单源覆写→自查。 |
结构化交接 + 晋升门禁
工作台(handoff)只放状态和指针,知识住书架。覆写工作台的唯一正路 = 先清账后覆写:
工作台上有价值的内容必须上架登记(或显式弃置/顺延)后才许覆写,防止无声覆灭。
触发时机
- finishing 阶段(无论 evaluate 结果如何——通过、精磨、推翻都要更新交接)
- 上下文快满、准备
/clear 前
- 用户手动调用
/structured-handoff
当前交接文档
!cat docs/active/handoff.md 2>/dev/null || cat harness/docs/active/handoff.md 2>/dev/null || echo "无交接文档"
台账模板(单源)
!cat .claude/skills/structured-handoff/handoff-template.md 2>/dev/null || cat harness/.claude/skills/structured-handoff/handoff-template.md 2>/dev/null || echo "(模板缺失: .claude/skills/structured-handoff/handoff-template.md)"
当前分支和改动
!git branch --show-current 2>/dev/null || echo "未知"
!git log --oneline -5 2>/dev/null || echo "无 git 历史"
执行流程(固定序 ①归档→②清账→③覆写→④自查,不可换序)
① 归档
无条件执行(不判断"是否初始模板";多归档一份无害,重跑幂等):
路径口径:以下路径(①归档命令/③覆写目标/④自查 wc)以上方「当前交接文档」注入实际命中者为准——自仓库带 harness/ 前缀,即 harness/docs/active/、harness/docs/completed/。
mkdir -p docs/completed && cp docs/active/handoff.md "docs/completed/handoff-$(date +%Y%m%d-%H%M%S).md"
归档即"覆写信号":check-handoff.sh 以最新归档件为覆写信号,信号点燃后会机械硬核台账的 promotion 声明(文法+锚点)。归档完成后不回滚——即使后续步骤中止,也按 ② 的阻塞路径落盘声明。
归档件存入 docs/completed/,供 skipped 态回收点引用与后续 grep 考古。
② 清账(晋升门禁本体)
对旧台账「待晋升暂存」区逐条裁决,四种结果:
| 裁决 | 动作 |
|---|
| 上架 | 写书架对应格(住址按下方路由表)+ 同批登记(references/ → 目录卡 references/README.md 加行;decisions/ → 文件名即登记)+ 台账指针区加 - -> 路径 — 为什么读 |
| 弃置 | 条目留在已归档的旧台账中,理由随归档件保全(弃置计数写进 promotion 声明);书架零污染 |
| 顺延 | 整体走 skipped 态:promotion 写 skipped(理由: <非空>; 回收: <归档件路径>),回收点 = 步骤①的归档件路径,下次会话从归档件回收再裁决 |
| 阻塞 | 有影响下游的未决点且不可弃(含清账中途等用户拍板):中止覆写,当场把台账 promotion 行写为 阻塞(理由: <非空>)、其余内容保持原状(归档已完成不回滚——信号已点燃) |
书架写入失败 → 同阻塞路径,理由写 写入失败待重试。
清账步必含兜底一问:本会话有无该暂存未暂存的内容?答案为有 → 先补登暂存区再继续清账。(机器测不出"没写的东西",此问是在场兜底;归档件保全原文可考古)
裁决依据(实质闸)——逐条目问四个问题:
- 关键问题是什么?
- 讨论到什么程度?
- 有无影响下游的未决点?
- 下游能否照此干活?
松紧梯度:探索期(非收口覆写)顺延合法;收口与治理/方向类条目从严——方向/原则级条目的处置列选项请用户拍板,事实/留痕级 AI 即办(不做自动晋升)。
蒸馏判据(上架前一问):「下个功能还需要它吗?」——否 → 弃置。
预算枯竭不逼回写:上下文将满、暂存条目多时,不强行仓促上架——走 skipped(理由+回收点),暂存随归档件保全,下会话回收再裁决,书架零仓促污染。
晋升路由表(上架到哪):
| 条目类型 | 书架格 | 上架住址 | 同批登记动作 |
|---|
| 决策 | 决策史 | docs/decisions/YYYY-MM-DD-<slug>.md | 文件名即卡;判断拐点另 append decision-trail(既有义务) |
| 调研 / 参考 | 行业认知 | docs/references/YYYY-MM-DD-<slug>.md | 目录卡(references/README.md)加行 |
| 经验(干活规矩级) | 干活规矩 | 对应 docs/governance/*.md | 命中凭证义务 → 须 audit 凭证(credentials-rules),不得收口顺手直插;此类条目允许"顺延"跨覆写保留 |
| 经验(项目事实) | 系统真相 | ARCHITECTURE.md / 模块 README | 文档随码既有规矩 |
| 偏好 | 用户偏好 | docs/preferences.md | 条目带日期+用户原话引录;命中凭证义务 → 须 audit 凭证(credentials-rules),用户原话直录可走 exempt 微 audit 轻路径(credentials-rules §4) |
类型不在表(如 [疑问])→ 按实质闸归并到最近的格,或问用户。
③ 覆写
以上方「台账模板(单源)」注入的模板(.claude/skills/structured-handoff/handoff-template.md)为骨架重写 docs/active/handoff.md:
- promotion 按下方文法写
已核(...) 或 skipped(...)
- 暂存区归零:
- 无
- 空账(清账时暂存本就
- 无):promotion 写 已核(上架: 无; 弃置: 0 条)(空账=清白,非顺延,不用 skipped)
- 各状态字段(更新时间/当前阶段/当前分支/目标/进度/下一步/关键上下文等)按本次会话实际填写
promotion 声明文法(与模板/check-handoff.sh 三处同名同文法,全链 promotion: 无别名)
promotion: 未核
promotion: 已核(上架: <路径>[, <路径>]...; 弃置: <N> 条) # 上架段可为字面 "无"
promotion: 已核(上架: 无; 弃置: 0 条) # 空账合法形:当且仅当暂存区为 "- 无"(空账=清白,非顺延)
promotion: skipped(理由: <非空>; 回收: <归档件路径>) # 仅用于暂存有条目且顺延(回收点必填);空账不用 skipped
promotion: 阻塞(理由: <非空>) # 合法中间态,非终态(见下段)
hook 整行校验: ^promotion: (未核|已核\(上架: [^;]+; 弃置: [0-9]+ 条\)|skipped\(理由: [^;]+; 回收: [^)]+\)|阻塞\(理由: [^)]+\))$
锚点抽查(已核): 上架段按", "切分;每路径 test -f && test -s;
路径前缀含 references/ → 再 grep -F 文件名 于目录卡
(路径为无日期前缀标准件 → 不要求目录卡行,豁免见 4.1.7);
上架段为字面 "无" 时跳过锚点抽查;空账形 已核(上架: 无; 弃置: 0 条):
当且仅当最新归档件暂存区为 "- 无" 才合法(空账=清白,非顺延),否则 exit 2
"暂存有条目却记零账";弃置 ≥1 = 全弃置,合法;归档件无 "## 待晋升暂存" 节
(旧格式,B9 迁移场景)→ 视同 "- 无"(向后兼容)
凭证设计: 有上架声明却无路径的"已核"被文法拒;空账形态(上架: 无; 弃置: 0 条)合法且跳过锚点抽查
("只写已阅读不算证据"仍由非空账形的锚点抽查承载)
半角纪律: ( ) : ; , 全半角;全角不命中 → 按未做处理 + stderr 提示(半角纪律权威即本 SKILL;
沿 2026-04-28 C3 Y3 教训)
「阻塞」是台账中的合法中间态(非终态):清账裁决为阻塞或清账中途等用户拍板时,因固定序①归档已点燃覆写信号,当场把台账 promotion 行写为 阻塞(理由: <非空>)、其余保持原状——check-handoff.sh 在 60 分钟窗内视其为合法中间态放行;阻塞解除后重走本门禁,覆写步骤重写为 已核/skipped。
活跃任务索引逐行重建(防腐第①件)
覆写「## 活跃任务索引」时不保留旧表整块,逐行重声明「这条还活着吗」:
- 活的任务线 → 重写该行(保留状态、更新任务名称/触发器/指针的最新信息)
- 挂起行 → 当场重写复活触发器列(禁止 copy 旧占位或旧触发器文本;必须本次重新确认条件)。⚠️ 这一步「这条还活着吗 / 触发器还算不算数」是做事者自答 = 公设1 已知击穿点,非独立质量闸(§10.2 限度#2),别把"重写了触发器"读成"质量已兜"
- 完成的任务线 → 删行;同时:
- 成果进
## 待晋升暂存 走晋升门禁(一条一句话,条目类型+梗概,如 - [决策] 活跃任务索引覆写工序确定)
- 一句话梗概进
## 进度 > ### 已完成(无需详细,如 - 活跃任务索引落地)
- 弃置的任务线 → 删行;理由随①归档步的归档件保全(查古归档件可见)
- 回填机读表头:根据新表体行数,更新表头
活跃任务: N(进行中 X / 挂起 Y):
- N = 表体活跃任务行数(不含表头行/分隔行/占位行)
- X = 状态列为「进行中」的行数
- Y = 状态列为「挂起」的行数
写入规则
- 具体优于概括:写
src/api/auth.ts 的 validateToken() 而不是"改了认证模块"(用函数名/类名定位,不用行号——行号会随代码改动失效)
- 保留关键值:错误信息、端口号、版本号、环境变量名——这些丢了新会话就得重新查
- 不写废话:不要写"本次会话进展顺利"这种没有信息量的话
- 不含敏感信息:不写密钥、token、密码
④ 自查
- 行数:
wc -l < docs/active/handoff.md ≤ 80。超限砍序 = 先砍散文(关键上下文),指针与声明字段不砍;散文砍尽仍超 → 允许超限,在回复中声明超限原因
- 正文无
[待填] 残留(新建台账除外);无适用值的字段写 无(如纯文档会话的 Evidence Depth 各级),不留 [待填]
- 文件路径真实存在;没有敏感信息
活跃任务索引计数/位置/软上限自查(覆写生产侧主责)
覆写后,对「## 活跃任务索引」段执行以下四条自查(AI 一眼可数,机器核与自查不重叠):
-
表头计数一致性核:机读表头 活跃任务: N(进行中 X / 挂起 Y) 中的数字与表体一致:
- N == 表体活跃任务行数(不含表头行
| 状态 |、分隔行 |---|、占位行 (无活跃任务))
- X + Y == N
- X == 表体状态列为「进行中」的行数
- Y == 表体状态列为「挂起」的行数
- 若不一致 → 改表头数字对齐表体(主责:覆写步骤自答,正常修)
-
挂起行触发器非空核 + 进行中行触发器清洁核:
- 每条挂起行的复活触发器列 trim 后非空(非空且非字面
—);空 → 改写合法触发器
- 每条「进行中」行的复活触发器列 ==
—(防挂起→进行中切回漏改、留旧触发器文本残留);非 — → 改回 —
- AI 语义自核:挂起行触发器是否真复活条件(措辞质量,机器不核)。⚠️ 这是做事者自答、非独立闸,逮不到 = 撞公设1(§10.2 限度#2 / 设计 spec);机器核非空 ≠ 质量保障,不构成质量兜底——废话触发器(如"等时机""看情况")机器核非空照过,只能靠此自答兜,无独立眼睛盯僵尸线。
-
位置自查:## 活跃任务索引 节精确落在 ## 目标 之后、## 进度 之前(在 ## 待晋升暂存 之前):
- AI 覆写时核位置,不只靠口头硬约束
- 错放 → 挪回正确位置
-
挂起行积压软上限提醒(非硬错,信息性):
- 表体挂起行数 > 5 → 自查时提醒「挂起线积压,考虑收编/弃置」
- 初值 = 5 条(非实证最优,实战标定;沿 freshness-scout N=90 初值范式)
- 软上限不阻断覆写,仅提示调度者审视是否有挂起线应关闭或收编
- 与 ④自查 #1「≤80 行」预算的关系:若挂起线积压与 80 行预算冲突,优先砍散文、收编/弃置挂起线(走关闭动作 §4.5),不砍活跃任务索引表行(表行列入指针/声明字段的"不砍"保护)
错误处理与幂等
- 覆写写入失败 → 归档件在,git 可恢复
- 重跑本 skill 幂等:再归档一份无害