{"generatedAt":"2026-07-13T07:45:15.469Z","usingPreview":false,"categories":[{"name":"硅基突触","slug":"silicon-synapse","count":4}],"posts":[{"id":"143611368770113536","title":"把飞书协同补录做成一个前端主导 Skill","slug":"sync-feishu-code-collab-skill","url":"/posts/sync-feishu-code-collab-skill/","summary":"该 skill 用于防止飞书协同表被误用为事实来源。它先读项目规则，定位当前协同表，核对 lark-cli、Base schema 及权限，确保截图仅本地留存且为真实渲染的目标态页面，禁止占位或拼接图。默认适用于前端场景，后端需自行配置 repo 文档、字段映射等。找不到有效表格链接时停止写入并提示用户。目标是让协同记录回归台账定位，技术事实留存于仓库文档。","category":{"id":"143210892169842688","name":"硅基突触","slug":"silicon-synapse","type":0},"tags":["skill","feishu","workflow"],"createdAt":"2026-06-02T07:00:18.485Z","modifiedAt":"2026-06-08T06:57:15.415Z","readCount":0,"likeCount":0,"text":"::: note\nSkill 已推到 GitHub：\nsync-feishu-code-collab\n。这是这篇记录的主角，不是附录。\n:::\n\n## 为什么要做这个\n\n飞书 Base 很适合做协作台账，但它很容易被误用成事实来源。一次前端提交、一次后端字段缺口、一张页面目标态截图、一次 shared dev 验证，看起来都能被塞进同一条记录里。问题是：这些东西的证据等级不同。\n\n所以我让 agent 把这套要求做成一个 skill。它不是替人拍脑袋填表。它先读项目本地规则，再确认当前飞书表格，再核对 `lark-cli`、Base schema、截图边界和后端可见文档。\n\n协同表是台账。仓库文档才是技术事实。\n\n<excalidraw>\n{\"type\":\"excalidraw\",\"version\":2,\"source\":\"sync-feishu-code-collab-skill\",\"elements\":[{\"id\":\"p1\",\"type\":\"rectangle\",\"x\":20,\"y\":40,\"width\":160,\"height\":70,\"angle\":0,\"strokeColor\":\"#1d4ed8\",\"backgroundColor\":\"#dbeafe\",\"fillStyle\":\"solid\",\"strokeWidth\":2,\"strokeStyle\":\"solid\",\"roughness\":1,\"opacity\":100,\"groupIds\":[],\"frameId\":null,\"roundness\":{\"type\":3},\"seed\":101,\"version\":1,\"versionNonce\":10101,\"isDeleted\":false,\"boundElements\":[],\"updated\":1,\"link\":null,\"locked\":false},{\"id\":\"p1t\",\"type\":\"text\",\"x\":43,\"y\":62,\"width\":114,\"height\":25,\"angle\":0,\"strokeColor\":\"#1f2937\",\"backgroundColor\":\"transparent\",\"fillStyle\":\"solid\",\"strokeWidth\":1,\"strokeStyle\":\"solid\",\"roughness\":1,\"opacity\":100,\"groupIds\":[],\"frameId\":null,\"roundness\":null,\"seed\":102,\"version\":1,\"versionNonce\":10201,\"isDeleted\":false,\"boundElements\":null,\"updated\":1,\"link\":null,\"locked\":false,\"text\":\"读项目规则\",\"fontSize\":20,\"fontFamily\":1,\"textAlign\":\"center\",\"verticalAlign\":\"middle\",\"containerId\":null,\"originalText\":\"读项目规则\",\"lineHeight\":1.25,\"baseline\":18},{\"id\":\"p2\",\"type\":\"rectangle\",\"x\":220,\"y\":40,\"width\":160,\"height\":70,\"angle\":0,\"strokeColor\":\"#7c3aed\",\"backgroundColor\":\"#ede9fe\",\"fillStyle\":\"solid\",\"strokeWidth\":2,\"strokeStyle\":\"solid\",\"roughness\":1,\"opacity\":100,\"groupIds\":[],\"frameId\":null,\"roundness\":{\"type\":3},\"seed\":103,\"version\":1,\"versionNonce\":10301,\"isDeleted\":false,\"boundElements\":[],\"updated\":1,\"link\":null,\"locked\":false},{\"id\":\"p2t\",\"type\":\"text\",\"x\":243,\"y\":62,\"width\":114,\"height\":25,\"angle\":0,\"strokeColor\":\"#1f2937\",\"backgroundColor\":\"transparent\",\"fillStyle\":\"solid\",\"strokeWidth\":1,\"strokeStyle\":\"solid\",\"roughness\":1,\"opacity\":100,\"groupIds\":[],\"frameId\":null,\"roundness\":null,\"seed\":104,\"version\":1,\"versionNonce\":10401,\"isDeleted\":false,\"boundElements\":null,\"updated\":1,\"link\":null,\"locked\":false,\"text\":\"找当前表\",\"fontSize\":20,\"fontFamily\":1,\"textAlign\":\"center\",\"verticalAlign\":\"middle\",\"containerId\":null,\"originalText\":\"找当前表\",\"lineHeight\":1.25,\"baseline\":18},{\"id\":\"p3\",\"type\":\"rectangle\",\"x\":420,\"y\":40,\"width\":160,\"height\":70,\"angle\":0,\"strokeColor\":\"#ca8a04\",\"backgroundColor\":\"#fef3c7\",\"fillStyle\":\"solid\",\"strokeWidth\":2,\"strokeStyle\":\"solid\",\"roughness\":1,\"opacity\":100,\"groupIds\":[],\"frameId\":null,\"roundness\":{\"type\":3},\"seed\":105,\"version\":1,\"versionNonce\":10501,\"isDeleted\":false,\"boundElements\":[],\"updated\":1,\"link\":null,\"locked\":false},{\"id\":\"p3t\",\"type\":\"text\",\"x\":439,\"y\":62,\"width\":122,\"height\":25,\"angle\":0,\"strokeColor\":\"#1f2937\",\"backgroundColor\":\"transparent\",\"fillStyle\":\"solid\",\"strokeWidth\":1,\"strokeStyle\":\"solid\",\"roughness\":1,\"opacity\":100,\"groupIds\":[],\"frameId\":null,\"roundness\":null,\"seed\":106,\"version\":1,\"versionNonce\":10601,\"isDeleted\":false,\"boundElements\":null,\"updated\":1,\"link\":null,\"locked\":false,\"text\":\"核对 schema\",\"fontSize\":20,\"fontFamily\":1,\"textAlign\":\"center\",\"verticalAlign\":\"middle\",\"containerId\":null,\"originalText\":\"核对 schema\",\"lineHeight\":1.25,\"baseline\":18},{\"id\":\"p4\",\"type\":\"rectangle\",\"x\":620,\"y\":40,\"width\":160,\"height\":70,\"angle\":0,\"strokeColor\":\"#15803d\",\"backgroundColor\":\"#dcfce7\",\"fillStyle\":\"solid\",\"strokeWidth\":2,\"strokeStyle\":\"solid\",\"roughness\":1,\"opacity\":100,\"groupIds\":[],\"frameId\":null,\"roundness\":{\"type\":3},\"seed\":107,\"version\":1,\"versionNonce\":10701,\"isDeleted\":false,\"boundElements\":[],\"updated\":1,\"link\":null,\"locked\":false},{\"id\":\"p4t\",\"type\":\"text\",\"x\":643,\"y\":62,\"width\":114,\"height\":25,\"angle\":0,\"strokeColor\":\"#1f2937\",\"backgroundColor\":\"transparent\",\"fillStyle\":\"solid\",\"strokeWidth\":1,\"strokeStyle\":\"solid\",\"roughness\":1,\"opacity\":100,\"groupIds\":[],\"frameId\":null,\"roundness\":null,\"seed\":108,\"version\":1,\"versionNonce\":10801,\"isDeleted\":false,\"boundElements\":null,\"updated\":1,\"link\":null,\"locked\":false,\"text\":\"写入读回\",\"fontSize\":20,\"fontFamily\":1,\"textAlign\":\"center\",\"verticalAlign\":\"middle\",\"containerId\":null,\"originalText\":\"写入读回\",\"lineHeight\":1.25,\"baseline\":18}],\"appState\":{\"viewBackgroundColor\":\"#ffffff\"},\"files\":{}}\n</excalidraw>\n\n## 第一条边界：确定协同表\n\n项目已经有协同表时，应该优先使用当前表。找不到表格链接或 Base 标识时，skill 会停止写入，并提示用户找开发者 `alexxiang` 提供表格链接，或者由用户自行创建并提供链接和字段规则。\n\n这条规则很小，但能防止一类最烦人的混乱：每个人都有一张“协同表”，最后没有人知道哪张是真的。\n\n当前 GitHub 提交是 `aeb7e06`，提交信息是 `feat: add sync-feishu-code-collab skill`。我同时用 GitHub connector 读回了线上 `SKILL.md`，确认公开仓库里确实有这份 skill。\n\n## 第二条边界：适用前端但可改造\n\n这个 skill 是 alexxiang 在开发「到了么」前端时创建的。默认场景是前端 commit、前端可见验证、UI/文案/交互截图，以及前端仓库里给后端看的协作文档。\n\n后端可以复用，但不能直接套。后端需要自己的 repo 文档、字段映射、验证命令、附件策略和 `lark-cli` auth/scopes。没有这些，就不能把它说成后端自动化。\n\n<excalidraw>\n{\"elements\":[{\"id\":\"f1\",\"type\":\"rectangle\",\"x\":40,\"y\":30,\"width\":260,\"height\":170,\"angle\":0,\"strokeColor\":\"#1d4ed8\",\"backgroundColor\":\"#dbeafe\",\"fillStyle\":\"solid\",\"strokeWidth\":2,\"strokeStyle\":\"solid\",\"roughness\":1,\"opacity\":100,\"groupIds\":[],\"frameId\":null,\"roundness\":{\"type\":3},\"seed\":201,\"version\":2,\"versionNonce\":736151779,\"isDeleted\":false,\"boundElements\":[],\"updated\":1780386097862,\"link\":null,\"locked\":false,\"index\":\"a0\"},{\"id\":\"f1t\",\"type\":\"text\",\"x\":122,\"y\":55,\"width\":96,\"height\":100,\"angle\":0,\"strokeColor\":\"#1f2937\",\"backgroundColor\":\"transparent\",\"fillStyle\":\"solid\",\"strokeWidth\":1,\"strokeStyle\":\"solid\",\"roughness\":1,\"opacity\":100,\"groupIds\":[],\"frameId\":null,\"roundness\":null,\"seed\":202,\"version\":5,\"versionNonce\":199793741,\"isDeleted\":false,\"boundElements\":[],\"updated\":1780386100232,\"link\":null,\"locked\":false,\"text\":\"前端默认\\ncommit\\n截图\\n验证\\n后端可见文档\",\"fontSize\":16,\"fontFamily\":1,\"textAlign\":\"center\",\"verticalAlign\":\"middle\",\"containerId\":null,\"originalText\":\"前端默认\\ncommit\\n截图\\n验证\\n后端可见文档\",\"lineHeight\":1.25,\"baseline\":96,\"index\":\"a1\",\"autoResize\":true},{\"id\":\"f2\",\"type\":\"rectangle\",\"x\":415.3984375,\"y\":26.97265625,\"width\":260,\"height\":170,\"angle\":0,\"strokeColor\":\"#7c3aed\",\"backgroundColor\":\"#ede9fe\",\"fillStyle\":\"solid\",\"strokeWidth\":2,\"strokeStyle\":\"solid\",\"roughness\":1,\"opacity\":100,\"groupIds\":[],\"frameId\":null,\"roundness\":{\"type\":3},\"seed\":203,\"version\":19,\"versionNonce\":1169651661,\"isDeleted\":false,\"boundElements\":[],\"updated\":1780386115237,\"link\":null,\"locked\":false,\"index\":\"a2\"},{\"id\":\"f2t\",\"type\":\"text\",\"x\":492.93359375,\"y\":52.28515625,\"width\":102.77993774414062,\"height\":125,\"angle\":0,\"strokeColor\":\"#1f2937\",\"backgroundColor\":\"transparent\",\"fillStyle\":\"solid\",\"strokeWidth\":1,\"strokeStyle\":\"solid\",\"roughness\":1,\"opacity\":100,\"groupIds\":[],\"frameId\":null,\"roundness\":null,\"seed\":204,\"version\":70,\"versionNonce\":1693513261,\"isDeleted\":false,\"boundElements\":[],\"updated\":1780386115237,\"link\":null,\"locked\":false,\"text\":\"后端可用\\n但需自配\\nrepo 文档\\n字段映射\\n权限 scope\",\"fontSize\":20,\"fontFamily\":1,\"textAlign\":\"left\",\"verticalAlign\":\"middle\",\"containerId\":null,\"originalText\":\"后端可用\\n但需自配\\nrepo 文档\\n字段映射\\n权限 scope\",\"lineHeight\":1.25,\"baseline\":96,\"index\":\"a3\",\"autoResize\":true},{\"id\":\"label\",\"type\":\"text\",\"x\":315.41796875,\"y\":97.05078125,\"width\":80,\"height\":20,\"angle\":0,\"strokeColor\":\"#374151\",\"backgroundColor\":\"transparent\",\"fillStyle\":\"solid\",\"strokeWidth\":1,\"strokeStyle\":\"solid\",\"roughness\":1,\"opacity\":100,\"groupIds\":[],\"frameId\":null,\"roundness\":null,\"seed\":205,\"version\":30,\"versionNonce\":598600035,\"isDeleted\":false,\"boundElements\":[],\"updated\":1780386117936,\"link\":null,\"locked\":false,\"text\":\"不是同一套\",\"fontSize\":16,\"fontFamily\":1,\"textAlign\":\"center\",\"verticalAlign\":\"middle\",\"containerId\":null,\"originalText\":\"不是同一套\",\"lineHeight\":1.25,\"baseline\":18,\"index\":\"a4\",\"autoResize\":true}],\"appState\":{\"viewBackgroundColor\":\"#ffffff\",\"gridSize\":20},\"files\":{}}\n</excalidraw>\n\n## 第三条边界：截图不能偷懒\n\n截图是这次要求里最容易被误解的部分。同步飞书记录，不等于允许上传截图。截图默认本机留存。只有用户明确说要上传附件，agent 才能外传。\n\n如果是前端视觉、文案或交互变更，主证据必须是当前分支真实代码渲染出的完整目标态页面。不能用结构示意图，不能用脱敏占位图，不能用手工拼接图，不能用旧图，也不能拿后端字段还没接上时的 live 回退页顶替。\n\n后端字段没接入时，可以用仓库外 fixture 生成 `frontend-target-state-preview`。但这不是后端已接，也不是 shared dev、staging 或 production 已验证。\n\n<excalidraw>\n{\"type\":\"excalidraw\",\"version\":2,\"source\":\"sync-feishu-code-collab-skill\",\"elements\":[{\"id\":\"s1\",\"type\":\"rectangle\",\"x\":40,\"y\":30,\"width\":220,\"height\":80,\"angle\":0,\"strokeColor\":\"#15803d\",\"backgroundColor\":\"#dcfce7\",\"fillStyle\":\"solid\",\"strokeWidth\":2,\"strokeStyle\":\"solid\",\"roughness\":1,\"opacity\":100,\"groupIds\":[],\"frameId\":null,\"roundness\":{\"type\":3},\"seed\":301,\"version\":1,\"versionNonce\":30101,\"isDeleted\":false,\"boundElements\":[],\"updated\":1,\"link\":null,\"locked\":false},{\"id\":\"s1t\",\"type\":\"text\",\"x\":67,\"y\":55,\"width\":166,\"height\":25,\"angle\":0,\"strokeColor\":\"#1f2937\",\"backgroundColor\":\"transparent\",\"fillStyle\":\"solid\",\"strokeWidth\":1,\"strokeStyle\":\"solid\",\"roughness\":1,\"opacity\":100,\"groupIds\":[],\"frameId\":null,\"roundness\":null,\"seed\":302,\"version\":1,\"versionNonce\":30201,\"isDeleted\":false,\"boundElements\":null,\"updated\":1,\"link\":null,\"locked\":false,\"text\":\"完整目标态截图\",\"fontSize\":20,\"fontFamily\":1,\"textAlign\":\"center\",\"verticalAlign\":\"middle\",\"containerId\":null,\"originalText\":\"完整目标态截图\",\"lineHeight\":1.25,\"baseline\":18},{\"id\":\"s2\",\"type\":\"rectangle\",\"x\":320,\"y\":30,\"width\":220,\"height\":80,\"angle\":0,\"strokeColor\":\"#ca8a04\",\"backgroundColor\":\"#fef3c7\",\"fillStyle\":\"solid\",\"strokeWidth\":2,\"strokeStyle\":\"solid\",\"roughness\":1,\"opacity\":100,\"groupIds\":[],\"frameId\":null,\"roundness\":{\"type\":3},\"seed\":303,\"version\":1,\"versionNonce\":30301,\"isDeleted\":false,\"boundElements\":[],\"updated\":1,\"link\":null,\"locked\":false},{\"id\":\"s2t\",\"type\":\"text\",\"x\":347,\"y\":55,\"width\":166,\"height\":25,\"angle\":0,\"strokeColor\":\"#1f2937\",\"backgroundColor\":\"transparent\",\"fillStyle\":\"solid\",\"strokeWidth\":1,\"strokeStyle\":\"solid\",\"roughness\":1,\"opacity\":100,\"groupIds\":[],\"frameId\":null,\"roundness\":null,\"seed\":304,\"version\":1,\"versionNonce\":30401,\"isDeleted\":false,\"boundElements\":null,\"updated\":1,\"link\":null,\"locked\":false,\"text\":\"live 图只补充\",\"fontSize\":20,\"fontFamily\":1,\"textAlign\":\"center\",\"verticalAlign\":\"middle\",\"containerId\":null,\"originalText\":\"live 图只补充\",\"lineHeight\":1.25,\"baseline\":18},{\"id\":\"s3\",\"type\":\"rectangle\",\"x\":180,\"y\":150,\"width\":220,\"height\":80,\"angle\":0,\"strokeColor\":\"#7c3aed\",\"backgroundColor\":\"#ede9fe\",\"fillStyle\":\"solid\",\"strokeWidth\":2,\"strokeStyle\":\"solid\",\"roughness\":1,\"opacity\":100,\"groupIds\":[],\"frameId\":null,\"roundness\":{\"type\":3},\"seed\":305,\"version\":1,\"versionNonce\":30501,\"isDeleted\":false,\"boundElements\":[],\"updated\":1,\"link\":null,\"locked\":false},{\"id\":\"s3t\",\"type\":\"text\",\"x\":207,\"y\":175,\"width\":166,\"height\":25,\"angle\":0,\"strokeColor\":\"#1f2937\",\"backgroundColor\":\"transparent\",\"fillStyle\":\"solid\",\"strokeWidth\":1,\"strokeStyle\":\"solid\",\"roughness\":1,\"opacity\":100,\"groupIds\":[],\"frameId\":null,\"roundness\":null,\"seed\":306,\"version\":1,\"versionNonce\":30601,\"isDeleted\":false,\"boundElements\":null,\"updated\":1,\"link\":null,\"locked\":false,\"text\":\"fixture 只预览\",\"fontSize\":20,\"fontFamily\":1,\"textAlign\":\"center\",\"verticalAlign\":\"middle\",\"containerId\":null,\"originalText\":\"fixture 只预览\",\"lineHeight\":1.25,\"baseline\":18},{\"id\":\"s4\",\"type\":\"rectangle\",\"x\":460,\"y\":150,\"width\":220,\"height\":80,\"angle\":0,\"strokeColor\":\"#be123c\",\"backgroundColor\":\"#ffe4e6\",\"fillStyle\":\"solid\",\"strokeWidth\":2,\"strokeStyle\":\"solid\",\"roughness\":1,\"opacity\":100,\"groupIds\":[],\"frameId\":null,\"roundness\":{\"type\":3},\"seed\":307,\"version\":1,\"versionNonce\":30701,\"isDeleted\":false,\"boundElements\":[],\"updated\":1,\"link\":null,\"locked\":false},{\"id\":\"s4t\",\"type\":\"text\",\"x\":487,\"y\":175,\"width\":166,\"height\":25,\"angle\":0,\"strokeColor\":\"#1f2937\",\"backgroundColor\":\"transparent\",\"fillStyle\":\"solid\",\"strokeWidth\":1,\"strokeStyle\":\"solid\",\"roughness\":1,\"opacity\":100,\"groupIds\":[],\"frameId\":null,\"roundness\":null,\"seed\":308,\"version\":1,\"versionNonce\":30801,\"isDeleted\":false,\"boundElements\":null,\"updated\":1,\"link\":null,\"locked\":false,\"text\":\"禁止占位拼图\",\"fontSize\":20,\"fontFamily\":1,\"textAlign\":\"center\",\"verticalAlign\":\"middle\",\"containerId\":null,\"originalText\":\"禁止占位拼图\",\"lineHeight\":1.25,\"baseline\":18}],\"appState\":{\"viewBackgroundColor\":\"#ffffff\"},\"files\":{}}\n</excalidraw>\n\n## 这个 skill 现在管什么\n\n- 先读当前项目规则，优先找到已有飞书协同表。\n- 找不到表格链接时，提示找 `alexxiang` 或自行提供表格链接。\n- 写入前检查 `lark-cli`、登录态、Base schema 和权限 scope。\n- 把后端要看的内容指向 repo 可见文档，而不是本机私有材料。\n- 截图默认只本机留存，外传必须显式授权。\n- 读回记录，不把“本地已写”“已推送”“已发布”“live 已验证”混成同一句话。\n\n> [!IMPORTANT]\n> 这不是一个“帮我随便补飞书”的 skill。它是一个防止协同记录污染事实来源的 skill。\n\n## Skill 树\n\n```text\n\nskills/automation/sync-feishu-code-collab/\n├── SKILL.md\n├── agents/openai.yaml\n└── references/feishu-code-collab-requirements.md\n\n```\n\n入口：[https://github.com/XJM034/SKILL/tree/main/skills/automation/sync-feishu-code-collab](https://github.com/XJM034/SKILL/tree/main/skills/automation/sync-feishu-code-collab)\n\n以后再补飞书协同记录，我希望 agent 先读这个 skill，再动手。先找表。先查 schema。先确认截图边界。再写。"},{"id":"143534615053733888","title":"Handoff 不是总结，是下一位 Agent 的接力棒","slug":"handoff-skill","url":"/posts/handoff-skill/","summary":"长会话交接的关键不是上下文长度，而是需清晰分离事实、推断与未决假设。为此设计了固定格式的handoff skill，将任务状态写入`./handoff/YYMMDD-handoff.md`，包含七个固定部分及具体操作细节，确保下一位agent能立即执行。其核心在于协作接口而非总结，强调路径稳定、状态重建和可验证性，最终验证是能否真正衔接。本次发布将本地skill转入GitHub仓库（commit `3da5954`），明确skill为主artifact，文章仅为解释。","category":{"id":"143210892169842688","name":"硅基突触","slug":"silicon-synapse","type":0},"tags":["skill","agent-workflow","handoff"],"createdAt":"2026-06-02T01:55:18.973Z","modifiedAt":"2026-06-09T02:09:31.907Z","readCount":0,"likeCount":0,"text":"Skill first：[skills/writing/handoff](https://github.com/XJM034/SKILL/tree/main/skills/writing/handoff)。\n\n长会话最危险的地方，不是上下文变长。\n\n危险在于交接时大家以为“总结一下”就够了。总结给人看，handoff 给下一位 agent 执行。这两件事完全不同。\n\n所以我把 `handoff` 做成一个固定 skill。它只做一件事：把当前任务、已确认事实、未完成事项、风险和最值得立刻做的下一步，写进一个 dated markdown 文件。路径默认是 `./handoff/YYMMDD-handoff.md`。\n\n这不是漂亮话。\n\n这是协作接口。\n\n## 接力路径\n\n1. 先把长会话里的状态压成可验证事实。\n2. 再写入 `handoff/YYMMDD-handoff.md`。\n3. 最后给下一位 agent 一个最具体的第一步。\n\n## 第一步：路径要稳定\n\n一个交接文件如果每次都放在不同地方，它就不是交接文件。它只是又一个附件。\n\n`handoff` 的默认路径是 `./handoff/YYMMDD-handoff.md`。如果用户给了自定义路径，就用自定义路径，并创建父目录。dated 文件已经存在时，默认替换，而不是追加。\n\n这个选择很小，但很硬。下一位 agent 不应该猜“上一轮到底写到哪里了”。\n\n## 第二步：先重建状态，再动笔\n\nhandoff 最容易写坏的方式，是一边回忆一边润色。这样会把确定事实、合理推断和未验证假设揉在一起。\n\n这个 skill 强制先重建状态：当前 thread、repo state、修改过的文件、最近跑过的检查、产出的 artifact。关键路径、命令、模块名和决策点要先验证，再写进文档。\n\n- Confirmed facts：精确文件、命令、输出、页面、接口结果。\n- Reasonable inferences：为什么这件事大概率成立。\n- Unresolved assumptions：下一位 agent 必须先确认什么。\n\n事实是事实。推断是推断。假设是债务。\n\n## 第三步：写给下一位 agent，不是写给用户\n\n这条规则是整个 skill 的中心。\n\n用户更新可以温柔，可以概括，可以把噪音折叠掉。handoff 不行。handoff 要保留下一位 agent 接手所需的操作性细节：文件路径、命令、API、route、class、module、table、env var、已知死路、风险和建议第一步。\n\n它不需要漂亮。它需要可继续。\n\n## 第四步：七段结构就是协议\n\n我不想让每次交接都重新发明格式，所以 `handoff` 固定了七个编号 section：\n\n1. 当前任务目标\n2. 当前进展\n3. 关键上下文\n4. 关键发现\n5. 未完成事项\n6. 建议接手路径\n7. 风险与注意事项\n\n最后还必须有一句 `下一位 Agent 的第一步建议`。这句话很重要。它把“你可以继续看看”变成“第一步先做这个”。\n\n## 第五步：验证不是形式主义\n\n这个 skill 的最后一步要求确认四件事：文件存在、七个 numbered sections 都在、最后的第一步建议存在、整篇读起来像内部 baton pass 而不是用户更新。\n\n这看起来像格式检查。其实是在防止一种更隐蔽的失败：文档写了，但下一位 agent 仍然不知道怎么开始。\n\n能接上，才算写完。\n\n## 这次发布的真实边界\n\n这次我把本地 `/Users/minxian/.codex/skills/handoff/SKILL.md` 放进 GitHub-backed skill repo 的 `skills/writing/handoff/SKILL.md`，并补了 repo 需要的 metadata、常见坑表和 verification checklist。\n\n这里有一个边界要说清楚：skill 是主 artifact，blog 是解释层。以后真正复用时，不应该回来看这篇文章照着猜，而应该直接用 GitHub 上的 skill。\n\n文章负责讲为什么。skill 负责让下一次少踩坑。\n\n如果你在长任务结束时只想做一件事，就做 handoff。不要等上下文已经糊成一团才开始抢救。\n\nSkill 源码：[https://github.com/XJM034/SKILL/tree/main/skills/writing/handoff](https://github.com/XJM034/SKILL/tree/main/skills/writing/handoff)"},{"id":"143260304891973632","title":"把 CLAUDE.md 和 AGENTS.md 做成可复用 workflow","slug":"claude-agents-bootstrap-skill","url":"/posts/claude-agents-bootstrap-skill/","summary":"把 CLAUDE.md 和 AGENTS.md 做成可复用工作流的经验：根文档只放稳定高频规则，细节收入低噪文档；新版 v0.2 补上了 scoped AGENTS.md、AGENTS/CLAUDE 兼容、skill source/mirror/install root 区分、文章证据回流和完整生命周期报告。短根文档比长百科更有用，但质量证据也要写清边界：AI 盲审是 smoke evidence，不等于 human blind review。","category":{"id":"143210892169842688","name":"硅基突触","slug":"silicon-synapse","type":0},"tags":["codex","skill","agents","docs"],"createdAt":"2026-06-01T07:45:18.334Z","modifiedAt":"2026-06-23T08:30:32.283Z","readCount":0,"likeCount":0,"text":"# 把 CLAUDE.md 和 AGENTS.md 做成可复用 workflow\n\n> Skill first：[claude-agents-bootstrap](https://github.com/XJM034/SKILL/tree/main/skills/automation/claude-agents-bootstrap)。\n\n弄丢了制作 `claude-agents-bootstrap` 的那段 session。\n\n这听起来像一件小事故，但它刚好证明了这个 skill 为什么应该存在：重要经验不能只活在聊天记录里。它要变成可检查、可推送、可复用的仓库资产。\n\n丢 session 不等于丢经验。只要 artifact 还在，流程就能补回来。\n\n## root docs 是地图，不是百科全书\n\n这个 skill 的核心不是“写一份更长的 `CLAUDE.md`”。相反，它要减少 resident context 里的噪音。\n\n根文档只放稳定、高频、会影响每次 agent 行为的规则：项目契约、先读文件、命令、验证、更新规则、禁止事项、compact 指令。低频细节进入 `docs/AI_REFERENCE.md`、`docs/ai/*.md` 或模块文档。\n\n根文档是地图。代码和版本化文档才是记录系统。\n\n## 让 agent 先找证据，再写规则\n\n`claude-agents-bootstrap` 的工作流有一个故意设置的摩擦：不能一上来就改 `AGENTS.md`。它要先读已有根文档、README、关键 docs，再检查代码里的高风险事实：角色边界、路由边界、auth/session、数据库来源、上传导出、安全边界、命令和验证面。\n\n如果 repo 已经足够说明事实，就不问填表式问题。如果关键政策缺口会改变输出，才问一个短问题。\n\n少问不是偷懒。少问是尊重已存在的证据。\n\n## 主动队列要写清楚生命周期\n\n很多项目的 AI docs 会慢慢变成垃圾桶：今天塞一个 bug，明天塞一个 tech debt，后天塞一个 release blocker。没有完成证据，没有归档规则，也没有“不确定时问用户”的边界。\n\n这个 skill 强制队列类 supporting docs 写生命周期：什么算 active、什么证据算完成、完成后去哪里、什么时候 agent 可以清理、什么时候必须问一个聚焦问题。\n\n队列要会释放。否则它只是另一个 backlog。\n\n## 2026-06-23：这次 v0.2 真正补上的东西\n\n后来我又拿一篇关于 `AGENTS.md` 的完整文章反查这个 skill。那篇文章里最刺眼的一点很简单：你不只有 root `AGENTS.md`。在 monorepo 或多应用仓库里，子目录也可以放 `AGENTS.md`，并和 root 指令一起进入 agent 上下文。\n\n这迫使新版把“短 root docs”推进一步：root 只负责跨项目的 resident rules；`apps/admin`、`apps/mobile`、`packages/api` 这类子树自己的命令、风险和约定，应该进入 scoped `AGENTS.md`。每一层都要克制，因为 nested instructions 会合并。把所有东西塞回 root，只是换一种方式制造泥球。\n\n新版也把工具兼容说清楚了。`AGENTS.md` 是开放约定，但不是所有 agent 都读；Claude Code 更常读 `CLAUDE.md`。所以 skill 不再只说“保持一致”，而是要求显式处理镜像、symlink 或有意分歧。同时，它会区分三种很容易被混淆的路径：canonical skill source、repo-local mirror、loader-visible install root。能读到一份副本，不等于这个 skill 已经被当前 harness 自动发现。\n\n另一个补丁是分类。个人偏好、团队约定、项目事实、工具限制不能混在一起写。个人喜欢某种 commit 风格，不等于项目事实。某个 loader 不支持某种发现机制，也不等于所有 agent 都有这个限制。分类不清，文档就会把偏好伪装成真理。\n\n文章还提醒了一个常见坏味道：初始化脚本生成的 `AGENTS.md` 不能原样信任。它们通常追求“多数场景有用”，但 root instruction budget 恰好最怕这种泛用内容。新版 workflow 要求先审计 generated draft：找 contradiction、stale path、generic default、deletion candidate，再决定什么留下。\n\n这次我没有只改正文。新版 `claude-agents-bootstrap` 进入了一个更完整的 SkillOps 形态：有 `manifest.json`、`agents/interface.yaml`、trigger eval、output eval、security policy、registry、dist package 和 Review Studio 报告。它被推到 GitHub `main` 的 commit 是 `52baeafe69776ef6a9d159b5f2ed316da4655358`。旧版也保留了 tag：`claude-agents-bootstrap-before-20260623`。\n\n验证数字也写在明处：resident 初始加载估算 `994/1000`；governance score `85`；6 个 output eval case 的 with-skill pass rate 是 `100%`；5 个 runtime target conformance 通过。Review Studio 没有 blocker，但还有 6 个 warning。这里不能说“完全毕业”。AI 盲审只是 smoke evidence，不能冒充 human blind review。\n\n> 这次更新后的判断更硬：AGENTS/CLAUDE bootstrap 不是写一份漂亮根文档，而是设计一套 context routing system。root、scoped AGENTS、supporting docs、skills、checks、handoff、archive，各有各的位置。\n\n## 这次留下的判断\n\n- 写 agent 指令文档时，短 root docs 比长百科更有价值。\n- 只有被 repo、命令、测试、CI、脚本或用户明确确认支撑的事实，才应该进入规则。\n- 子目录 `AGENTS.md` 是重要工具，但它不是扩写 root 的借口。每一层都要通过 resident-budget test。\n- 能被项目读到的 mirror，不等于被 agent loader 安装。source、mirror、install root 必须分开写。\n- 生命周期报告能提高信任，但要诚实标注剩余 warning。不要把 AI 盲审说成人工盲审。\n\n> 底部再放一次 skill：[claude-agents-bootstrap](https://github.com/XJM034/SKILL/tree/main/skills/automation/claude-agents-bootstrap)。文章解释为什么它存在，真正要复用的是仓库里的操作文档。"},{"id":"143229385464352768","title":"把一次真实浏览器 QA 沉淀成 skill","slug":"chrome-live-business-qa-session-to-skill","url":"/posts/chrome-live-business-qa-session-to-skill/","summary":"将真实浏览器QA经验沉淀为可复用skill。核心是约束多角色业务测试流程：强制跨角色读回验证、写入后必须还原数据、设定停止规则避免无限测试。先落地操作清单而非博客，确保下次QA能直接复用证据、还原和判断步骤，而非仅靠复盘。","category":{"id":"143210892169842688","name":"硅基突触","slug":"silicon-synapse","type":0},"tags":["codex","skill","qa"],"createdAt":"2026-06-01T05:42:26.567Z","modifiedAt":"2026-06-09T02:13:47.777Z","readCount":0,"likeCount":0,"text":"# 把一次真实浏览器 QA 沉淀成 skill\n\nSkill first：[chrome-live-business-qa](https://github.com/XJM034/SKILL/tree/main/skills/automation/chrome-live-business-qa)。\n\n这次沉淀的不是一个漂亮结论，而是一种容易在真实项目里失控的工作：用可见 Chrome 去测一个有多角色、有真实后端、有写入副作用的业务系统。\n\n页面能打开，不等于流程通过。管理员保存成功，也不等于用户侧真的变了。导出按钮能点，也不等于导出的内容能交给真实用户。这个区别，就是这次 session 最值得留下来的地方。\n\n## 我先把经验写成可复用的操作\n\n这个 workflow 的铁律是 `skill first, blog second`。原因很直接：如果先写 blog，很容易写成一篇情绪顺滑的复盘；如果先写 skill，就必须把触发条件、输入、步骤、坑、验证清单都说清楚。\n\n所以我先落地了一个 skill：`chrome-live-business-qa`。它不是教人“怎么点浏览器”，而是约束一次真实业务 QA 该怎么开始、怎么记录、什么时候停、怎样避免把测试数据弄脏。\n\n## 最大的坑：只测当前角色\n\n在多角色系统里，一个动作经常不只影响当前页面。管理员改了老师、时间、名单、状态，真正要看的不是保存按钮变绿，而是另一个角色的页面有没有同步变化。\n\n所以 skill 里把跨角色读回放成硬步骤：写入后立刻切到受影响角色，读回详情页、列表、概览、导出内容。读不回，就不能把这个用例说成通过。\n\n这条规则很朴素，但它能拦住大量“看起来测过了”的假通过。\n\n## 第二个坑：真实数据需要还原\n\n真实后端不是沙盒。一次测试改了时间、老师、状态，如果没有还原，下一个测试、下一个同事、甚至真实用户都会踩到这次测试留下的痕迹。\n\n因此 skill 要求每个写入动作都带着恢复路径：先知道怎么撤销，再执行写入；写完读回；恢复后再读回。如果恢复失败，就把它记录为明确的 leftover cleanup，而不是把现场假装干净。\n\n## 第三个坑：测试不能无限延长\n\n长时间 live QA 很容易变成“再看一个页面”。这会让报告越来越长，但风险不一定下降。真正有用的是覆盖核心流程后停下来，把剩余工作转成最小回归集。\n\n所以 skill 里有一个 stop audit：当创建、编辑、跨角色读回、导出、登录、导航这些核心面都已有证据，就停止全量写入测试，把后续工作变成修复后的最小复测。\n\n停止也是一种工程判断。\n\n## 这次保留下来的模板\n\n除了主 skill，我还保留了 `references/case-ledger-template.md`。它用来记录每个 case 的结果、页面、步骤、读回、跨角色读回、是否写入、是否恢复，以及后续归属。\n\n这个模板的价值是让下一次 QA 不需要重新发明记录格式。它也让交接更诚实：什么已经验证，什么只是观察，什么需要用户确认，什么必须等修复后最小回归。\n\n## 这次 session 的教训\n\n- 技能沉淀不是把聊天记录复制成文章，而是把可重复的判断写成操作清单。\n- 真实业务 QA 的核心不是浏览器自动化，而是证据、还原、跨角色副作用和停止规则。\n- 个人博客版本不需要推到别人的 `Innei/SKILL` 仓库；skill 应该先进入自己的 GitHub skills 仓库，有真实、可访问、可维护的位置。\n- blog 是发现层，skill 才是下一次能复用的操作层。\n\n底部再放一次 skill：[chrome-live-business-qa](https://github.com/XJM034/SKILL/tree/main/skills/automation/chrome-live-business-qa)。这篇文章只是入口，真正要复用的是那份操作文档。"}]}