diff --git a/AGENTS.md b/AGENTS.md index 8d0d5d3..643d22f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -34,21 +34,20 @@ skiff status ``` skills/ ├── _template/ # 新建 skill 的脚手架 +├── ack/ # 完整 ACK skill,含 references/templates/scripts ├── declarative-openspec-loop/ # 自研 skill,必须含 SKILL.md │ ├── SKILL.md │ └── reference.md ├── discussion-notes/ # 讨论沉淀笔记 │ ├── SKILL.md │ └── reference.md -kits/ -└── agent-collaboration-kit/ # 可复制到项目的协作规范包,不是 skill skiff/ # CLI 源码(Python 3) bin/skiff # CLI 入口 registry.yaml # 外部 Git skill 来源目录 AGENTS.md # 本文档 ``` -**本仓库包含**:`skills/`、`kits/`、`skiff/`、`bin/skiff`、`registry.yaml`、`AGENTS.md` +**本仓库包含**:`skills/`、`skiff/`、`bin/skiff`、`registry.yaml`、`AGENTS.md` **本仓库不包含**:各项目的 skill 启用清单 --- @@ -68,20 +67,13 @@ AGENTS.md # 本文档 新建 skill:复制 `skills/_template/` → `skills//`,编辑 `SKILL.md`,在本仓库 commit。 -### 规范包(Kits,不是 Skill) +Skill 需要的稳定规范、模板、示例和脚本直接放在自己的目录中,例如 +`skills/ack/references/`、`templates/`、`examples/` 和 `scripts/`。项目初始化只生成 +项目状态,不复制或链接 Skill 内容: -`kits/` 放可复制到项目的流程规范、模板、检查清单和示例资料。它们不是 Agent Skill: - -- 不放 `SKILL.md` frontmatter -- 不由 `skiff install` / `skiff add` 安装 -- 不会被 Agent 自动触发加载 -- 使用方式是复制到目标项目文档目录,或在目标项目 `AGENTS.md` 中引用 - -| Kit | 说明 | 推荐落地位置 | -| --- | --- | --- | -| [ack](kits/ack/README.md) | 多 Agent 协作闭环规范包 | `docs/ack/` | - -新建规范包:创建 `kits//README.md`,写清适用场景、复制到项目后的推荐目录、需要项目填充的占位符,并在本仓库 commit。已有 kit 可通过 `skiff kit init ` 初始化到项目。 +```bash +skiff init ack +``` ### 外部(External Git) @@ -136,8 +128,8 @@ npx skills find typescript 1. **SSOT** — 自研 skill 只存在于 `skills//`,不在 Agent 目录直接创建 2. **项目自治** — 每个项目自己维护 `.skills.yaml`,本仓库不维护项目清单 3. **软链优先** — 通过 symlink 映射到 Agent 目录,改 skill 即改 SSOT -4. **类型分离** — `skills/` 只放可安装 skill;非 skill 的规范包、模板包放 `kits/` -5. **一体维护** — skill、规范包与 CLI 同仓库维护;需要时再与独立 skiff 仓库同步 +4. **能力内聚** — Skill 使用的规范、模板和脚本与 `SKILL.md` 同目录维护 +5. **一体维护** — skill 与 CLI 同仓库维护;需要时再与独立 skiff 仓库同步 --- @@ -146,7 +138,6 @@ npx skills find typescript ``` skills 仓库(本仓库) skiff CLI skills// ←── skiff install / enable -kits// ←── 手动复制 / 项目文档引用 skiff/ ←── python3 -m skiff registry.yaml ←── skiff add / fetch ↑ @@ -173,7 +164,6 @@ registry.yaml ←── skiff add / fetch | 类型 | 位置 | 维护方式 | | --- | --- | --- | -| **Kit** | `kits//` | 本仓库 commit;复制到目标项目 `docs/` 或由项目 `AGENTS.md` 引用 | | **OpenSpec 配置** | `openspec/` | 本仓库 commit;服务于本仓库自身的规格流程 | diff --git a/README.md b/README.md index 8acf290..550cc3d 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,6 @@ skiff status ``` skills/ # 自研 skill(SSOT):每个子目录必须有 SKILL.md -kits/ # 可复制到项目的规范包 / 模板包,不是 Agent Skill skiff/ # CLI 源码(Python 3) bin/skiff # CLI 入口 registry.yaml # 外部 Git skill 目录 @@ -28,8 +27,7 @@ AGENTS.md # 详细规范与架构说明 | 路径 | 说明 | |------|------| -| [skills/](skills/) | 自研 skill,每个子目录含 `SKILL.md` | -| [kits/](kits/) | 项目规范包、协作模板、可复制资料,不由 skiff 安装 | +| [skills/](skills/) | 自研 skill,每个子目录含 `SKILL.md`,可附带 references、templates 和 scripts | | [skiff/](skiff/README.md) | 安装、软链、健康检查 CLI | | [registry.yaml](registry.yaml) | 外部 Git skill 注册表 | | [AGENTS.md](AGENTS.md) | 设计原则、编写规范、架构详解 | @@ -43,18 +41,11 @@ AGENTS.md # 详细规范与架构说明 | [declarative-openspec-loop](skills/declarative-openspec-loop/SKILL.md) | 声明式编程循环:用户提供校验方式,Agent 自动迭代直到通过 | | [discussion-notes](skills/discussion-notes/SKILL.md) | 讨论沉淀:边讨论边维护 Markdown 笔记 | -## 规范包(不是 Skill) - -`kits/` 用来维护可复制到项目里的规范说明、模板和检查清单。它们没有 `SKILL.md`,不会被 `skiff install`、`skiff add` 或 Agent 自动加载。 - -| Kit | 说明 | -|-----|------| -| [ack](kits/ack/README.md) | 多 Agent 协作闭环规范包,通过 `skiff kit init ack` 初始化到项目 `docs/ack/` | +ACK 是包含规范、模板与校验脚本的完整 Skill。安装 Skill 后可初始化当前项目状态: ```bash -skiff kit init ack # 当前项目,软链接到 SSOT(推荐) -skiff kit init ack --project ~/app # 指定项目 -skiff kit init ack --copy # 整份复制,后续需手动升级 +skiff init ack +skiff init ack --project ~/app ``` 新建 skill: @@ -122,7 +113,6 @@ npx skills find typescript ``` 本仓库 ├── skills// ←── skiff install / enable -├── kits// ←── 手动复制 / 项目文档引用 ├── registry.yaml ←── skiff add / fetch └── skiff/ ←── python3 -m skiff ↑ @@ -140,7 +130,7 @@ npx skills find typescript 1. **SSOT** — 自研 skill 只存在于 `skills//` 2. **项目自治** — 各项目自行维护 `.skills.yaml` 3. **软链优先** — 通过 symlink 映射到 Agent 目录,改 skill 即改 SSOT -4. **规范包分离** — 非 skill 的流程规范、模板包放在 `kits//`,不混入 `skills/` +4. **能力内聚** — Skill 所需规范、模板和脚本与 `SKILL.md` 放在同一目录 5. **一体维护** — skill 与 CLI 同仓库,Python 3 直接运行,无需编译 ## 文档 diff --git a/kits/ack/README.md b/kits/ack/README.md deleted file mode 100644 index c1bda12..0000000 --- a/kits/ack/README.md +++ /dev/null @@ -1,175 +0,0 @@ -# ack — Agent Collaboration Kit - -`ack`(Agent Collaboration Kit)是一套可复用到其它项目的多 Agent 协作规范,默认三个独立角色:**Coordinator (PM) 拆解需求并调度闭环,Developer 实现与白盒验证,Test 独立黑盒复测**。关键属性是验证者 ≠ 实现者。角色默认按成本分层:Coordinator 用强模型(且不亲自跑测试),Test/Developer 用中低模型(见 `core/model-routing.md`)。 - -当前版本见 `VERSION`。这不是 Agent Skill(无 `SKILL.md`),不由 skiff 安装,而是复制/引用到目标项目。 - ---- - -## 适用场景 - -- 多个 Agent 分工协作,而非单个 Agent 从需求写到代码。 -- 需要区分规格、测试、实现、复测的责任边界(Coordinator / Test / Developer 三角色)。 -- 需要把失败项派发给 Developer,`worker_done` 后由独立的 Test 复测、Coordinator 终检。 -- 需要连续修复多个问题,并把三轮仍未修好的问题留档。 - ---- - -## 目录结构 - -```text -ack/ - VERSION # kit 版本,接入时记入项目 - README.md - init-new-project.md # 给 Agent 的新项目初始化手册 - adoption-checklist.md - core/ # 稳定核心:跨项目通用,随 kit 升级,尽量别改 - kickoff.md # 如何开始一个需求(启动手册 + 开场指令模板) - roles-and-permissions.md # 角色/权限/状态机/完成定义(SSOT) - model-routing.md # 三角色默认模型档位 + 升级规则(SSOT) - closed-loop.md # 编排无关闭环 + 手动模式 + worktree 对齐 - optimization-method.md # 验收信号 + 三轮失败策略(SSOT) - prompt-templates.md # 派发 prompt 模板 - orca-adapter.md # Orca 具体命令(一种编排实现,可选) - templates/ # 项目覆盖层:复制一次并填空 - project.template.md # 项目覆盖层模板(文件名可配置,默认不占用 AGENTS.md) - tasks.template.yaml - tasks.schema.json # 任务板权威结构(跨语言) - examples/ # 填好的最小可跑示例 - project.example.md - tasks.example.yaml - scripts/ - validate_tasks.py # 校验 tasks.yaml(参考实现) -``` - -**核心原则**:`core/` 是稳定核心,每个概念只定义一次;`templates/` 是项目覆盖层。二者分离,让 kit 升级和项目定制互不干扰。 - ---- - -## 项目目录布局(推荐) - -每个项目在 `docs/ack/` 下只放**一个软链接**加两个项目文件,稳定核心全部走软链接: - -```text -/docs/ack/ - kit -> <此框架目录> # 唯一软链接:core/templates/examples/scripts 全在里面 - project.md # 项目覆盖层(差异),可改名,见下 - tasks.yaml # 项目任务板 -``` - -引用稳定核心时统一走 `kit/` 前缀,例如 `docs/ack/kit/core/roles-and-permissions.md`。 -这样「一个项目一个软链接」,kit 升级自动生效,项目定制(`project.md` + `tasks.yaml`)互不干扰。 - -## 分发方式(二选一) - -### 方式 A:单软链接引用(推荐,可升级) - -把本框架目录整体 symlink 成项目的 `docs/ack/kit`: - -```bash -mkdir -p /docs/ack -ln -s <此框架绝对路径> /docs/ack/kit -``` - -也可用 git submodule / sparse checkout 达到同样效果。项目只维护 `project.md` 与 `tasks.yaml`。 - -### 方式 B:整份复制(简单,手动升级) - -把本框架整目录复制成 `docs/ack/kit/`(或直接铺平到 `docs/ack/`,此时引用去掉 `kit/` 前缀)。**务必**在 `project.md` 与 `tasks.yaml` 的 `kitVersion` 记录来源版本,日后照 `VERSION` diff 升级。 - -### 覆盖层文件名(重要) - -项目差异(路径、命令、handle、模型档位)写在**项目覆盖层文件**里,**默认 `docs/ack/project.md`,不占用 `AGENTS.md`**,以免与团队已有的 `AGENTS.md` 约定冲突。文件名可配置:想让 Agent 自动加载,可在 `AGENTS.md` 加一行指向它,或直接命名为 `AGENTS.md`。无论叫什么,都在 `tasks.yaml` 的 `project.overlayFile` 记录实际路径。覆盖层只填差异,不复制 `core/` 内容。 - ---- - -## 快速接入 - -让 Agent 在新项目执行初始化时,优先给它 `init-new-project.md`。 - -1. 建 `docs/ack/`,按方式 A 建单软链接 `kit`。 -2. 复制 `kit/templates/project.template.md` → `docs/ack/project.md`,填项目差异与模型档位,记 `kitVersion`。 -3. 复制 `kit/templates/tasks.template.yaml` → `docs/ack/tasks.yaml`,填 `project`(含 `overlayFile`)与首个任务。 -4. 跑 `python3 docs/ack/kit/scripts/validate_tasks.py docs/ack/tasks.yaml` 确认结构。 -5. 按 `kit/core/closed-loop.md` 跑闭环(Orca 见 `kit/core/orca-adapter.md`,无 Orca 用手动模式)。 -6. 逐项对照 `kit/adoption-checklist.md`。 - -参考 `examples/` 里填好的 `project.example.md` 与 `tasks.example.yaml`。 - ---- - -## 常用使用方法 - -### 开一个新需求(最常用) - -你(强模型会话)就是 Coordinator(PM)。完整手册见 `core/kickoff.md`,开场指令: - -```text -我要做一个新需求:<一句话需求>。你作为 ack 的 Coordinator(PM),按 docs/ack/kit/core 规范: -先读 project.md 与 core/*;写产品文档到 docs/ 并把需求拆成带可观测验收信号的任务写进 docs/ack/tasks.yaml; -先给我确认产品文档+任务拆分,再按 project.md 优先复用空闲 DEV/TEST worker,没有时才校验并创建,核对实际模型后循环派发/复测/终检; -每个任务最多三轮,三轮不过记 leftover。 -``` - -### 复用或启动 worker - -先按 `core/orca-adapter.md` §「解析并复用 worker」运行 `terminal list` 和活跃任务查询。只有没有同 worktree、同角色、配置兼容的空闲 worker 时,才执行下面的创建命令: - -```bash -DEV_CMD='codex --dangerously-bypass-approvals-and-sandbox -m gpt-5.6-terra -c model_reasoning_effort=medium' -TEST_CMD='codex --dangerously-bypass-approvals-and-sandbox -m gpt-5.6-luna -c model_reasoning_effort=low' -python3 docs/ack/validate_worker_command.py --role developer --command "$DEV_CMD" -python3 docs/ack/validate_worker_command.py --role test --command "$TEST_CMD" -orca terminal create --worktree active --command "$DEV_CMD" --title "ACK-DEV-CODEX-TERRA-1" --json -orca terminal create --worktree active --command "$TEST_CMD" --title "ACK-TEST-CODEX-LUNA-1" --json - -# Cursor worker 使用同一项目校验器 -CURSOR_CMD='cursor-agent --yolo --model auto' -python3 docs/ack/validate_worker_command.py --role developer --command "$CURSOR_CMD" -``` - -派发成功后把实际 handle 写入任务的 `dispatch.worker`,下次优先复用。需要隔离/并行时先建 worktree:`orca worktree create --name --base-branch --json`(选择依据见 `core/closed-loop.md`)。 - -### 派发与等待(Orca) - -```bash -orca orchestration task-create --spec "<任务与验收>" --json -orca orchestration dispatch --task --to --json -orca orchestration check --terminal --wait \ - --types worker_done,retest_result,escalation,decision_gate --timeout-ms 900000 --json -``` - -不能 `--inject` 时手动投递 `core/prompt-templates.md` 的模板;命令细节见 `core/orca-adapter.md`。 - -### 校验任务板结构 - -```bash -python3 docs/ack/kit/scripts/validate_tasks.py docs/ack/tasks.yaml -``` - -### 只处理已有未通过项 - -用「默认口令」(见下)让 Coordinator 直接扫 `tasks.yaml` 里的 `open` / `failed_retest` 继续闭环。 - -### 速查:想做什么 → 看哪个文件 - -| 想做的事 | 文件 | -|----------|------| -| 开一个新需求怎么起步 | `core/kickoff.md` | -| 角色/权限/状态机/完成定义 | `core/roles-and-permissions.md` | -| 三角色各自该怎么做(规划/写测试/复测能力清单) | `core/roles-and-permissions.md` §三角色能力清单 | -| 用哪个模型、怎么固定、何时升级 | `core/model-routing.md` | -| 闭环步骤、手动模式、worktree 决策与对齐 | `core/closed-loop.md` | -| 验收信号写法、三轮失败策略 | `core/optimization-method.md` | -| 派发/复测/回报的 prompt 文案 | `core/prompt-templates.md` | -| Orca 具体命令 | `core/orca-adapter.md` | -| 让 Agent 在新项目初始化 ack | `init-new-project.md` | -| 新项目接入步骤 | `adoption-checklist.md` | - ---- - -## 默认口令 - -```text -用三角色协作闭环处理 docs/ack/tasks.yaml 里的未通过项:Coordinator 派发给 Developer 修复,再交给 Test 独立复测并终检;每个问题最多修三轮,三轮仍不过就记录为遗留,然后继续下一个。 -``` diff --git a/kits/ack/adoption-checklist.md b/kits/ack/adoption-checklist.md deleted file mode 100644 index 7bb26b6..0000000 --- a/kits/ack/adoption-checklist.md +++ /dev/null @@ -1,71 +0,0 @@ -# 接入清单 - -把本工具包引用/复制到新项目后,按此清单接入。术语与规则详见 `core/`。 - -## 1. 分发与版本 - -- [ ] 选定分发方式(README §「分发方式」A 单软链接 / B 复制)。 -- [ ] 在 `docs/ack/` 下建单软链接 `kit`(指向本框架)。 -- [ ] 覆盖层文件与 `tasks.yaml` 记录 `kitVersion`(对齐 `kit/VERSION`)。 - -## 2. 项目级规范(覆盖层) - -- [ ] 由 `kit/templates/project.template.md` 生成覆盖层文件(默认 `docs/ack/project.md`,**不占用 `AGENTS.md`**)。 -- [ ] 在 `tasks.yaml` 的 `project.overlayFile` 记录覆盖层实际路径。 -- [ ] 覆盖层引用 `docs/ack/kit/core/`,不复制其内容。 -- [ ] 填清项目简介、技术栈、运行/构建/单测/集成测试命令。 -- [ ] 若要 Agent 自动加载覆盖层:在 `AGENTS.md` 加一行指向它,或直接命名为 `AGENTS.md`(可选)。 - -## 2b. 模型档位 - -- [ ] Coordinator 默认强模型且不亲自跑测试。 -- [ ] Test、Developer 默认中低模型。 -- [ ] 记录升级规则:三轮失败升级 Coordinator 复盘;复杂实现升级 Developer 档位(见 `kit/core/model-routing.md`)。 - -## 3. 路径权限 - -- [ ] 填实际的 Coordinator (PM) 可写路径(规格)。 -- [ ] 填实际的 Test 可写路径(集成测试、复测记录)。 -- [ ] 填实际的 Developer 可写路径(源码、单元测试、配置模板)。 -- [ ] 本地私有配置标记只读或不提交。 -- [ ] 确认 `tasks.yaml` 只有 Coordinator 写(见 `kit/core/roles-and-permissions.md`)。 - -## 4. 任务板 - -- [ ] 由 `kit/templates/tasks.template.yaml` 生成 `docs/ack/tasks.yaml`。 -- [ ] 替换 ``、``、``、``、`overlayFile`。 -- [ ] 至少加一个真实任务,验收写成可观测信号(见 `kit/core/optimization-method.md` §1)。 -- [ ] 跑 `python3 docs/ack/kit/scripts/validate_tasks.py docs/ack/tasks.yaml` 通过。 - -## 5. 编排 - -- [ ] 决定用 Orca(`kit/core/orca-adapter.md`)还是手动模式(`kit/core/closed-loop.md`)。 -- [ ] Orca:`orca status`、`terminal list` 可用,Coordinator / Developer / Test 三个终端都在,回报能发回 Coordinator。 -- [ ] 派发前会先查空闲 worker:按 `ACK----` 复用同 worktree、同角色、同配置终端;仅在不存在或都 busy 时新建,并把实际 handle 写入 `dispatch.worker`。 -- [ ] 决定子任务放当前 worktree 起子 agent,还是新建隔离 worktree(决策速查见 `kit/core/closed-loop.md` §「子任务放哪」)。 -- [ ] 多 worktree 时确认 `tasks.yaml`(SSOT)只保留一个权威副本,由 Coordinator 单写。 - -## 6. 验证命令 - -- [ ] Test 有黑盒复测命令,Developer 有白盒验证命令。 -- [ ] 构建产物与服务启动命令写清。 -- [ ] 浏览器测试 `BASE_URL` 写清,复测前能确认服务来自正确 worktree。 - -## 7. 三轮失败策略 - -- [ ] 每个任务记录 `dispatch.rounds`。 -- [ ] 三轮失败标记 `leftover` 并填 `resolution.leftoverReason`。 -- [ ] `leftover` 不阻塞其它任务;最终报告列出所有 `leftover` 与最后失败证据。 - -## 8. 第一次试运行 - -选一个低风险 bug 跑完整闭环,结束后检查是否出现: - -- Developer 修改了越权路径,或 Test 改了源码。 -- worker_done 或复测报告没有验证证据。 -- Test 复测到了旧服务。 -- Coordinator 没做终检就直接 verified。 -- 任务板字段不够记录失败原因。 -- 三轮失败策略没被执行。 - -把发现的问题回写到项目覆盖层文件;若属通用问题,回流到 kit 的 `kit/core/` 并升 `VERSION`。 diff --git a/kits/ack/init-new-project.md b/kits/ack/init-new-project.md deleted file mode 100644 index 380ef48..0000000 --- a/kits/ack/init-new-project.md +++ /dev/null @@ -1,183 +0,0 @@ -# 在新项目初始化 ack(给 Agent 的操作手册) - -本文件指导 Agent 把 `ack` 接入一个目标项目。它是**执行手册**:按步骤在目标项目创建 `docs/ack/`、挂载 kit、生成项目覆盖层和任务板,并完成一次结构校验。 - -若只想人工核对是否接入完整,看 `adoption-checklist.md`。若要开始一个真实需求,看 `core/kickoff.md`。 - ---- - -## 0. 前提与安全边界 - -开始前先确认三件事: - -1. 目标项目根目录:运行或读取当前环境的项目根,不要假设路径。 -2. ack kit 目录:本框架目录的绝对路径,例如 ``。 -3. 分发方式:默认用**单软链接引用**,只有用户明确要求时才整份复制。 - -硬规则: - -- 不要覆盖已有 `docs/ack/project.md`、`docs/ack/tasks.yaml` 或团队现有 `AGENTS.md`。如果文件已存在,先读内容并向用户说明差异,再询问是否合并。 -- 不要把 `core/` 内容复制进项目覆盖层。项目覆盖层只写项目差异。 -- 不要提交、推送或改 git 配置,除非用户明确要求。 -- 不要把私有配置、token、`.env` 内容写进 `tasks.yaml` 或 `project.md`。 - ---- - -## 1. 建目录并挂载 kit - -在目标项目根目录下创建推荐布局: - -```text -docs/ack/ - kit -> - project.md - tasks.yaml -``` - -默认方式(推荐,可升级): - -```bash -mkdir -p docs/ack -ln -s docs/ack/kit -``` - -如果 `docs/ack/kit` 已存在: - -- 是指向同一个 ack 目录的软链接:继续。 -- 是指向旧版本的软链接:报告当前指向与目标指向,询问是否更新。 -- 是普通目录:不要删除;询问用户是保留、备份还是改用复制模式。 - -复制模式(仅用户明确要求): - -```bash -mkdir -p docs/ack -cp -R docs/ack/kit -``` - -复制模式接入后,后续升级需要人工对比 `docs/ack/kit/VERSION`。 - ---- - -## 2. 生成项目覆盖层 `project.md` - -从模板生成: - -```bash -cp docs/ack/kit/templates/project.template.md docs/ack/project.md -``` - -然后填实际项目差异: - -- 项目名、技术栈、运行命令、Base URL。 -- 覆盖层文件路径:默认 `docs/ack/project.md`。 -- 三角色模型档位:默认 Coordinator 强模型,Developer/Test 中低模型。 -- 路径权限:规格文档、集成测试、复测记录、源码、单元测试、配置模板、本地私有配置。 -- Developer 白盒验证命令:单测、构建、服务启动或重启。 -- Test 黑盒复测命令:preflight、API smoke、浏览器回归。 - -如果是网站项目,务必在命令里写清: - -- Developer 改完后如何重启服务或确认热更新生效。 -- Test 使用哪个 Base URL。 -- Test 浏览器复测入口、用例目录或手工检查路径。 - -可选:若希望 Agent 自动加载覆盖层,在目标项目 `AGENTS.md` 加一行指向它: - -```markdown -本项目使用 ack 三角色协作协议,项目覆盖层见 `docs/ack/project.md`。 -``` - -如果目标项目已有 `AGENTS.md`,只追加这一行或一个短小段落;不要重写原文件。 - ---- - -## 3. 生成任务板 `tasks.yaml` - -从模板生成: - -```bash -cp docs/ack/kit/templates/tasks.template.yaml docs/ack/tasks.yaml -``` - -至少替换这些字段: - -- `updatedAt`:当前时间,带时区。 -- `kitVersion`:读取 `docs/ack/kit/VERSION`。 -- `project.name`:项目名。 -- `project.repoPath`:目标项目根目录绝对路径。 -- `project.baseUrl`:网站或 API 的默认访问地址;非服务项目可写 `n/a`。 -- `project.devWorktree`:默认当前 worktree;如果会用独立 worktree,写实际路径。 -- `project.overlayFile`:默认 `docs/ack/project.md`。 - -任务可以先保留一个低风险示例任务,但更推荐写入真实首个任务。每个任务的验收必须是可观测信号: - -- 可见文本:页面或 CLI 输出出现什么。 -- API 结果:状态码、字段、响应值。 -- 交互结果:点击、跳转、提交、取消后的真实状态。 - -不要只写“功能正常”“体验更好”。 - ---- - -## 4. 校验结构 - -在目标项目根目录运行: - -```bash -python3 docs/ack/kit/scripts/validate_tasks.py docs/ack/tasks.yaml -``` - -通过后继续;失败则按错误修正 `tasks.yaml`,不要绕过校验。 - -同时人工检查: - -- `docs/ack/kit` 是否能访问 `core/`、`templates/`、`scripts/`。 -- `docs/ack/project.md` 是否只写项目差异,没有复制大段 core 文本。 -- `docs/ack/tasks.yaml` 的 `project.overlayFile` 是否指向真实文件。 -- 路径权限是否能防止 Developer 改规格、Test 改源码、多人写 `tasks.yaml`。 -- 网站项目是否写清服务重启和浏览器复测方式。 - ---- - -## 5. 给用户的初始化报告 - -初始化完成后,Agent 应给用户一段短报告: - -```text -ack 初始化完成。 - -创建/确认: -- docs/ack/kit -> -- docs/ack/project.md -- docs/ack/tasks.yaml - -已填项目差异: -- 技术栈:<...> -- Developer 验证命令:<...> -- Test 复测命令:<...> -- Base URL:<...> - -校验: -- python3 docs/ack/kit/scripts/validate_tasks.py docs/ack/tasks.yaml: passed - -下一步: -- 用 docs/ack/kit/core/kickoff.md 开一个真实需求;或 -- 选一个低风险 bug 跑一次完整三角色闭环。 -``` - -如果有未完成项,不要说“初始化完成”。改用: - -```text -ack 初始化已部分完成,阻塞在:<具体原因>。 -需要用户决定:<选项或缺失信息>。 -``` - ---- - -## 6. 一句话口令 - -当用户在新项目里说“初始化 ack”时,Agent 可以按下面执行: - -```text -请在当前项目初始化 ack:确认项目根和 ack kit 路径;创建 docs/ack/kit 软链接;由 kit/templates 生成 docs/ack/project.md 与 docs/ack/tasks.yaml;填入项目实际路径、命令、Base URL、模型档位和首个任务;运行 validate_tasks.py;不要覆盖已有文件,不要提交或推送,完成后报告创建文件、校验结果和下一步。 -``` diff --git a/skiff/README.md b/skiff/README.md index 5af0409..6ccb6cc 100644 --- a/skiff/README.md +++ b/skiff/README.md @@ -66,7 +66,7 @@ skiff bootstrap |------|------| | `skiff bootstrap` | 将本项目的 `skiff` skill 全局安装到所有 Agent | | `skiff update` | 在 `~/.skills` 执行 `git pull`,更新 skiff 自身 | -| `skiff kit init [--project DIR] [--copy]` | 在项目的 `docs//` 初始化规范包;默认软链接到 SSOT | +| `skiff init [--project DIR]` | 使用 builtin skill 自带模板初始化项目状态 | ### 全局安装(自研 skill) diff --git a/skiff/cli.py b/skiff/cli.py index 3fddf68..441f9ed 100644 --- a/skiff/cli.py +++ b/skiff/cli.py @@ -4,7 +4,6 @@ from __future__ import annotations import argparse import re -import shutil import subprocess import sys from datetime import datetime @@ -18,7 +17,6 @@ from skiff.paths import ( DRAFTS_DIR, EXTERNALS_DIR, CONFIG_FILE, - KITS_DIR, SKILLS_DIR, SKILLS_HOME, TEMPLATE_DIR, @@ -83,7 +81,7 @@ def _project_root(explicit: str | None = None) -> Path: return find_repo_root() or Path.cwd() -def _render_kit_template(source: Path, destination: Path, values: dict[str, str]) -> None: +def _render_template(source: Path, destination: Path, values: dict[str, str]) -> None: content = source.read_text(encoding="utf-8") for placeholder, value in values.items(): content = content.replace(placeholder, value) @@ -1132,66 +1130,55 @@ def cmd_doctor(args: argparse.Namespace) -> None: sys.exit(1) -def cmd_kit_init(args: argparse.Namespace) -> None: - """将 owned kit 初始化到目标项目。""" +def cmd_init(args: argparse.Namespace) -> None: + """使用 builtin skill 自带的模板初始化目标项目状态。""" ensure_skills_home() - kit_source = KITS_DIR / args.name - if not kit_source.is_dir(): - available = sorted(path.name for path in KITS_DIR.iterdir() if path.is_dir()) if KITS_DIR.is_dir() else [] - suffix = f";可用 kit: {', '.join(available)}" if available else "" - raise SystemExit(f"kit 不存在: {args.name}{suffix}") + skill_source = SKILLS_DIR / args.name + if not (skill_source / "SKILL.md").is_file(): + raise SystemExit(f"builtin skill 不存在: {args.name}") project = _project_root(args.project) if not project.is_dir(): raise SystemExit(f"项目目录不存在: {project}") destination = project / "docs" / args.name - kit_target = destination / "kit" project_file = destination / "project.md" tasks_file = destination / "tasks.yaml" - managed_targets = (kit_target, project_file, tasks_file) + managed_targets = (project_file, tasks_file) existing = [path for path in managed_targets if path.exists() or path.is_symlink()] if existing: paths = ", ".join(str(path.relative_to(project)) for path in existing) raise SystemExit(f"拒绝覆盖已有路径: {paths}") - project_template = kit_source / "templates" / "project.template.md" - tasks_template = kit_source / "templates" / "tasks.template.yaml" + project_template = skill_source / "templates" / "project.template.md" + tasks_template = skill_source / "templates" / "tasks.template.yaml" missing = [path for path in (project_template, tasks_template) if not path.is_file()] if missing: paths = ", ".join(str(path.relative_to(SKILLS_HOME)) for path in missing) - raise SystemExit(f"kit 缺少初始化模板: {paths}") + raise SystemExit(f"skill 缺少初始化模板: {paths}") destination.mkdir(parents=True, exist_ok=True) - if args.copy: - shutil.copytree(kit_source, kit_target) - mode = "copy" - else: - kit_target.symlink_to(kit_source.resolve(), target_is_directory=True) - mode = "symlink" - version_file = kit_source / "VERSION" - kit_version = version_file.read_text(encoding="utf-8").strip() if version_file.is_file() else "unknown" + version_file = skill_source / "VERSION" + ack_version = version_file.read_text(encoding="utf-8").strip() if version_file.is_file() else "unknown" now = datetime.now().astimezone().isoformat(timespec="seconds") values = { "": project.name, "": str(project), "": str(project), "": f"docs/{args.name}/project.md", - "": kit_version, - "<接入时的 ack 版本,见 kit 根 VERSION>": kit_version, + "": ack_version, + "<接入时的 ack skill 版本>": ack_version, "": now, } - _render_kit_template(project_template, project_file, values) - _render_kit_template(tasks_template, tasks_file, values) + _render_template(project_template, project_file, values) + _render_template(tasks_template, tasks_file, values) - validator = kit_target / "scripts" / "validate_tasks.py" + validator = skill_source / "scripts" / "validate_tasks.py" if validator.is_file(): subprocess.run([sys.executable, str(validator), str(tasks_file)], check=True) - _print(f"✓ kit 初始化完成: {args.name}") + _print(f"✓ skill 项目状态初始化完成: {args.name}") _print(f" 项目: {project}") - _print(f" 模式: {mode}") - _print(f" kit: {kit_target}") _print(f" 覆盖层: {project_file}") _print(f" 任务板: {tasks_file}") _print("下一步: 填写 project.md 中的项目命令、路径权限和 Base URL") @@ -1363,23 +1350,16 @@ def build_parser() -> argparse.ArgumentParser: p_finalize.add_argument("name", help="skill 名称") p_finalize.set_defaults(func=cmd_finalize) + p_init = sub.add_parser("init", help="使用 skill 模板初始化项目状态") + p_init.add_argument("name", help="skill 名称") + p_init.add_argument("--project", help="项目根目录(默认自动检测或当前目录)") + p_init.set_defaults(func=cmd_init) + p_doctor = sub.add_parser("doctor", help="软链健康检查") p_doctor.add_argument("-a", "--agent", dest="agents", nargs="+", action="append") p_doctor.add_argument("--fix", action="store_true", help="自动修复可修复的软链") p_doctor.set_defaults(func=cmd_doctor) - p_kit = sub.add_parser("kit", help="管理项目规范包") - kit_sub = p_kit.add_subparsers(dest="kit_command", required=True) - p_kit_init = kit_sub.add_parser("init", help="在项目中初始化 kit") - p_kit_init.add_argument("name", help="kit 名称") - p_kit_init.add_argument("--project", help="项目根目录(默认自动检测或当前目录)") - p_kit_init.add_argument( - "--copy", - action="store_true", - help="复制 kit,而不是创建指向 SSOT 的软链接", - ) - p_kit_init.set_defaults(func=cmd_kit_init) - return parser diff --git a/skiff/paths.py b/skiff/paths.py index 82890a1..11089b9 100644 --- a/skiff/paths.py +++ b/skiff/paths.py @@ -7,7 +7,6 @@ from pathlib import Path HOME = Path.home() SKILLS_HOME = HOME / ".skills" SKILLS_DIR = SKILLS_HOME / "skills" -KITS_DIR = SKILLS_HOME / "kits" TEMPLATE_DIR = SKILLS_DIR / "_template" DRAFTS_DIR = SKILLS_HOME / ".drafts" REGISTRY_FILE = SKILLS_HOME / "registry.yaml" diff --git a/skiff/source-model.md b/skiff/source-model.md new file mode 100644 index 0000000..708889c --- /dev/null +++ b/skiff/source-model.md @@ -0,0 +1,219 @@ +# Skill 来源模型 + +## 背景 + +skiff 当前使用 `owned` 表示本仓库 `skills/` 中维护的 Skill,同时还支持 +`registry` 外部仓库和用户配置的 custom source。 + +这些名称混合了不同维度: + +- `owned` 表示所有权。 +- `registry` 表示来源配置存放在哪里。 +- `external` 表示内容不在当前仓库。 +- `collection` 表示一个来源中包含多个 Skill。 + +它们不能作为同一层级的互斥类型。例如 custom source 既可能来自外部 Git 仓库, +也可能是 collection;因此 `custom` 与 `external` 并不互斥。 + +本文建议将用户可见的来源注册方式统一为三类: + +- `builtin`:随当前 skiff 仓库提供的 Skill。 +- `catalog:`:由 skiff 自带目录预先登记的来源。 +- `custom:`:用户在本机显式配置的命名来源。 + +来源注册方式与获取方式、仓库布局相互独立。builtin、catalog 和 custom 中的任意 +来源都可以包含一个或多个 Skill;除 builtin 外,catalog 和 custom 都可以使用 +Git 仓库或本地目录。 + +## 当前模型 + +```mermaid +flowchart TD + S[skiff 可发现的 Skills] + + S --> O["owned
~/.skills/skills/*"] + S --> C["custom source
~/.config/skiff/config.yaml"] + S --> R["registry
registry.yaml"] + + O --> O1["本仓库维护
随 skiff 一起分发"] + + C --> C1["本地目录
--local PATH"] + C --> C2["指定 Git 仓库
repo + skills_path"] + + R --> R1["外部单 Skill 仓库"] + R --> R2["外部 Skill Collection"] + R1 --> E["~/.local/share/skills/externals/"] + R2 --> E +``` + +当前实现中: + +- `list` 和 `status` 支持 owned、registry 和 custom source。 +- `resolve_skill_source` 可以解析三种来源并处理同名歧义。 +- `select` 只组装 owned 和 registry 条目,尚未展示 custom source。 +- `.skills.yaml` 默认将未声明来源的 Skill 解释为 `owned`。 +- custom source 的 `skills_path` 已经可以包含多个 Skill,本质上也是 collection。 + +## 推荐模型 + +```mermaid +flowchart TD + A[Skill Provider] + + A --> B["builtin
仓库内隐式注册"] + A --> C["catalog:waza
skiff 预置目录"] + A --> D["custom:company
用户本机配置"] + + B --> B1["skills/ack"] + B --> B2["skills/skiff"] + B --> B3["skills/deb-publisher"] + + C --> C1["Git 或本地目录"] + C1 --> C2["单 Skill"] + C1 --> C3["Collection"] + C3 --> C4["waza/think"] + C3 --> C5["waza/check"] + + D --> D1["Git 或本地目录"] + D1 --> D2["单 Skill"] + D1 --> D3["Collection"] + D3 --> D4["company/security-review"] + D3 --> D5["company/release"] +``` + +### 来源注册方式 + +| 类型 | 含义 | 配置来源 | 用户界面展示 | +| --- | --- | --- | --- | +| `builtin` | 随当前 skiff 仓库提供 | `skills/` | `builtin` | +| `catalog` | skiff 预先登记、所有用户可发现的来源 | `catalog.yaml`,迁移前为 `registry.yaml` | `catalog:` | +| `custom` | 用户在本机显式注册的命名来源 | `~/.config/skiff/config.yaml` | `custom:` | + +`builtin` 比 `owned` 更适合作为用户可见名称,因为它表达 Skill 的分发位置和可用 +方式,而不是仓库的所有权关系。 + +`catalog` 比 `registry` 更准确:当前文件只是 skiff 随仓库维护的预置来源目录, +并不是远程注册中心,也不是一种 Skill 来源协议。 + +### 三个正交维度 + +每个 provider 应由三个维度描述: + +```text +registration: builtin | catalog | custom +transport: bundled | local | git +layout: single | collection +``` + +custom source 示例: + +```text +registration: custom +name: company +transport: local | git +layout: single | collection +``` + +catalog entry 示例: + +```text +registration: catalog +name: waza +transport: local | git +layout: single | collection +``` + +`external` 只适合描述物理位置,可作为 catalog 和部分 custom provider 的统称, +不应成为与 builtin、custom 并列的持久化类型。 + +## `select` 展示 + +`skiff select` 应同时展示 builtin、catalog 和 custom Skill: + +```text +[ ] ack builtin +[ ] deb-publisher builtin +[-] company custom source + [ ] company/release custom:company + [ ] company/security-review custom:company +[-] waza catalog source + [ ] waza/check catalog:waza + [ ] waza/think catalog:waza +``` + +建议遵循以下规则: + +- builtin Skill 直接显示 Skill 名称。 +- catalog 和 custom collection 都使用来源名称作为父节点。 +- catalog 和 custom Skill 都使用 `/` 作为选择器键。 +- 单 Skill 来源可以省略父节点,但仍显示注册方式和来源名称。 +- 不同来源安装后名称相同时,继续拒绝同时选择,避免覆盖同一安装路径。 + +## 配置表示 + +新写入的 `.skills.yaml` 使用以下形式: + +```yaml +skills: + - name: ack + source: builtin + - name: security-review + source: company + - name: think + source: catalog:waza +``` + +custom source 在 manifest 中继续保存其逻辑名称,例如 `company`。这样不同机器可以 +独立配置仓库地址,而项目只依赖稳定的来源名称。 + +## 兼容迁移 + +这是一次用户可见术语调整,应提供兼容层,避免已有项目立即失效: + +1. 对外文档、CLI 输出和 selector 统一使用 `builtin`、`catalog:` 和 + `custom:`。 +2. 新生成的 `.skills.yaml` 对内置 Skill 写入 `source: builtin`。 +3. 读取旧 manifest 时继续接受 `source: owned`,并在解析时归一化为 `builtin`。 +4. CLI 参数在过渡期继续接受 `--source owned`,但帮助和输出只推荐 `builtin`。 +5. 读取旧 manifest 中的 `source: registry` 和 `registry: `,归一化为 + `catalog:`。 +6. `registry.yaml` 可以先保留文件名,仅将用户界面术语改为 catalog;单独迁移为 + `catalog.yaml` 时,应兼容读取旧文件。 +7. custom source 的逻辑名称和现有 `config.yaml` 结构保持不变。 +8. 将 `builtin`、`catalog` 和兼容别名 `owned`、`registry` 设为 custom source + 保留字。 +9. `select` 同步接入 custom Skill,并让 custom collection 与 catalog collection + 使用相同的父子展示逻辑。 + +## 影响范围 + +实施时预计涉及: + +- `skiff/skills.py`:来源解析、归一化和 builtin 命名。 +- `skiff/project.py`:manifest 默认值、序列化与旧值兼容。 +- `skiff/sources.py`:来源保留字。 +- `skiff/registry.py`:逐步重命名为 catalog 概念。 +- `skiff/cli.py`:`list`、`status`、`add`、`select` 和输出文案。 +- `skiff/selector.py`:统一 catalog/custom collection 的父子展示。 +- CLI 与来源解析测试。 +- 根 README、`skiff/README.md`、`skills/skiff/SKILL.md` 和相关示例。 + +## 验证要求 + +实施完成后至少覆盖: + +- builtin Skill 可以通过新名称列出、选择、安装和写入 manifest。 +- 旧的 `source: owned` manifest 仍可同步。 +- custom local source 和 custom Git source 都出现在 selector 中。 +- catalog 单 Skill 和 Collection 都保持可选择。 +- custom 单 Skill 和 Collection 都保持可选择。 +- 多来源同名 Skill 必须显式指定来源。 +- 两个选择最终安装为同一个名称时,selector 拒绝冲突。 +- `list`、`status`、`select` 对同一来源使用一致术语。 + +## 设计前提 + +本方案假设 `registry.yaml` 当前的真实职责是维护 skiff 预置的来源目录,而不是提供 +远程发布、版本解析或可信签名等注册中心能力。因此推荐逐步将用户可见概念改为 +`catalog`。如果未来实现真正的远程 registry,再单独定义其协议和与 catalog 的同步 +关系,不复用当前含义模糊的名称。 diff --git a/skills/ack/README.md b/skills/ack/README.md new file mode 100644 index 0000000..a6d1b53 --- /dev/null +++ b/skills/ack/README.md @@ -0,0 +1,85 @@ +# ACK + +ACK 是一个显式调用的 Agent Skill,用三种独立角色运行工程协作闭环: + +- Coordinator 拆解需求、派发任务并终检。 +- Developer 实现并执行白盒验证。 +- Test 独立执行黑盒复测。 + +关键约束是验证者不等于实现者。每个任务最多修复三轮,仍未通过时记录为 +`leftover`,然后继续处理其它任务。 + +## 安装 + +全局安装: + +```bash +skiff add ack -g +``` + +或只安装到当前项目: + +```bash +skiff add ack +``` + +ACK 只在用户显式调用 `/ack` 或 `$ack` 时运行。 + +## 初始化项目 + +```bash +skiff init ack +skiff init ack --project ~/code/my-app +``` + +初始化后,项目只保存自己的 ACK 状态: + +```text +docs/ack/ +├── project.md +└── tasks.yaml +``` + +不会在项目中复制或链接 ACK Skill。通用规范、模板和脚本始终从已安装的 Skill +目录读取。 + +## Skill 结构 + +```text +skills/ack/ +├── SKILL.md +├── README.md +├── VERSION +├── references/ # 三角色规范、闭环流程和初始化说明 +├── templates/ # project.md 与 tasks.yaml 模板和 schema +├── examples/ # 完整示例 +└── scripts/ # tasks.yaml 与 worker 命令校验器 +``` + +`SKILL.md` 是 Agent 的工作流入口。`references/` 是按需读取的稳定规范; +`docs/ack/project.md` 只保存当前项目的命令、路径和权限差异; +`docs/ack/tasks.yaml` 保存当前任务状态。 + +## 检查任务板 + +Agent 会从当前 ACK Skill 目录解析校验脚本: + +```bash +python3 /scripts/validate_tasks.py docs/ack/tasks.yaml +``` + +## 开始一个需求 + +初始化完成后可以直接说: + +```text +/ack 处理这个需求:<一句话需求> +``` + +Coordinator 会先读取项目状态和 `references/kickoff.md`,生成产品文档、任务拆分与 +可观测验收信号;用户确认后才派发实现和复测。 + +## 版本 + +当前 Skill 版本见 `VERSION`。新项目在 `tasks.yaml` 中记录 `ackVersion`。旧项目的 +`kitVersion` 可以继续读取,但建议迁移为 `ackVersion`。 diff --git a/skills/ack/SKILL.md b/skills/ack/SKILL.md index 652a74e..96495fc 100644 --- a/skills/ack/SKILL.md +++ b/skills/ack/SKILL.md @@ -1,15 +1,19 @@ --- name: ack description: >- - 初始化、检查并运行 ACK(Agent Collaboration Kit)三角色协作闭环。仅在用户显式调用 - /ack 或 $ack,并要求初始化 ACK、检查 docs/ack 配置、按 ACK 规划需求或指挥 - Coordinator/Developer/Test 工作时使用。 + 初始化、检查并运行 ACK 三角色协作闭环。仅在用户显式调用 /ack 或 $ack,并要求 + 初始化 ACK、检查 docs/ack 配置、按 ACK 规划需求或指挥 Coordinator/Developer/Test + 工作时使用。 --- # ACK 项目协作入口 -把全局 skill 作为入口,把项目状态留在 `docs/ack/`,把通用规范留在 -`~/.skills/kits/ack/`。不要在本 skill 复制或改写 kit 的核心规范。 +本 Skill 是 ACK 的完整能力包:`references/` 保存通用规范,`templates/` 保存项目 +状态模板,`scripts/` 保存校验工具。目标项目只在 `docs/ack/` 保存 `project.md` 和 +`tasks.yaml`,不要复制或链接 Skill 内容。 + +开始时解析当前 `SKILL.md` 所在目录,记为 ``。所有通用规范、模板和 +脚本都相对此目录访问,不依赖固定的全局安装路径。 ## 选择模式 @@ -27,10 +31,11 @@ description: >- 2. 不存在时执行: ```bash - skiff kit init ack --project + skiff init ack --project ``` - 默认使用软链接模式。只有用户明确要求项目自带完整副本时才加 `--copy`。 + 该命令从本 Skill 的 `templates/` 生成项目状态,不会在项目中创建 Skill + 软链接或资源副本。 3. 如果 `docs/ack` 已存在,不重复初始化、不覆盖文件;转入“检查”,报告缺失项并 只补用户授权且能安全确定的内容。 4. 读取项目的公开配置和文档,例如 README、语言清单、包管理清单、测试配置与 @@ -39,33 +44,32 @@ description: >- - 用实际项目值替换全部占位符。 - 无服务地址时把 Base URL 写为 `n/a`,不要虚构端口。 - 无法从项目证据确定的命令写为 `n/a`,并在结果中列为待配置项。 - - 保留 `docs/ack/kit/core/` 引用,不复制 core 内容。 + - 只写项目差异,不复制 `references/` 中的通用规范。 6. 完善 `docs/ack/tasks.yaml` 的项目信息。纯初始化且用户没有提供真实任务时, 删除模板示例任务并保留 `tasks: []`;不要虚构需求或缺陷。 7. 更新 `updatedAt`,并运行: ```bash - python3 docs/ack/kit/scripts/validate_tasks.py docs/ack/tasks.yaml + python3 /scripts/validate_tasks.py docs/ack/tasks.yaml ``` 8. 检查 `project.md` 与 `tasks.yaml` 是否仍有 `<...>` 占位符。结构校验通过且 必填项目事实完整时才称“初始化完成”;否则称“部分完成”并列出缺失值。 -9. 报告创建的路径、软链接或复制模式、检测到的命令、校验结果和下一步。除非用户 - 明确要求,不提交、不推送。 +9. 报告创建的路径、检测到的命令、校验结果和下一步。除非用户明确要求,不提交、 + 不推送。 ## 检查 1. 检查以下路径: - - `docs/ack/kit` - `docs/ack/project.md` - `docs/ack/tasks.yaml` -2. 确认 `kit` 可访问 `VERSION`、`core/`、`templates/` 和 `scripts/`。软链接模式下 - 同时报告其真实目标。 -3. 对比 `tasks.yaml` 的 `kitVersion` 与 `kit/VERSION`。 -4. 查找未替换占位符,并核对项目路径、覆盖层路径、Developer 白盒命令、Test +2. 读取 `/VERSION`,对比 `tasks.yaml` 的 `ackVersion`。旧项目只有 + `ackVersion` 时仍可读取,但建议迁移为 `ackVersion`。 +3. 查找未替换占位符,并核对项目路径、覆盖层路径、Developer 白盒命令、Test 黑盒命令和 Base URL。 -5. 运行任务板校验器。只报告证据明确的问题,不因可选字段缺失而宣称失败。 -6. 检查不会自动修复或覆盖现有配置;用户明确要求修复后再修改。 +4. 使用 `/scripts/validate_tasks.py` 校验任务板。只报告证据明确的 + 问题,不因可选字段缺失而宣称失败。 +5. 检查不会自动修复或覆盖现有配置;用户明确要求修复后再修改。 ## 工作 @@ -73,8 +77,8 @@ description: >- 2. 依次读取: - `docs/ack/project.md` - `docs/ack/tasks.yaml` - - `docs/ack/kit/core/kickoff.md` - - kickoff 指定且与当前任务相关的 core 文件 + - `/references/kickoff.md` + - kickoff 指定且与当前任务相关的 references 文件 3. 当前会话担任 Coordinator,遵守项目覆盖层中的命令、路径权限、模型路由和 worker 复用规则。项目覆盖层优先于通用示例命令。 4. 新需求先写产品文档、任务拆分与可观测验收信号,更新 `tasks.yaml` 并校验, @@ -87,7 +91,8 @@ description: >- ## 边界 - 不修改或追加任何项目 Agent 指令文件,包括 `AGENTS.md`。 -- 不在 skill 中维护第二份 ACK core、模板或任务 schema。 +- 不在项目中维护第二份 ACK 通用规范、模板或任务 schema。 - 不猜测项目命令、服务地址、worker handle 或模型名称。 - 不覆盖已有 `docs/ack` 文件,不擅自提交、推送、创建终端或新 worktree。 -- kit 初始化的机械操作始终委托给 `skiff kit init ack`。 +- 项目只保存 `docs/ack/project.md` 和 `docs/ack/tasks.yaml`;通用资源始终从当前 + ACK Skill 目录读取。 diff --git a/kits/ack/VERSION b/skills/ack/VERSION similarity index 100% rename from kits/ack/VERSION rename to skills/ack/VERSION diff --git a/kits/ack/examples/project.example.md b/skills/ack/examples/project.example.md similarity index 72% rename from kits/ack/examples/project.example.md rename to skills/ack/examples/project.example.md index 162d5ed..214b29e 100644 --- a/kits/ack/examples/project.example.md +++ b/skills/ack/examples/project.example.md @@ -1,9 +1,9 @@ # notes-web Agent 协作协议(示例,项目覆盖层) > 本项目基于 ack v0.8.1。 -> 稳定规范引用 `docs/ack/kit/core/`,本文件只填项目差异。 +> 通用规范由 `/ack` 从 Skill 自身的 `references/` 读取,本文件只填项目差异。 > 覆盖层文件放在 `docs/ack/project.md`,不占用 `AGENTS.md`。 -> 目录下只有一个软链接 `kit/` + `project.md` + `tasks.yaml`。 +> `docs/ack/` 只保存 `project.md` 与 `tasks.yaml`。 ## 项目概览 @@ -16,13 +16,13 @@ ## 稳定规范(引用,不重复) -- 开始一个需求(启动手册):`docs/ack/kit/core/kickoff.md` -- 角色 / 权限 / 状态机 / 完成定义:`docs/ack/kit/core/roles-and-permissions.md` -- 模型档位与升级规则:`docs/ack/kit/core/model-routing.md` -- 闭环流程(含手动模式、worktree 对齐):`docs/ack/kit/core/closed-loop.md` -- 优化方法(验收信号、三轮策略):`docs/ack/kit/core/optimization-method.md` -- 派发 prompt 模板:`docs/ack/kit/core/prompt-templates.md` -- Orca 编排命令:`docs/ack/kit/core/orca-adapter.md` +- 开始一个需求(启动手册):`references/kickoff.md` +- 角色 / 权限 / 状态机 / 完成定义:`references/roles-and-permissions.md` +- 模型档位与升级规则:`references/model-routing.md` +- 闭环流程(含手动模式、worktree 对齐):`references/closed-loop.md` +- 优化方法(验收信号、三轮策略):`references/optimization-method.md` +- 派发 prompt 模板:`references/prompt-templates.md` +- Orca 编排命令:`references/orca-adapter.md` ## 模型档位 @@ -63,16 +63,12 @@ curl -s -X POST http://localhost:5173/api/fix/preview -d @fixtures/preview.json # 浏览器回归:tests/browser/cases/*.md ``` -任务板校验: +任务板校验由 `/ack` 使用 Skill 自带的 `scripts/validate_tasks.py` 执行。 -```bash -python3 docs/ack/kit/scripts/validate_tasks.py docs/ack/tasks.yaml -``` - -## 硬规则(其余见 kit/core/) +## 硬规则(其余见 references/) - 三角色独立:Coordinator 只编排、Test 只验证、Developer 只实现。 -- 模型分层:Coordinator 强模型不跑测试,Test/Developer 中低模型(见 kit/core/model-routing.md)。 +- 模型分层:Coordinator 强模型不跑测试,Test/Developer 中低模型(见 references/model-routing.md)。 - `worker_done` 与复测报告都不等于完成,必须 Test 独立复测 + Coordinator 终检后才能 `verified`。 - 只有 Coordinator 写 `tasks.yaml`;Test 与 Developer 只读。 - 每个任务最多派发 3 轮,仍不过标记 `leftover` 并继续。 diff --git a/kits/ack/examples/tasks.example.yaml b/skills/ack/examples/tasks.example.yaml similarity index 99% rename from kits/ack/examples/tasks.example.yaml rename to skills/ack/examples/tasks.example.yaml index fe8327f..ebcfeda 100644 --- a/kits/ack/examples/tasks.example.yaml +++ b/skills/ack/examples/tasks.example.yaml @@ -2,7 +2,7 @@ version: 1 updatedAt: "2026-07-06T09:40:00+08:00" source: "Coordinator (PM) Agent" -kitVersion: "0.3.0" +ackVersion: "0.8.1" project: name: "notes-web" repoPath: "/home/dev/notes-web" diff --git a/skills/ack/references/adoption-checklist.md b/skills/ack/references/adoption-checklist.md new file mode 100644 index 0000000..9e738b8 --- /dev/null +++ b/skills/ack/references/adoption-checklist.md @@ -0,0 +1,51 @@ +# ACK 接入清单 + +## 安装与初始化 + +- [ ] ACK Skill 已全局安装或安装到当前项目。 +- [ ] 已运行 `skiff init ack --project `。 +- [ ] `docs/ack/` 只包含项目自己的 `project.md` 与 `tasks.yaml`。 +- [ ] 项目中没有 ACK Skill 的复制目录或 `kit`、`framework` 软链接。 +- [ ] `tasks.yaml` 使用 `ackVersion` 记录 ACK Skill 版本。 + +## 项目覆盖层 + +- [ ] `project.md` 只保存项目差异,不复制 Skill 的通用规范。 +- [ ] `tasks.yaml` 的 `project.overlayFile` 指向实际覆盖层。 +- [ ] 技术栈、运行、构建、单测和集成测试命令均来自项目证据。 +- [ ] Coordinator、Developer、Test 的模型档位和升级规则已明确。 + +## 路径权限 + +- [ ] Coordinator 可写规格和任务板。 +- [ ] Test 可写集成测试与复测记录,但不能改源码。 +- [ ] Developer 可写源码与单元测试,但不能改规格或黑盒验收。 +- [ ] 私有配置只读且不提交。 +- [ ] `tasks.yaml` 只有 Coordinator 写。 + +## 任务板 + +- [ ] 已替换项目名、仓库路径、Base URL、worktree 和覆盖层路径。 +- [ ] 没有真实任务时使用 `tasks: []`。 +- [ ] 真实任务的验收是可观测信号。 +- [ ] 已运行 `/scripts/validate_tasks.py` 并通过。 + +## 编排 + +- [ ] 已选择 Orca 或手动模式。 +- [ ] 派发前优先复用同 worktree、同角色、同配置的空闲 worker。 +- [ ] Developer 与 Test 的启动命令通过校验。 +- [ ] 多 worktree 场景只有一个权威 `tasks.yaml`。 +- [ ] Test 使用的服务来自正确 worktree。 + +## 闭环 + +- [ ] `worker_done` 不直接视为完成。 +- [ ] Test 独立复测后由 Coordinator 读取证据终检。 +- [ ] 每轮写入 `dispatch.rounds`。 +- [ ] 三轮失败后标记 `leftover` 并填写原因。 +- [ ] `leftover` 不阻塞其它任务。 + +首次接入建议选择一个低风险问题跑完整闭环。项目差异写回 +`docs/ack/project.md`;通用问题回流到 ACK Skill 的 `references/`、`templates/` +或 `scripts/`,并更新 `VERSION`。 diff --git a/kits/ack/core/closed-loop.md b/skills/ack/references/closed-loop.md similarity index 100% rename from kits/ack/core/closed-loop.md rename to skills/ack/references/closed-loop.md diff --git a/skills/ack/references/init-new-project.md b/skills/ack/references/init-new-project.md new file mode 100644 index 0000000..152ae01 --- /dev/null +++ b/skills/ack/references/init-new-project.md @@ -0,0 +1,92 @@ +# 在新项目初始化 ACK + +本文件说明如何把 ACK 的项目状态初始化到目标项目。ACK Skill 自身已经通过 Agent +的 Skill 机制安装;项目不复制、不链接 Skill 内容。 + +## 前提与边界 + +开始前确认: + +1. 目标项目根目录。 +2. ACK Skill 已全局安装或安装到当前项目。 +3. `skiff` 命令可用。 + +不要覆盖已有的 `docs/ack/project.md`、`docs/ack/tasks.yaml`、`AGENTS.md` 或其它 +Agent 指令文件。不要把 token、`.env` 内容或其它私有配置写入 ACK 项目状态。 + +## 初始化 + +在目标项目执行: + +```bash +skiff init ack +``` + +或显式指定项目: + +```bash +skiff init ack --project +``` + +命令从 ACK Skill 自带的 `templates/` 生成: + +```text +docs/ack/ +├── project.md +└── tasks.yaml +``` + +如果任一目标文件已经存在,命令会拒绝覆盖。初始化过程不会创建 `kit`、 +`framework` 或其它指向 Skill 的软链接。 + +## 完善项目覆盖层 + +编辑 `docs/ack/project.md`,填入: + +- 项目名、技术栈、运行命令和 Base URL。 +- Coordinator、Developer、Test 的实际模型档位。 +- 规格、集成测试、源码、单元测试和私有配置的路径权限。 +- Developer 白盒验证命令。 +- Test 黑盒复测命令。 + +无法从项目证据确定的值写为 `n/a`,不要猜测。 + +## 完善任务板 + +编辑 `docs/ack/tasks.yaml`: + +- `ackVersion` 使用 ACK Skill 的 `VERSION`。 +- `updatedAt` 使用当前带时区时间。 +- `project.name`、`repoPath`、`devWorktree` 和 `overlayFile` 使用真实值。 +- 非服务项目的 `baseUrl` 写为 `n/a`。 +- 没有真实任务时使用 `tasks: []`,不要保留或虚构示例任务。 + +每个真实任务的验收必须是可观测信号,例如可见文本、API 状态和字段,或明确的交互 +结果;不要只写“功能正常”。 + +## 校验 + +Agent 从当前 `SKILL.md` 解析 ACK Skill 目录后运行: + +```bash +python3 /scripts/validate_tasks.py docs/ack/tasks.yaml +``` + +同时确认: + +- `project.md` 和 `tasks.yaml` 没有未替换的 `<...>` 占位符。 +- `project.overlayFile` 指向真实文件。 +- Developer 与 Test 的验证命令可执行。 +- 网站或 API 项目写清服务启动、重启和 Base URL。 + +## 初始化报告 + +完成后报告: + +- 创建或确认的两个项目文件。 +- 检测到的技术栈和验证命令。 +- 任务板校验结果。 +- 仍需用户补充的值。 + +只有结构校验通过且必填项目事实完整时才称“初始化完成”;否则称“部分完成”,并列出 +具体阻塞项。除非用户明确要求,不提交、不推送。 diff --git a/kits/ack/core/kickoff.md b/skills/ack/references/kickoff.md similarity index 89% rename from kits/ack/core/kickoff.md rename to skills/ack/references/kickoff.md index 73b776e..6cd2f25 100644 --- a/kits/ack/core/kickoff.md +++ b/skills/ack/references/kickoff.md @@ -14,9 +14,9 @@ ```text 我要做一个新需求:<一句话需求>。 -你作为 ack 的 Coordinator(PM),按 docs/ack/kit/core 的规范执行: +你作为 ack 的 Coordinator(PM),按 ACK Skill 的 references 规范执行: -1. 先读 docs/ack/project.md、docs/ack/kit/core/roles-and-permissions.md、closed-loop.md、optimization-method.md。 +1. 先读 docs/ack/project.md、references/roles-and-permissions.md、closed-loop.md、optimization-method.md。 2. 写产品文档到 docs/(PRD / 交互 / 验收),把需求拆成任务,每个任务的验收写成可观测信号(可见文本 / API 结果 / 交互结果)。 3. 把任务写进 docs/ack/tasks.yaml(只有你写),跑 validate 校验结构。 4. 先把「产品文档 + 任务拆分 + 验收信号」给我确认,不要急着派发。 @@ -34,7 +34,7 @@ 3. 校验结构: ```bash -python3 docs/ack/kit/scripts/validate_tasks.py docs/ack/tasks.yaml +python3 /scripts/validate_tasks.py docs/ack/tasks.yaml ``` 4. **停下来给人确认**——这是强模型该花时间的地方,不要跳过。 @@ -58,14 +58,14 @@ python3 docs/ack/kit/scripts/validate_tasks.py docs/ack/tasks.yaml # Codex 示例(模型与执行模式以项目覆盖层为准) DEV_CMD='codex --dangerously-bypass-approvals-and-sandbox -m gpt-5.6-terra -c model_reasoning_effort=medium' TEST_CMD='codex --dangerously-bypass-approvals-and-sandbox -m gpt-5.6-luna -c model_reasoning_effort=low' -python3 docs/ack/validate_worker_command.py --role developer --command "$DEV_CMD" -python3 docs/ack/validate_worker_command.py --role test --command "$TEST_CMD" +python3 /scripts/validate_worker_command.py --role developer --command "$DEV_CMD" +python3 /scripts/validate_worker_command.py --role test --command "$TEST_CMD" orca terminal create --worktree active --command "$DEV_CMD" --title "ACK-DEV-CODEX-TERRA-1" --json orca terminal create --worktree active --command "$TEST_CMD" --title "ACK-TEST-CODEX-LUNA-1" --json # Cursor 示例 CURSOR_CMD='cursor-agent --yolo --model auto' -python3 docs/ack/validate_worker_command.py --role developer --command "$CURSOR_CMD" +python3 /scripts/validate_worker_command.py --role developer --command "$CURSOR_CMD" orca terminal create --worktree active --command "$CURSOR_CMD" --title "ACK-DEV-CURSOR-AUTO-1" --json ``` diff --git a/kits/ack/core/model-routing.md b/skills/ack/references/model-routing.md similarity index 95% rename from kits/ack/core/model-routing.md rename to skills/ack/references/model-routing.md index 0bd57b1..1258883 100644 --- a/kits/ack/core/model-routing.md +++ b/skills/ack/references/model-routing.md @@ -71,7 +71,7 @@ 执行模式也必须在创建 worker 时固定,并服从项目覆盖层或用户的明确要求。Cursor 的 YOLO 参数是 `--yolo`;Codex 的等价参数是 `--dangerously-bypass-approvals-and-sandbox`。不要把 Cursor 的 `--yolo` 原样传给 Codex,也不要把裸启动 `codex` 当作“自动选择了正确角色模型”。如果项目提供 worker 命令校验脚本,校验通过是 `terminal create` 的前置条件。 -**本 kit 对 Cursor 的默认建议**:Test 与 Developer worker 用 `cursor-agent --yolo --model auto`(自动选型,天然偏向高效模型,符合"中低档位"意图,并按当前项目授权启用 YOLO);需要更强时改成具体强模型并保留 `--yolo`。Coordinator 作为强模型脑,通常就是发起编排的那个会话本身。 +**ACK 对 Cursor 的默认建议**:Test 与 Developer worker 用 `cursor-agent --yolo --model auto`(自动选型,天然偏向高效模型,符合"中低档位"意图,并按当前项目授权启用 YOLO);需要更强时改成具体强模型并保留 `--yolo`。Coordinator 作为强模型脑,通常就是发起编排的那个会话本身。 ### Codex 默认映射 diff --git a/kits/ack/core/optimization-method.md b/skills/ack/references/optimization-method.md similarity index 100% rename from kits/ack/core/optimization-method.md rename to skills/ack/references/optimization-method.md diff --git a/kits/ack/core/orca-adapter.md b/skills/ack/references/orca-adapter.md similarity index 100% rename from kits/ack/core/orca-adapter.md rename to skills/ack/references/orca-adapter.md diff --git a/kits/ack/core/prompt-templates.md b/skills/ack/references/prompt-templates.md similarity index 100% rename from kits/ack/core/prompt-templates.md rename to skills/ack/references/prompt-templates.md diff --git a/kits/ack/core/roles-and-permissions.md b/skills/ack/references/roles-and-permissions.md similarity index 97% rename from kits/ack/core/roles-and-permissions.md rename to skills/ack/references/roles-and-permissions.md index 5ec088b..2b3dcd9 100644 --- a/kits/ack/core/roles-and-permissions.md +++ b/skills/ack/references/roles-and-permissions.md @@ -8,7 +8,7 @@ ## 角色模型(三角色) -本 kit 默认三个独立 Agent:**Coordinator 只编排、Test 只验证、Developer 只实现**。关键属性是**验证者 ≠ 实现者**:Developer 不能给自己盖章,验证权在独立的 Test。 +ACK 默认三个独立 Agent:**Coordinator 只编排、Test 只验证、Developer 只实现**。关键属性是**验证者 ≠ 实现者**:Developer 不能给自己盖章,验证权在独立的 Test。 | 角色 | 主要职责 | 验证方式 | 不应做的事 | |------|----------|----------|------------| diff --git a/kits/ack/scripts/validate_tasks.py b/skills/ack/scripts/validate_tasks.py similarity index 100% rename from kits/ack/scripts/validate_tasks.py rename to skills/ack/scripts/validate_tasks.py diff --git a/kits/ack/scripts/validate_worker_command.py b/skills/ack/scripts/validate_worker_command.py similarity index 100% rename from kits/ack/scripts/validate_worker_command.py rename to skills/ack/scripts/validate_worker_command.py diff --git a/kits/ack/templates/project.template.md b/skills/ack/templates/project.template.md similarity index 67% rename from kits/ack/templates/project.template.md rename to skills/ack/templates/project.template.md index 0144bb5..d09f291 100644 --- a/kits/ack/templates/project.template.md +++ b/skills/ack/templates/project.template.md @@ -1,14 +1,13 @@ # <项目名> Agent 协作协议(项目覆盖层) -> 本项目基于 ack v(见 `docs/ack/kit/VERSION`)。 -> 稳定规范引用 `docs/ack/kit/core/`,不复制其内容;本文件只填项目自己的差异。 +> 本项目基于 ACK Skill v。通用规范由 `/ack` 从 Skill 自身的 +> `references/` 读取;本文件只保存项目差异。 > > **本文件是「项目覆盖层」,文件名可配置。** 默认放 `docs/ack/project.md`, > 不占用 `AGENTS.md`,避免与团队已有的 `AGENTS.md` 约定冲突。 > 若希望 Agent 自动加载,可在项目 `AGENTS.md` 里加一行指向本文件,或直接把本文件命名为 `AGENTS.md`。 > 无论叫什么,都在 `tasks.yaml` 的 `project.overlayFile` 记录实际路径。 -> -> 目录约定:`docs/ack/` 下只有一个软链接 `kit/`(指向共享框架),加本项目 `project.md` + `tasks.yaml`。 +> `docs/ack/` 只保存本项目的 `project.md` 与 `tasks.yaml`,不复制或链接 Skill。 ## 项目概览 @@ -19,17 +18,17 @@ - 任务板:`docs/ack/tasks.yaml` - 覆盖层文件:``(默认 `docs/ack/project.md`) -## 稳定规范(不在此重复,直接引用) +## 通用规范(由 ACK Skill 按需读取) -- 开始一个需求(启动手册):`docs/ack/kit/core/kickoff.md` -- 角色模型 / 权限 / 状态机 / 完成定义:`docs/ack/kit/core/roles-and-permissions.md` -- 模型档位与升级规则:`docs/ack/kit/core/model-routing.md` -- 闭环流程(含手动模式、worktree 对齐):`docs/ack/kit/core/closed-loop.md` -- 优化方法(验收信号、三轮策略):`docs/ack/kit/core/optimization-method.md` -- 派发 prompt 模板:`docs/ack/kit/core/prompt-templates.md` -- Orca 编排命令(可选):`docs/ack/kit/core/orca-adapter.md` +- 开始需求:`references/kickoff.md` +- 角色、权限、状态机与完成定义:`references/roles-and-permissions.md` +- 模型档位与升级规则:`references/model-routing.md` +- 闭环流程与 worktree 对齐:`references/closed-loop.md` +- 验收信号与三轮策略:`references/optimization-method.md` +- 派发 prompt 模板:`references/prompt-templates.md` +- Orca 编排命令(可选):`references/orca-adapter.md` -## 模型档位(项目可覆盖,默认见 core/model-routing.md) +## 模型档位(项目可覆盖,默认见 references/model-routing.md) | 角色 | 默认档位 | 本项目实际 | |------|----------|------------| @@ -68,16 +67,12 @@ Test 黑盒复测: ``` -任务板校验: +任务板校验由 `/ack` 使用 Skill 自带的 `scripts/validate_tasks.py` 执行。 -```bash -python3 docs/ack/kit/scripts/validate_tasks.py docs/ack/tasks.yaml -``` - -## 硬规则(其余见 kit/core/) +## 硬规则(其余见 references/) - 三角色独立:Coordinator 只编排、Test 只验证、Developer 只实现(验证者 ≠ 实现者)。 -- 模型分层:Coordinator 用强模型且不亲自跑测试,Test/Developer 用中低模型,必要时升级(见 kit/core/model-routing.md)。 +- 模型分层:Coordinator 用强模型且不亲自跑测试,Test/Developer 用中低模型,必要时升级(见 references/model-routing.md)。 - `worker_done` 与复测报告都不等于完成。必须 Test 独立复测 + Coordinator 终检后才能 `verified`。 - 只有 Coordinator 写 `tasks.yaml`;Developer 与 Test 都只读,通过消息回报。 - 每个任务最多派发 3 轮,仍不过标记 `leftover` 并继续下一个。 diff --git a/kits/ack/templates/tasks.schema.json b/skills/ack/templates/tasks.schema.json similarity index 94% rename from kits/ack/templates/tasks.schema.json rename to skills/ack/templates/tasks.schema.json index ee8aacb..1227600 100644 --- a/kits/ack/templates/tasks.schema.json +++ b/skills/ack/templates/tasks.schema.json @@ -1,7 +1,7 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://git.yumee.top/laily/skills/kits/ack/tasks.schema.json", - "title": "Agent Collaboration Kit task board", + "$id": "https://git.yumee.top/laily/skills/skills/ack/templates/tasks.schema.json", + "title": "ACK task board", "description": "tasks.yaml 的权威结构。跨语言可用;参考校验实现见 scripts/validate_tasks.py。", "type": "object", "required": ["version", "project", "tasks"], @@ -10,10 +10,14 @@ "version": { "type": "integer", "minimum": 1 }, "updatedAt": { "type": "string" }, "source": { "type": "string" }, - "kitVersion": { + "ackVersion": { "type": "string", "description": "接入时所基于的 ack 版本,便于日后 diff 升级" }, + "kitVersion": { + "type": "string", + "description": "旧版 ACK 版本字段;兼容读取,新项目应使用 ackVersion" + }, "project": { "type": "object", "required": ["name"], diff --git a/kits/ack/templates/tasks.template.yaml b/skills/ack/templates/tasks.template.yaml similarity index 96% rename from kits/ack/templates/tasks.template.yaml rename to skills/ack/templates/tasks.template.yaml index 3490ee7..24678a9 100644 --- a/kits/ack/templates/tasks.template.yaml +++ b/skills/ack/templates/tasks.template.yaml @@ -2,7 +2,7 @@ version: 1 updatedAt: "" source: "Coordinator (PM) Agent" -kitVersion: "<接入时的 ack 版本,见 kit 根 VERSION>" +ackVersion: "<接入时的 ack skill 版本>" project: name: "" repoPath: "" diff --git a/skills/skiff/SKILL.md b/skills/skiff/SKILL.md index 7d1a30a..9814a94 100644 --- a/skills/skiff/SKILL.md +++ b/skills/skiff/SKILL.md @@ -2,9 +2,9 @@ name: skiff description: >- 创建和维护 ~/.skills 自研 skill:把项目开发中产生的想法提炼为草稿,完善并校验后发布, - 用 skiff add/remove 在项目及全局挂卸 skill,或用 skiff kit init 初始化项目规范包。 + 用 skiff add/remove 在项目及全局挂卸 skill,或用 skiff init 初始化 skill 项目状态。 触发词:skiff、自研 skill、创建 skill、想做一个 skill、publish skill、安装自研 skill、 - 更新 skill 到项目、初始化 kit。 + 更新 skill 到项目、初始化 skill。 --- # skiff 自研 Skill 工作流 @@ -136,15 +136,15 @@ skiff rm discussion-notes -g -y # rm 别名 skiff add --list ``` -初始化项目 kit: +使用 Skill 自带模板初始化项目状态: ```bash -skiff kit init ack # 当前项目,默认软链接到 SSOT -skiff kit init ack --project ~/app # 指定项目 -skiff kit init ack --copy # 用户明确要求时整份复制 +skiff init ack +skiff init ack --project ~/app ``` -`skiff` 只负责可靠地创建 kit 文件。需要分析项目并完善 ACK 配置、检查接入状态或 +`skiff` 只负责可靠地生成项目状态文件,不复制或链接 Skill。需要分析项目并完善 +ACK 配置、检查接入状态或 运行三角色闭环时,显式调用全局 `/ack` skill。 --- @@ -173,7 +173,7 @@ skiff kit init ack --copy # 用户明确要求时整份复制 | `create --idea TEXT [--from-project PATH]` | 创建自研 skill 草稿 | | `check ` | 校验草稿或正式 skill | | `finalize ` | 校验草稿并转为正式 skill | -| `kit init [--project DIR] [--copy]` | 在项目中初始化 kit | +| `init [--project DIR]` | 使用 skill 模板初始化项目状态 | --- diff --git a/tests/test_ack_skill.py b/tests/test_ack_skill.py index 022abfd..7a8cf46 100644 --- a/tests/test_ack_skill.py +++ b/tests/test_ack_skill.py @@ -8,15 +8,16 @@ REPO_ROOT = Path(__file__).resolve().parents[1] class AckSkillContentTests(unittest.TestCase): - def test_ack_skill_routes_to_kit_without_modifying_agent_instructions(self) -> None: + def test_ack_skill_owns_resources_without_modifying_agent_instructions(self) -> None: content = (REPO_ROOT / "skills" / "ack" / "SKILL.md").read_text(encoding="utf-8") for expected in ( - "skiff kit init ack --project ", + "skiff init ack --project ", "docs/ack/project.md", "docs/ack/tasks.yaml", "tasks: []", "validate_tasks.py", + "references/kickoff.md", "不要修改项目的 `AGENTS.md`", "当前会话担任 Coordinator", ): diff --git a/tests/test_project_skill.py b/tests/test_project_skill.py index e02dfe2..9559ae2 100644 --- a/tests/test_project_skill.py +++ b/tests/test_project_skill.py @@ -19,7 +19,7 @@ class ProjectSkillContentTests(unittest.TestCase): "skiff check ", "~/.skills/skills//", "第三方 skill", - "skiff kit init ack", + "skiff init ack", "显式调用全局 `/ack` skill", ): self.assertIn(expected, content) diff --git a/tests/test_kit_init.py b/tests/test_skill_init.py similarity index 63% rename from tests/test_kit_init.py rename to tests/test_skill_init.py index 297ef7e..c81f82a 100644 --- a/tests/test_kit_init.py +++ b/tests/test_skill_init.py @@ -11,22 +11,23 @@ from pathlib import Path REPO_ROOT = Path(__file__).resolve().parents[1] -class KitInitTests(unittest.TestCase): +class SkillInitTests(unittest.TestCase): def setUp(self) -> None: self.temp_dir = tempfile.TemporaryDirectory() self.home = Path(self.temp_dir.name) self.skills_home = self.home / ".skills" - kit = self.skills_home / "kits" / "ack" - (kit / "templates").mkdir(parents=True) - (kit / "scripts").mkdir() - (kit / "VERSION").write_text("1.2.3\n", encoding="utf-8") - (kit / "templates" / "project.template.md").write_text( - "# \nversion=\npath=\n", + skill = self.skills_home / "skills" / "ack" + (skill / "templates").mkdir(parents=True) + (skill / "scripts").mkdir() + (skill / "SKILL.md").write_text("---\nname: ack\n---\n", encoding="utf-8") + (skill / "VERSION").write_text("1.2.3\n", encoding="utf-8") + (skill / "templates" / "project.template.md").write_text( + "# \nversion=\npath=\n", encoding="utf-8", ) - (kit / "templates" / "tasks.template.yaml").write_text( + (skill / "templates" / "tasks.template.yaml").write_text( 'updatedAt: ""\n' - 'kitVersion: "<接入时的 ack 版本,见 kit 根 VERSION>"\n' + 'ackVersion: "<接入时的 ack skill 版本>"\n' 'project:\n' ' name: ""\n' ' repoPath: ""\n' @@ -50,16 +51,16 @@ class KitInitTests(unittest.TestCase): check=False, ) - def test_init_creates_symlink_and_rendered_project_files(self) -> None: + def test_init_creates_only_rendered_project_files(self) -> None: project = self.home / "sample-app" project.mkdir() - result = self.run_skiff("kit", "init", "ack", "--project", str(project)) + result = self.run_skiff("init", "ack", "--project", str(project)) self.assertEqual(result.returncode, 0, result.stderr) target = project / "docs" / "ack" - self.assertTrue((target / "kit").is_symlink()) - self.assertEqual((target / "kit").resolve(), self.skills_home / "kits" / "ack") + self.assertFalse((target / "kit").exists()) + self.assertFalse((target / "framework").exists()) project_content = (target / "project.md").read_text(encoding="utf-8") tasks_content = (target / "tasks.yaml").read_text(encoding="utf-8") self.assertIn("# sample-app", project_content) @@ -67,18 +68,6 @@ class KitInitTests(unittest.TestCase): self.assertIn(f'repoPath: "{project}"', tasks_content) self.assertNotIn("", tasks_content) - def test_init_copy_mode_copies_kit(self) -> None: - project = self.home / "copied-app" - project.mkdir() - - result = self.run_skiff("kit", "init", "ack", "--copy", "--project", str(project)) - - self.assertEqual(result.returncode, 0, result.stderr) - target = project / "docs" / "ack" / "kit" - self.assertTrue(target.is_dir()) - self.assertFalse(target.is_symlink()) - self.assertEqual((target / "VERSION").read_text(encoding="utf-8"), "1.2.3\n") - def test_init_refuses_to_overwrite_existing_files(self) -> None: project = self.home / "existing-app" target = project / "docs" / "ack" @@ -86,22 +75,28 @@ class KitInitTests(unittest.TestCase): existing = target / "project.md" existing.write_text("keep me", encoding="utf-8") - result = self.run_skiff("kit", "init", "ack", "--project", str(project)) + result = self.run_skiff("init", "ack", "--project", str(project)) self.assertNotEqual(result.returncode, 0) self.assertIn("拒绝覆盖已有路径", result.stderr) self.assertEqual(existing.read_text(encoding="utf-8"), "keep me") - self.assertFalse((target / "kit").exists()) + self.assertFalse((target / "tasks.yaml").exists()) def test_init_rejects_missing_project_directory(self) -> None: project = self.home / "missing-app" - result = self.run_skiff("kit", "init", "ack", "--project", str(project)) + result = self.run_skiff("init", "ack", "--project", str(project)) self.assertNotEqual(result.returncode, 0) self.assertIn("项目目录不存在", result.stderr) self.assertFalse(project.exists()) + def test_legacy_kit_command_is_not_exposed(self) -> None: + result = self.run_skiff("kit", "init", "ack") + + self.assertNotEqual(result.returncode, 0) + self.assertIn("invalid choice", result.stderr) + if __name__ == "__main__": unittest.main()