{"version":1,"note":"初始版本","published_by_client":"workhub","created_at":"2026-10-20T16:20:24.979493+00:00","guide":"接入由 AI 终端（Claude Code 或 Codex）自动完成：你把一句话发给它，它会读取接入剧本，一步步把项目接上中央工作台。你要做的是准备好下面几样东西，并在过程中确认几次。新项目、已经在做的项目都一样。\n\n### 一、准备（每台设备做一次）\n\n1. **拿到本端密钥。** 向负责中央工作台的同事要一把密钥（以 `whk_` 开头）。每台电脑或每个 AI 终端一把，不要共用，也不要发到群里。\n2. **把密钥设成环境变量 `WORKHUB_KEY`**，然后**重新打开终端**，再启动 Claude Code 或 Codex：\n   - macOS / Linux：在 `~/.zshrc` 或 `~/.bashrc` 末尾加一行 `export WORKHUB_KEY=whk_...`\n   - Windows：在 PowerShell 或命令提示符里执行 `setx WORKHUB_KEY \"whk_...\"`\n\n   不要把密钥写进项目文件。\n\n### 二、准备（每个项目）\n\n1. **项目在 Git 服务上有仓库**（Gitee、GitHub 或自建 Gogs），本地已经 clone 下来。还没有仓库的新项目，先在 Git 服务上建一个。\n2. **你能在仓库设置里添加“部署公钥”**（中央只读，不会提交代码）。没有这个权限的话，准备一个只读的访问令牌也可以。\n3. **想好标尺分支。** 前期每个项目只用一个分支，一般是 `main` 或 `master`，进度文件提交到这个分支，中央也只读这个分支。\n\n### 三、发一句话给 AI\n\n在项目根目录打开 Claude Code 或 Codex，发送：\n\n```text\n请阅读 {{ base_url }}/onboarding.md，按它把当前项目接入 workhub。\n```\n\n### 四、过程中你要确认的事\n\n| AI 会问你 | 你要做的 |\n| --- | --- |\n| 标尺分支用哪个 | 确认 `main` 或 `master` |\n| 添加部署公钥 | 把 AI 给出的公钥加到仓库的“部署公钥 / Deploy keys”，**只勾选只读**；或者给它一个只读令牌 |\n| 是否登记项目 | 确认 |\n| 进度文件的内容 | 仔细看一遍：它会公开显示在本站，不能有客户信息、服务器地址、账号密码 |\n| 目录按[项目规范](/standards)映射还是改造（已在建的项目） | 目录已经稳定就选“映射”（不动文件，只写对照关系）；想统一成标准结构就选“改造”，AI 会先列迁移计划给你看 |\n| 写入 AI 规则 | 在 `AGENTS.md` 里加一段 workhub 规则（`CLAUDE.md` 引用它），以后每次会话都按规范和流程干活；看一下内容，同意 |\n| 安装 agent 和 skill | 看一下清单（来自团队共享的能力库），没问题就同意 |\n| 提交并推送 | 看一下改动清单，同意 |\n\n### 五、接入之后\n\n- **配置 webhook（可选，建议）：** AI 会给你一个 webhook 地址（只出现一次），配到仓库的 WebHooks，触发事件选 push，不需要密码或 Secret。Gitee 在“仓库 → 管理 → WebHooks”，GitHub 在“Settings → Webhooks”。不配的话，中央每 5 分钟检查一次进度。\n- 项目会出现在本页的列表里。\n- 以后 AI 每次干活都会按[项目规范](/standards)和 [Loop 视图](/loop)执行，并随时更新进度。\n- 接入要求（当前 v{{ version }}）、项目规范或 Loop 视图更新后，再发一次同样的话，AI 会按最新要求更新项目。\n\n### 常见问题\n\n- **AI 说密钥无效（401）：** 密钥过期或已停用，找负责中央工作台的同事换一把。\n- **AI 说试拉失败：** 部署公钥没加上、加错了仓库，或者分支名不对。\n- **本页显示“进度文件解析错误”：** 让 AI 按页面上的错误提示修正 `.workhub/progress.yaml` 并重新提交。\n- **想看 AI 具体会做什么：** 打开[接入剧本](/onboarding)。\n","playbook":"# workhub 接入剧本 v{{ version }}\n\n> 给 AI 终端（Claude Code、Codex）的执行说明。人把这个链接交给你，你读完后按步骤把**当前项目**接入中央工作台 workhub。\n> 新项目、已在建的项目都适用；已经接入过的项目，重新执行一遍就会按最新要求更新。\n>\n> - 中央地址：`{{ base_url }}`。如果你打开这份剧本用的地址与它不同（比如内网地址），以你实际打开的地址为准，下文的地址都相应替换。\n> - 版本：v{{ version }}，即中央当前的接入要求版本。接入后记在 `.workhub/lock.yaml` 的 `onboarding`；以后接入要求更新了，重新执行一遍就会按新版本更新项目。\n> - 在项目仓库的根目录执行。命令以 bash 为例；Windows PowerShell 里用 `curl.exe`（`curl` 是 Invoke-WebRequest 的别名），环境变量写成 `$env:WORKHUB_KEY`。\n> - 在 Windows 上用 Python 处理含中文的内容时加 `-X utf8`（如 `python -X utf8 script.py`），否则输出可能是乱码。\n\n## 你要做成什么\n\n接入完成后，项目仓库的标尺分支（main 或 master）上会有：\n\n| 文件 | 作用 |\n| --- | --- |\n| `.workhub/progress.yaml` | 项目进度。中央从 Git 读取它，这是项目对外公开的全部内容 |\n| `.workhub/loop.md` | Loop 视图（loop-engineering 流程图）的本地副本。所有接入项目都按它干活 |\n| `.workhub/capabilities/` | 视图里用到的 agent 及其依赖的 skill，已解压 |\n| `.workhub/standards.md` | 项目规范的副本：目录、设计文件、脚本、知识库怎么放 |\n| `.workhub/layout.yaml` | 选择“映射”方式时才有：规范的各角色在本项目对应哪个目录 |\n| `.workhub/lock.yaml` | 接入状态：接入要求版本、项目 ID、分支、视图版本、规范版本、已装能力。重跑剧本时据此判断要做什么 |\n| `AGENTS.md` 里的 workhub 规则块 | 以后每次会话都要遵守的规则。Codex 直接读 `AGENTS.md` |\n| `CLAUDE.md` 第一行的 `@AGENTS.md` | 让 Claude Code 读到同一份规则 |\n| `.gitattributes` 里的一行 | 让 `.workhub/` 下的文件不做换行转换，避免签出后出现无意义的改动 |\n\n中央 workhub 只从 Git 读取进度，不会向仓库提交任何东西。\n\n## 原则\n\n- **可重复执行**：每一步先检查是否已经做过，做过就跳过或更新，不重复登记。**任何一步改动了文件，最后都要执行第 7 步提交推送。**\n- **密钥不落盘**：workhub 密钥、Git 凭据、密码箱内容都不写进仓库、提交信息、日志或 shell 历史可见的命令行参数。\n- **关键动作先问人**：确认分支、登记项目、首次的进度文件、目录选映射还是改造、写入 AI 规则、安装 agent 和 skill、提交推送之前，先给人看并得到同意。\n- **透明**：只用 git、curl 和常规命令；不下载并执行任何脚本。\n- **请求体用文件发送**：JSON 里有中文、换行或私钥时，先用脚本（如 Python）生成 UTF-8 的 JSON 文件，再 `curl --data-binary @文件` 发送，发完删除。不要在命令行里手写这类 JSON。临时文件放在系统临时目录，不要放进仓库。\n\n## 从哪一步开始\n\n先做第 0 步，再按第 1 步的结果走：\n\n| 情况 | 依次执行 |\n| --- | --- |\n| A. 中央没有登记这个仓库 | 2 → 3 → 4 → 5 → 6 → 7 → 8 |\n| B. 已登记，但项目里没有 `.workhub/lock.yaml` | 2（分支以中央记录的为准）→ 4 → 5 → 6 → 7 → 8 |\n| C. 已有 `.workhub/lock.yaml`（重跑） | 4（只检查）→ 5 → 6 →（前面有任何改动，或 `onboarding` 小于 {{ version }}，就执行 7）→ 8 |\n\n## 第 0 步：准备\n\n1. 读取环境变量 `WORKHUB_KEY`。没有的话，请人提供本端的 workhub 密钥（`whk_` 开头）。建议人自己在终端设置环境变量后重启会话；如果人直接在对话里给出，只在本次会话的 shell 里设置（bash：`export WORKHUB_KEY=...`；PowerShell：`$env:WORKHUB_KEY=\"...\"`），不写进任何文件。\n2. 校验密钥：\n\n```bash\ncurl -s -w \"\\n%{http_code}\\n\" {{ base_url }}/v1/whoami -H \"Authorization: Bearer $WORKHUB_KEY\"\n# 200 → {\"client\": \"build-server-02\", ...}   401 表示密钥无效或已过期，请人确认\n```\n\n   AI 终端的每条命令往往在新的 shell 里执行，环境变量不会保留。最好请人在启动 AI 终端之前就设置好 `WORKHUB_KEY`；否则每条命令前都要重新设置。\n\n3. 确认当前目录是 Git 仓库，并有远端：`git remote get-url origin`。\n   - 没有远端的新项目：请人先在 Gitee、GitHub、Gogs 等创建仓库（或在 `gh` 已登录时用 `gh repo create`），设为 `origin` 并推送一次。\n   - 远端是 `file://` 或本地路径：中央在另一台服务器上，通常访问不到，请人确认（只有中央和项目在同一台机器上的测试环境才能这样登记，此时 `git_credential` 随便填一个令牌即可）。\n\n## 第 1 步：识别项目状态\n\n1. 有 `.workhub/lock.yaml`：读出 `project_id`，`GET {{ base_url }}/v1/projects/<project_id>`。\n   - 200：走情况 C。\n   - 404：中央已没有这个项目。告诉人，人同意后删掉 `lock.yaml`，按下面第 2 条重新判断。\n2. 没有 `lock.yaml`，按仓库地址查询：\n\n```bash\ncurl -s -G {{ base_url }}/v1/projects/lookup --data-urlencode \"repo_url=$(git remote get-url origin)\" \\\n  -H \"Authorization: Bearer $WORKHUB_KEY\"\n# 200 → 情况 B，记下 project_id 和 status_ref\n# 404（not_registered）→ 情况 A\n```\n\n## 第 2 步：确认标尺分支\n\n前期每个项目只用一个分支（main 或 master），中央也读这个分支。\n\n1. 情况 B：用 lookup 返回的 `status_ref`。\n2. 情况 A：查远端默认分支 `git ls-remote --symref origin HEAD`（输出 `ref: refs/heads/main\tHEAD`），取不到就看有没有 `main` 或 `master`。\n3. **问人确认**：“标尺分支用 `<分支>`，进度文件和 workhub 文件都提交到这个分支，可以吗？”之后的工作都在这个分支上做。\n\n## 第 3 步：登记项目\n\n中央需要一份**只读**凭据来拉取仓库。选一种，**告诉人你要怎么做**：\n\n- **A. SSH 部署密钥（推荐）**。在系统临时目录（不在仓库内）生成一对密钥：\n\n```bash\nssh-keygen -t ed25519 -N \"\" -C \"workhub-readonly\" -f \"<临时目录>/workhub_deploy\"\n```\n\n  把公钥 `workhub_deploy.pub` 加到仓库的“部署公钥 / Deploy keys”（只读）：\n  - GitHub 且 `gh` 已登录：`gh repo deploy-key add \"<临时目录>/workhub_deploy.pub\" --title workhub-readonly`\n  - 其他情况：把公钥内容给人，请人在 Gitee / GitHub / Gogs 的仓库设置里添加，完成后告诉你。\n\n  仓库地址用 SSH 形式（如 `git@gitee.com:team/order.git`）。私钥全文放进请求体 JSON 时用脚本读取文件生成（换行要正确转义），登记完成后删除私钥、公钥和请求体文件。\n- **B. 只读令牌**：请人提供一个只读的 HTTPS 访问令牌。仓库地址用 `https://` 形式。`username` 可选，Gitee 等要求填真实用户名时再填。\n\n请求体（用脚本生成 UTF-8 文件 `<临时目录>/register.json`）：\n\n```json\n{\n  \"repo_url\": \"git@gitee.com:team/order.git\",\n  \"status_ref\": \"main\",\n  \"name\": \"订单服务\",\n  \"git_credential\": {\"auth\": \"ssh_key\", \"private_key\": \"-----BEGIN OPENSSH PRIVATE KEY-----\\n...\\n-----END OPENSSH PRIVATE KEY-----\\n\"}\n}\n```\n\n`git_credential` 也可以是 `{\"auth\": \"https_token\", \"token\": \"<令牌>\"}`。`name` 用项目名称（不超过 40 字）。**问人确认后**登记：\n\n```bash\ncurl -sX POST {{ base_url }}/v1/projects -H \"Authorization: Bearer $WORKHUB_KEY\" \\\n  -H \"Content-Type: application/json; charset=utf-8\" --data-binary @\"<临时目录>/register.json\"\n# 201 → {\"project_id\": \"prj_...\", \"status_ref\": \"main\", \"webhook_url\": \"...\", ...}\n```\n\n- 409 `already_registered`：这个仓库已经登记过，响应里有 `project_id`，按情况 B 继续。\n- 502：中央试拉失败（公钥还没加好、地址不对、分支不存在），按 `message` 处理后重试。\n- `webhook_url` 只返回这一次：让登记响应直接输出到终端，把地址交给人，建议配到 Git 服务的 push webhook（不配的话中央每 5 分钟拉一次）。**不要写进仓库或任何文件。** 丢了可以由登记它的端调 `POST {{ base_url }}/v1/projects/<project_id>/webhook` 重新生成（旧地址失效）。\n\n## 第 4 步：进度文件\n\n按附录 A 的格式写 `.workhub/progress.yaml`（先建好 `.workhub/` 目录），`project_id` 用登记得到的。已有这个文件时（情况 C、D），只检查格式和 `project_id`，不改内容。\n\n- **新项目**：`summary` 写项目要做什么、目前刚开始；`items` 列出已经开始的工作和接下来计划做的工作（`planned`）。\n- **已在建的项目**：阅读 README、文档、近期提交（`git log --oneline -30`）、TODO 或任务清单，归纳出：\n  - `summary`：一句话现状；\n  - `phase`：当前阶段；\n  - `progress`：整体进度，按已完成的工作占全部工作的比例粗估，拿不准就不写；\n  - `items`：近期要做的、进行中、阻塞、刚完成或刚失败的工作（最多 20 条）。还没开始的计划写成 `planned`；阻塞的写清原因；\n  - `milestones`：近期达成的里程碑，新的在前；\n  - `updated_at`：写文件时的当前时间，带时区。\n\n提交前校验（请求体同样用脚本生成）：\n\n```bash\n# <临时目录>/progress.json 的内容：{\"project_id\": \"<project_id>\", \"content\": \"<progress.yaml 全文>\"}\ncurl -sX POST {{ base_url }}/v1/progress/validate -H \"Authorization: Bearer $WORKHUB_KEY\" \\\n  -H \"Content-Type: application/json; charset=utf-8\" --data-binary @\"<临时目录>/progress.json\"\n# → {\"ok\": true, ...} 或 {\"ok\": false, \"error\": \"...\"}\n```\n\n首次写入时**把内容给人确认**（这个文件对外网公开）。\n\n## 第 5 步：项目规范、AI 规则和换行设置\n\n项目规范规定干活的产出放在哪、怎么留存（目录、设计文件、脚本、知识库）；AI 规则块写进 `AGENTS.md`，让以后每次会话都按规范和 Loop 视图干活。两者在中央同属一个版本。\n\n1. 下载规范：\n\n```bash\ncurl -s -o \"<临时目录>/standards.md\" -D \"<临时目录>/standards.headers\" {{ base_url }}/standards.md\n# 版本号在响应头 X-Standards-Version\n```\n\n   复制到 `.workhub/standards.md`。\n\n2. **目录适配**（`lock.yaml` 里已经有 `standards_version` 的项目跳过这一条，除非规范的目录要求变了）：\n   - **新项目**：按规范的默认位置建目录（`docs/design/`、`docs/knowledge/`、`scripts/` 等，空目录可以先不建，用到时再建），并按范本写一个 `docs/knowledge/index.md`。\n   - **已在建的项目**：**问人选映射还是改造**。\n     - 映射：读现有目录，按规范“已在建的项目”一节写 `.workhub/layout.yaml`，列出各角色在本项目对应的目录，给人确认。\n     - 改造：对照规范末尾的范本，列出迁移计划（哪些文件移到哪里、要新建哪些文件），给人确认后执行。改造单独提交一次，不和接入的其他改动混在一起。\n\n3. 写 AI 规则块（已填好项目 ID、分支、地址）：\n\n```bash\ncurl -s \"{{ base_url }}/standards/agents.md?project_id=<project_id>\"\n```\n\n   - `AGENTS.md`：没有就新建，内容就是规则块。已有的话，找 `<!-- workhub:begin` 开头的行到 `<!-- workhub:end -->` 的一段，整段替换；没有这一段就在文件末尾空一行后追加。项目原有的内容不要改动。文件以换行结尾。\n   - `CLAUDE.md`：没有就新建；第一行是 `@AGENTS.md`（已有这一行就不动）。Claude Code 通过它读取同一份规则，Codex 直接读 `AGENTS.md`。\n   - 规则块有变化时，**把新旧差异给人看并确认**后再写入。\n\n4. `.gitattributes` 里没有 `.workhub/** -text` 这一行就加上（没有这个文件就新建），避免换行转换让 `.workhub/` 下的文件在签出后出现无意义的改动。\n\n内容与原来一致就算没有改动。\n\n## 第 6 步：Loop 视图、agent 和 skill\n\n所有接入项目都必须按 Loop 视图干活。视图和其中用到的 agent、skill 来自 workhub 能力库，由团队的各个端发布。它们会写进项目，以后的会话会按它们执行，所以**安装前要给人看**。\n\n1. 下载视图到临时文件，检查状态码：\n\n```bash\ncurl -s -o \"<临时目录>/loop.md\" -D \"<临时目录>/loop.headers\" -w \"%{http_code}\" {{ base_url }}/v1/loop/content\n# 200 → 版本号在响应头 X-Loop-Version\n# 404 → 中央还没有视图：跳过本步，lock.yaml 的 loop_version 记 0、capabilities 记 []\n```\n\n2. 取视图用到的全部 agent 和 skill（已去重）：\n\n```bash\ncurl -s {{ base_url }}/v1/loop/resolve -H \"Authorization: Bearer $WORKHUB_KEY\"\n# → {\"loop_version\": 2, \"items\": [{\"id\": \"public/backend-dev\", \"type\": \"agent\", \"version\": 1, \"status\": \"active\",\n#     \"content_sha256\": \"...\", \"content_path\": \"/v1/capabilities/public/backend-dev/versions/1/content\"}, ...]}\n# 410 → 视图引用了已下架的版本：停下来告诉人\n```\n\n3. 与 `lock.yaml` 对比，找出要新装或更新的项（`id`、`version`、`content_sha256` 有一个不同，或目录不存在）和要删除的项（lock 里有、清单里没有）。没有任何变化、视图版本也没变，就跳到第 5 条。\n4. 把要新装或更新的包下载到临时目录，校验并只读查看：\n   - 下载：`curl -s -o \"<临时目录>/<名称>.zip\" {{ base_url }}<content_path> -H \"Authorization: Bearer $WORKHUB_KEY\"`；\n   - 校验 SHA-256 与 `content_sha256` 一致（`sha256sum`、`shasum -a 256`、`certutil -hashfile <文件> SHA256` 或 Python），不一致就停止并告诉人；\n   - 列出包里的文件：`python -X utf8 -m zipfile -l <zip>`，读出 `manifest.yaml`。中央在发布时已经拒绝了路径穿越、绝对路径和符号链接，这里再看一眼文件名即可。\n\n   **给人看并确认**：视图版本和更新说明（`GET {{ base_url }}/v1/loop` 的 `note`），要安装、更新、删除的能力清单，每个包的 `manifest.yaml` 和文件列表；`status` 为 `deprecated` 的一并告诉人。人同意后：\n   - 解压到临时目录（`python -X utf8 -m zipfile -e <zip> <目录>`、PowerShell `Expand-Archive` 或 `unzip`），再替换到 `.workhub/capabilities/<id>/`（如 `.workhub/capabilities/public/backend-dev/`，先删除旧目录）；\n   - 删除清单里已经没有的能力目录，以及因此变空的范围目录；\n   - 把视图从临时文件复制到 `.workhub/loop.md`。\n\n   人不同意就停在这里，不改动项目里的视图和能力。\n5. 上报本项目在用的全部能力（清单里的每一项，包括 skill）。每次执行本步都上报一次：\n\n```bash\n# 请求体：{\"project_id\": \"<project_id>\", \"items\": [{\"id\": \"public/backend-dev\", \"version\": 1}, ...]}\ncurl -sX POST {{ base_url }}/v1/capabilities/installed -H \"Authorization: Bearer $WORKHUB_KEY\" \\\n  -H \"Content-Type: application/json; charset=utf-8\" --data-binary @\"<临时目录>/installed.json\"\n```\n\n## 第 7 步：写接入状态并提交\n\n1. 写 `.workhub/lock.yaml`（`capabilities` 与 `.workhub/capabilities/` 下的目录一一对应，顺序与 `/v1/loop/resolve` 的清单一致；`sha256` 是 zip 包的 `content_sha256`，不是解压后文件的）：\n\n```yaml\n# 由 workhub 接入剧本维护，不要手改\nonboarding: {{ version }}\nproject_id: prj_01JB8XQ2M4\nstatus_ref: main\nloop_version: 2\nstandards_version: 1\ncapabilities:\n  - {id: public/backend-dev, version: 1, sha256: \"<64 位>\"}\n```\n\n2. **把改动清单给人确认**（`git status`、`git diff --stat`），确认没有把密钥、私钥、令牌、webhook 地址、密码箱内容加进去，然后在标尺分支上提交并推送：\n\n```bash\ngit add .workhub AGENTS.md CLAUDE.md .gitattributes\ngit commit -m \"接入 workhub（接入剧本 v{{ version }}）\"   # 首次接入\n# 重跑时写明改了什么，如：git commit -m \"更新 workhub 接入：Loop 视图 v2，新增 public/doc-writer\"\n# 你的工具自带的署名行可以照常附加\ngit push origin <标尺分支>\n```\n\n## 第 8 步：验收并汇报\n\n```bash\ncurl -sX POST \"{{ base_url }}/v1/projects/<project_id>/sync?wait=true\" -H \"Authorization: Bearer $WORKHUB_KEY\"\n# updated / file_unchanged / unchanged：成功\n# parse_error：看 error，修正进度文件后回到第 7 步\n# error：中央拉取失败，GET /v1/projects/<project_id>/sync-log 看原因\n```\n\n向人汇报：项目 ID、项目页面 `{{ base_url }}/projects/<project_id>`、视图版本、装了哪些能力、本次改动了什么，以及需要人处理的事（如配置 webhook；中央无法判断 webhook 是否已配置，只能问人）。\n\n---\n\n## 附录 A：进度文件 `.workhub/progress.yaml`\n\n```yaml\nschema: workhub/progress/v1\nproject_id: prj_01JB8XQ2M4        # 登记时分配，必须一致\nname: 订单服务\nsummary: 退款功能开发中，预计本周完成联调   # 一句话现状\nphase: 实现                        # 当前阶段，自由文本\nprogress: 60                       # 整体进度 0–100，可选\nupdated_at: 2026-10-20T16:00:00+08:00\n\nitems:                             # 计划中、进行中、阻塞或刚结束的工作，最多 20 条\n  - id: refund                     # 项目内稳定标识\n    title: 订单退款\n    state: blocked                 # planned / running / blocked / done / failed / cancelled\n    stage: 前后端实现\n    progress: 60\n    blocked_reason: 等待接口字段确认  # state 为 blocked 时必填\n    updated_at: 2026-10-20T15:40:00+08:00\n\nmilestones:                        # 近期里程碑，最多 20 条，新的在前\n  - date: 2026-10-18\n    title: 退款接口设计评审通过\n```\n\n| 字段 | 必填 | 规则 |\n| --- | --- | --- |\n| schema | 是 | 固定为 `workhub/progress/v1` |\n| project_id | 是 | 与登记返回的一致 |\n| name | 是 | 不超过 40 字 |\n| summary | 是 | 不超过 200 字 |\n| phase | 否 | 不超过 20 字 |\n| progress | 否 | 0–100 的整数 |\n| updated_at | 是 | ISO 8601，带时区 |\n| items[].id、title、state | 是 | id 为字母数字和 `_.-`；title 不超过 100 字 |\n| items[].stage | 否 | 不超过 20 字 |\n| items[].blocked_reason | blocked 时必填 | 不超过 200 字 |\n| milestones[].date、title | 是 | date 为 YYYY-MM-DD |\n\n文件不超过 64 KB；对外网公开，只写可以公开的概括；标尺分支禁止 force push 和删除。不合规时中央保留上一份合规内容，页面上显示解析错误。\n\n## 附录 B：密码箱\n\n一条凭据 = 标题和说明（公开）+ 内容（任意文本，加密）。默认私有（只有本端能取用），`public` 则所有端都能取用。只有创建它的端能修改和撤销。\n\n```bash\n# 存（请求体用脚本生成）：{\"title\": \"订单服务测试环境管理员\", \"description\": \"测试后台登录\", \"project_id\": \"<project_id>\", \"visibility\": \"public\", \"content\": \"...\"}\ncurl -sX POST {{ base_url }}/v1/secrets -H \"Authorization: Bearer $WORKHUB_KEY\" \\\n  -H \"Content-Type: application/json; charset=utf-8\" --data-binary @\"<临时目录>/secret.json\"\n# 列出本端能取用的（只有公开字段），可加 &project_id=... 过滤\ncurl -s \"{{ base_url }}/v1/secrets?mine=true\" -H \"Authorization: Bearer $WORKHUB_KEY\"\n# 一次取回多条内容（最多 50 条）\ncurl -sX POST {{ base_url }}/v1/secrets/values -H \"Authorization: Bearer $WORKHUB_KEY\" -H \"Content-Type: application/json\" \\\n  -d '{\"ids\": [\"sec_xxxxxxxxxx\", \"sec_yyyyyyyyyy\"]}'\n```\n\n创建者还可以 `PATCH /v1/secrets/{sid}`、`PUT /v1/secrets/{sid}/content`（版本加 1）、`POST /v1/secrets/{sid}/revoke`。`GET /v1/audit-log` 看本端的取用和本端凭据被谁取用。\n\n## 附录 C：能力库\n\n能力是 Skill 或 Agent 的 zip 包，根目录必须有 `manifest.yaml`。标识 `public/<名称>` 为公共能力，`<project_id>/<名称>` 为项目私有能力。\n\n```bash\ncurl -s {{ base_url }}/v1/capabilities                                                   # 浏览\ncurl -s {{ base_url }}/v1/capabilities/public/backend-dev/versions/latest/resolve -H \"Authorization: Bearer $WORKHUB_KEY\"\n# 推送自己封装的能力\ncurl -sX POST {{ base_url }}/v1/capabilities -H \"Authorization: Bearer $WORKHUB_KEY\" -H \"Content-Type: application/json\" \\\n  -d '{\"id\": \"<project_id>/refund-checker\", \"type\": \"skill\"}'\ncurl -sX POST {{ base_url }}/v1/capabilities/<project_id>/refund-checker/versions \\\n  -H \"Authorization: Bearer $WORKHUB_KEY\" -H \"Content-Type: application/zip\" --data-binary @refund-checker.zip\n```\n\n```yaml\n# manifest.yaml\ntype: skill            # skill 或 agent\nname: 退款校验\ndescription: 校验退款规则\nscenarios: [退款开发]   # 适用场景，可选\n# agent 才有：依赖的 skill 及版本。公共能力只能依赖公共能力\n# skills:\n#   - {id: public/api-impl, version: 2}\n```\n\n版本发布后不可修改，单包不超过 10 MB。创建者可以废弃（`.../versions/{v}/deprecate`）或下架（`.../versions/{v}/yank`，需填原因）。\n\n## 附录 D：Loop 视图\n\n全局一张，md 文件，开头是 YAML 头：\n\n```markdown\n---\nschema: workhub/loop/v1\nname: 后端需求交付\nentry: design\nnodes:\n  - id: design                        # 小写字母、数字、_、-；不能叫 done\n    name: 接口设计\n    agent: public/api-designer        # 默认用最新版；写 @版本号 锁定\n    rules:\n      - 输出接口文档，评审通过才进入下一步\n    next:\n      - to: implement\n  - id: implement\n    name: 编码实现\n    agent: public/backend-dev\n    next:\n      - {to: done, when: 测试通过}                     # done 表示结束\n      - {to: implement, when: 测试失败, max_loops: 3}   # 回到前面的节点就是 loop\n---\n\n## 说明\n\n（自由文本）\n```\n\n并行：`to: [a, b]` 表示分叉，a、b 同时开始；各分支最后汇到同一个标了 `join: all` 的节点，所有分支完成后才开始它。分支里不能再分叉、不能回环、不能直接到 `done`。执行到分叉时，按视图正文的说明启动并行子任务。\n\n要改进视图：基于最新版修改后发布，`base_version` 填下载时的版本号；期间有别的端发布了新版本会返回 409（`version_conflict`），先下载最新版覆盖本地再改。请求体 `{\"base_version\": 3, \"content\": \"<整个 md 文件的内容>\", \"note\": \"更新说明\"}` 用脚本生成：\n\n```bash\ncurl -sX POST {{ base_url }}/v1/loop -H \"Authorization: Bearer $WORKHUB_KEY\" \\\n  -H \"Content-Type: application/json; charset=utf-8\" --data-binary @\"<临时目录>/loop.json\"\n```\n\n## 附录 E：错误\n\n| 状态码 | 含义 |\n| --- | --- |\n| 400 / 422 | 参数不合法，`message` 里有原因 |\n| 401 | 密钥无效、已删除或已过期 |\n| 403 | 不是创建者，或取用别的端的私有凭据 |\n| 404 | 不存在 |\n| 409 | 仓库已登记（`already_registered`，带 `project_id`）；Loop 视图或接入要求的版本冲突（`version_conflict`） |\n| 410 | 已撤销或已下架 |\n| 429 | 请求过多 |\n| 502 | 中央访问 Git 仓库失败 |\n\n完整接口文档：{{ base_url }}/v1/docs\n\n## 附录 F：维护接入要求\n\n本剧本和首页的《接入一个项目》说明合在一起，是中央的“接入要求”，按版本维护，任何端都能发布新版本：\n\n```bash\n# 取当前版本的原文：{\"version\": 3, \"guide\": \"<首页说明 md>\", \"playbook\": \"<本剧本 md>\", \"note\": ..., ...}\ncurl -s {{ base_url }}/v1/onboarding\n# 基于它修改后发布。请求体（用脚本生成）：{\"base_version\": 3, \"guide\": \"...\", \"playbook\": \"...\", \"note\": \"更新说明\"}\ncurl -sX POST {{ base_url }}/v1/onboarding -H \"Authorization: Bearer $WORKHUB_KEY\" \\\n  -H \"Content-Type: application/json; charset=utf-8\" --data-binary @\"<临时目录>/onboarding.json\"\n```\n\n- `base_version` 与中央当前版本不一致会返回 409（`version_conflict`）：先取最新版本，再修改后发布。\n- 两个文件里可以用占位符 `\\{{ base_url }}`（中央地址）和 `\\{{ version }}`（版本号），中央返回时替换；要原样显示占位符本身，在前面加反斜杠（`\\\\{{ base_url }}`）。\n- 历史版本：`GET {{ base_url }}/v1/onboarding/versions`。要回退，就用旧版本的内容重新发布一版。\n\n## 附录 G：维护项目规范\n\n项目规范（`standards.md`，含对照范本）和 AI 规则块（`agents_rules.md`）同属一个版本，任何端都能发布新版本，规则与接入要求相同：\n\n```bash\ncurl -s {{ base_url }}/v1/standards          # 当前版本原文：{\"version\": 2, \"standards\": \"...\", \"agents_rules\": \"...\", ...}\n# 请求体：{\"base_version\": 2, \"standards\": \"...\", \"agents_rules\": \"...\", \"note\": \"更新说明\"}\ncurl -sX POST {{ base_url }}/v1/standards -H \"Authorization: Bearer $WORKHUB_KEY\" \\\n  -H \"Content-Type: application/json; charset=utf-8\" --data-binary @\"<临时目录>/standards.json\"\n```\n\n两个文件里可以用占位符 `\\{{ base_url }}`、`\\{{ version }}`；规则块另有 `\\{{ project_id }}`、`\\{{ branch }}`。\n"}