Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 17 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,13 @@ AI Project Workflow makes delivery explicit:
v
your-project/
├── AGENTS.md, CLAUDE.md entry points read by the AI tool
├── core/ full copy of the canonical source
├── .cursor/ or .trae/ or ... adapter files where your tool loads them
└── .ai-workflow/state.json workflow state
└── .ai-workflow/ everything APW-internal
├── VERSION
├── state.json workflow state
├── project.yaml optional custom stage order
├── runtime/ skills, rules, templates, schemas, agents
└── adapters/ platform notes
```

Enforcement is prompt-based. The adapter instructs the AI agent to read the active Skill, verify upstream documents, and update the state file before moving on. The CLI verifies the files (`apw validate`, `apw status`); the agent follows the contract because every entry point tells it to. If an agent drifts, point it back to `AGENTS.md`.
Expand Down Expand Up @@ -87,15 +91,15 @@ This is what actually happens after installation, using a todo web app in Cursor
npx @dayahs/ai-project-workflow init todo-app --platform cursor
```

`todo-app/` now contains `AGENTS.md`, `core/`, `.cursor/`, and `.ai-workflow/state.json` with `currentStage: "init"`.
`todo-app/` now contains `AGENTS.md`, `CLAUDE.md`, `.cursor/`, and a `.ai-workflow/` directory holding the runtime, the state file (`currentStage: "init"`) and everything else APW-internal. The project root stays clean.

2. **Start the first stage.** Open `todo-app` in Cursor and tell the agent:

```text
/prd I want to build a todo web app for small teams
```

The rule in `.cursor/rules/ai-sdd.mdc` is always attached, so the agent reads `core/skills/prd/SKILL.md`, asks clarifying questions first, then writes `docs/PRD.md` and updates the state file.
The rule in `.cursor/rules/ai-sdd.mdc` is always attached, so the agent reads `.ai-workflow/runtime/skills/prd/SKILL.md`, asks clarifying questions first, then writes `docs/PRD.md` and updates the state file.

3. **Review and gate.** Read `docs/PRD.md` yourself. The agent stops after each stage; nothing advances without your confirmation.

Expand Down Expand Up @@ -133,13 +137,13 @@ Upstream documents are authoritative. If the code disagrees with the SDD, fix th

## Configurable workflows

APW uses the built-in eight-stage workflow when a project has no `.apw/project.yaml` file:
APW uses the built-in eight-stage workflow when a project has no `.ai-workflow/project.yaml` file:

```text
init -> prd -> hld -> sdd -> impl -> review -> deploy -> retro
```

Projects can define a stage order in `.apw/project.yaml`:
Projects can define a stage order in `.ai-workflow/project.yaml` (a legacy `.apw/project.yaml` is still honored):

```yaml
protocolVersion: 1.0.0
Expand All @@ -157,9 +161,9 @@ Stage ids must start with a lowercase letter and may contain lowercase letters,
Custom stage Skills are resolved in this order:

```text
1. .apw/skills/<stage>/SKILL.md
1. .ai-workflow/skills/<stage>/SKILL.md (legacy .apw/skills/ still honored)
2. installed platform Skill
3. core/skills/<stage>/SKILL.md
3. .ai-workflow/runtime/skills/<stage>/SKILL.md (core/skills/ in this repository)
```

The project-level YAML parser intentionally supports only this documented subset: scalar `protocolVersion`, a `stages` list, string stage ids, and object stage entries with `id`, `title`, and `description`. It does not support anchors, aliases, multiline blocks, inline collections, or arbitrary nesting.
Expand All @@ -171,8 +175,8 @@ What gets installed and how the workflow is triggered, per tool:
| Tool | Files installed | How it loads |
|---|---|---|
| Cursor | `.cursor/rules/ai-sdd.mdc` (always applied), `.cursor/skills/`, `.cursor/agents/` | The rule auto-attaches to every chat and points the agent at the active Skill. Type the stage command (for example `/prd`) in chat. |
| Claude Code | `CLAUDE.md`, `AGENTS.md`, `core/` | `CLAUDE.md` is read automatically at session start. |
| Codex | `AGENTS.md`, `core/` | Codex reads `AGENTS.md` natively. |
| Claude Code | `CLAUDE.md`, `AGENTS.md`, `.ai-workflow/runtime/` | `CLAUDE.md` is read automatically at session start. |
| Codex | `AGENTS.md`, `.ai-workflow/runtime/` | Codex reads `AGENTS.md` natively. |
| TRAE | `.trae/rules.md`, `.trae/skills/`, `.trae/agents/` | Add `.trae/rules.md` as project rules. TRAE custom agents are configured in its UI — paste the role definitions from `.trae/agents/` when creating them. |
| Qoder | `.qoder/skills/`, `.qoder/agents/` | Reference the Skill files in your prompts, or rely on the root `AGENTS.md`. |
| CodeBuddy | `.codebuddy/skills/`, `.codebuddy/agents/`, adapter note | Minimal compatibility adapter; falls back to `AGENTS.md`. |
Expand Down Expand Up @@ -204,7 +208,7 @@ Target projects track progress in `.ai-workflow/state.json`:
}
```

The schema lives at `core/schemas/workflow-state.schema.json`. The agent updates this file at the end of every stage; `apw status` reads it back.
The schema lives at `.ai-workflow/runtime/schemas/workflow-state.schema.json` in installed projects (`core/schemas/` in this repository). The agent updates this file at the end of every stage; `apw status` reads it back.

## CLI reference

Expand Down Expand Up @@ -237,7 +241,7 @@ Yes — say so explicitly. The agent records the skip and your reason in `skippe
Yes. Install with `--platform all` (or run `apw install` again with another platform). Adapters live in separate directories and coexist.

**How do I upgrade after a new package version?**
Update the package, then re-run `apw install .` in the project — your edited files are preserved and incoming changes appear as `.ai-sdd.new` files. Run `apw validate .` afterwards.
Update the package, then re-run `apw install .` in the project — your edited files are preserved and incoming changes appear as `.ai-sdd.new` files. Run `apw validate .` afterwards. Projects installed before the consolidated layout (with `core/` at the project root) upgrade with `apw migrate . --apply`.

**A stage went wrong. How do I go back?**
Each Skill defines rollback rules: broken design returns to `sdd`, wrong architecture boundaries return to `hld`, missing requirements return to `prd`. Revise the upstream document first, then rerun the downstream stages.
Expand All @@ -263,7 +267,7 @@ examples/configurable-workflow/
test-node/ test suite (node --test)
```

`core/` is the only canonical source. Adapter files are generated — edit `core/` and run `apw sync . --platform all`.
`core/` is the only canonical source in this repository. Installed projects receive the same content under `.ai-workflow/runtime/`. Adapter files are generated — edit `core/` and run `apw sync . --platform all`.

## Extending

Expand Down
30 changes: 17 additions & 13 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,13 @@ AI Project Workflow 把交付过程显式化:
v
your-project/
├── AGENTS.md, CLAUDE.md AI 工具读取的入口
├── core/ 规范源的完整副本
├── .cursor/ 或 .trae/ 或 ... 适配文件,放在工具真正加载的位置
└── .ai-workflow/state.json 工作流状态
└── .ai-workflow/ APW 内部实现全部收纳于此
├── VERSION
├── state.json 工作流状态
├── project.yaml 可选的自定义阶段配置
├── runtime/ skills、rules、templates、schemas、agents
└── adapters/ 平台说明文件
```

约束是基于提示词的:适配层指示 AI 先读当前阶段的 Skill、核对上游文档、更新状态文件,然后才能推进。CLI 负责校验文件(`apw validate`、`apw status`);AI 遵守契约是因为每个入口都这样要求它。如果 AI 跑偏了,让它重新阅读 `AGENTS.md`。
Expand Down Expand Up @@ -88,15 +92,15 @@ Qoder 待验证:当前测试账号额度不足,尚未完成真实环境验
npx @dayahs/ai-project-workflow init todo-app --platform cursor
```

`todo-app/` 现在包含 `AGENTS.md`、`core/`、`.cursor/` 和 `.ai-workflow/state.json`(`currentStage: "init"`)。
`todo-app/` 现在包含 `AGENTS.md`、`CLAUDE.md`、`.cursor/`,以及一个收纳全部 APW 内部实现的 `.ai-workflow/` 目录(runtime、状态文件 `currentStage: "init"` 等)。项目根目录保持干净。

2. **启动第一个阶段。** 在 Cursor 中打开 `todo-app`,对 AI 说:

```text
/prd 我要做一个面向小团队的待办清单 Web 应用
```

`.cursor/rules/ai-sdd.mdc` 规则始终挂载,AI 会先读 `core/skills/prd/SKILL.md`,先反问澄清,然后把产出写入 `docs/PRD.md` 并更新状态文件。
`.cursor/rules/ai-sdd.mdc` 规则始终挂载,AI 会先读 `.ai-workflow/runtime/skills/prd/SKILL.md`,先反问澄清,然后把产出写入 `docs/PRD.md` 并更新状态文件。

3. **人工审查与门禁。** 你自己读一遍 `docs/PRD.md`。AI 在每个阶段结束后都会停下;没有你的确认,流程不会前进。

Expand Down Expand Up @@ -134,13 +138,13 @@ PRD -> Architecture -> SDD -> Test Plan -> Code

## 可配置工作流

当项目没有 `.apw/project.yaml` 时,APW 使用内置八阶段:
当项目没有 `.ai-workflow/project.yaml` 时,APW 使用内置八阶段:

```text
init -> prd -> hld -> sdd -> impl -> review -> deploy -> retro
```

项目可以在 `.apw/project.yaml` 中定义阶段顺序:
项目可以在 `.ai-workflow/project.yaml` 中定义阶段顺序(旧路径 `.apw/project.yaml` 仍被兼容):

```yaml
protocolVersion: 1.0.0
Expand All @@ -158,9 +162,9 @@ stages:
自定义阶段的 Skill 查找顺序:

```text
1. .apw/skills/<stage>/SKILL.md
1. .ai-workflow/skills/<stage>/SKILL.md(旧路径 .apw/skills/ 仍被兼容)
2. 已安装平台中的 Skill
3. core/skills/<stage>/SKILL.md
3. .ai-workflow/runtime/skills/<stage>/SKILL.md(本仓库内为 core/skills/)
```

项目级 YAML 解析器只支持这里明确展示的子集:标量 `protocolVersion`、`stages` 列表、字符串阶段 id,以及包含 `id`、`title`、`description` 的对象阶段。它不支持 anchors、aliases、多行块、行内集合或任意深层嵌套。
Expand All @@ -172,8 +176,8 @@ stages:
| 工具 | 安装的文件 | 加载方式 |
|---|---|---|
| Cursor | `.cursor/rules/ai-sdd.mdc`(始终生效)、`.cursor/skills/`、`.cursor/agents/` | 规则自动挂载到每次对话,并把 AI 指向当前阶段的 Skill。在对话里输入阶段命令(如 `/prd`)。 |
| Claude Code | `CLAUDE.md`、`AGENTS.md`、`core/` | 会话启动时自动读取 `CLAUDE.md`。 |
| Codex | `AGENTS.md`、`core/` | Codex 原生读取 `AGENTS.md`。 |
| Claude Code | `CLAUDE.md`、`AGENTS.md`、`.ai-workflow/runtime/` | 会话启动时自动读取 `CLAUDE.md`。 |
| Codex | `AGENTS.md`、`.ai-workflow/runtime/` | Codex 原生读取 `AGENTS.md`。 |
| TRAE | `.trae/rules.md`、`.trae/skills/`、`.trae/agents/` | 把 `.trae/rules.md` 添加为项目规则。TRAE 的自定义智能体在其 UI 中配置——创建时把 `.trae/agents/` 里的角色定义粘贴进去。 |
| Qoder | `.qoder/skills/`、`.qoder/agents/` | 在提示词中引用 Skill 文件,或依赖根目录的 `AGENTS.md`。 |
| CodeBuddy | `.codebuddy/skills/`、`.codebuddy/agents/`、适配说明 | 最小兼容适配;回退到 `AGENTS.md`。 |
Expand Down Expand Up @@ -205,7 +209,7 @@ Claude Code 已通过自然语言阶段指令完成真实验证,例如输入 `
}
```

schema 位于 `core/schemas/workflow-state.schema.json`。AI 在每个阶段结束时更新此文件;`apw status` 负责读取展示。
schema 在已安装项目中位于 `.ai-workflow/runtime/schemas/workflow-state.schema.json`(本仓库内为 `core/schemas/`)。AI 在每个阶段结束时更新此文件;`apw status` 负责读取展示。

## CLI 参考

Expand Down Expand Up @@ -238,7 +242,7 @@ apw --version
可以。用 `--platform all` 安装(或对另一个平台再跑一次 `apw install`)。各适配层目录独立,互不干扰。

**包发新版后如何升级?**
更新包,然后在项目里重新运行 `apw install .`——你改过的文件会被保留,新内容以 `.ai-sdd.new` 出现。之后运行 `apw validate .`。
更新包,然后在项目里重新运行 `apw install .`——你改过的文件会被保留,新内容以 `.ai-sdd.new` 出现。之后运行 `apw validate .`。旧布局项目(`core/` 在项目根)用 `apw migrate . --apply` 一键升级到收纳布局。

**某个阶段做坏了,怎么回退?**
每个 Skill 都定义了回退规则:设计无法实现回 `sdd`,架构边界错了回 `hld`,需求缺失回 `prd`。先修订上游文档,再重跑下游阶段。
Expand All @@ -264,7 +268,7 @@ examples/configurable-workflow/
test-node/ 测试套件(node --test)
```

`core/` 是唯一规范源。适配文件是生成物——改 `core/` 后运行 `apw sync . --platform all`。
`core/` 是本仓库的唯一规范源;已安装项目中同样的内容位于 `.ai-workflow/runtime/`。适配文件是生成物——改 `core/` 后运行 `apw sync . --platform all`。

## 扩展

Expand Down
42 changes: 33 additions & 9 deletions src/commands/install.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,47 @@
import { basename, join, relative, sep } from "node:path";
import { PLATFORM_CHOICES, PLATFORM_DOT_DIRS } from "../lib/constants.js";
import { expandPlatforms } from "../lib/adapters.js";
import { copyFileSafe, copyTreeSafe, writeFileSafe } from "../lib/safe-copy.js";
import { copyFileSafe, writeFileSafe } from "../lib/safe-copy.js";
import { initialState } from "../lib/state.js";
import { exists, isDirectory, listFiles } from "../lib/fs-utils.js";
import { exists, isDirectory, listFiles, readText } from "../lib/fs-utils.js";
import { ROOT, rel } from "../lib/path-utils.js";
import { loadWorkflowConfig } from "../lib/workflow-config.js";
import { RUNTIME_DIR, WORKFLOW_DIR, isTextDocPath, toProjectPaths } from "../lib/layout.js";

// Installed projects keep every APW-internal file under .ai-workflow/ so the
// project root only shows the user's own files, the AI entry points
// (AGENTS.md, CLAUDE.md) and the tool dot-directories that the tools
// themselves require at the root. Canonical core/ path references inside
// markdown content are rewritten to .ai-workflow/runtime/ on the way in.
async function installFile(source, destination, context) {
if (isTextDocPath(source)) {
await writeFileSafe(destination, toProjectPaths(await readText(source)), context);
} else {
await copyFileSafe(source, destination, context);
}
}

async function installTree(sourceRoot, targetRoot, context) {
for (const source of await listFiles(sourceRoot)) {
await installFile(source, join(targetRoot, relative(sourceRoot, source)), context);
}
}

// Adapter dot-directories (.cursor/, .trae/, ...) must be installed at the
// project root because that is the only location the tools load them from.
// Everything else in an adapter (README notes) stays under adapters/<platform>/.
// Everything else in an adapter (README notes) goes to
// .ai-workflow/adapters/<platform>/.
async function installAdapter(platform, target, context) {
const source = join(ROOT, "adapters", platform);
if (!(await exists(source))) return;
const dotDir = PLATFORM_DOT_DIRS[platform];
for (const file of await listFiles(source)) {
const relPath = relative(source, file);
const inDotDir = dotDir && (relPath === dotDir || relPath.startsWith(`${dotDir}${sep}`));
const destination = inDotDir ? join(target, relPath) : join(target, "adapters", platform, relPath);
await copyFileSafe(file, destination, context);
const destination = inDotDir
? join(target, relPath)
: join(target, WORKFLOW_DIR, "adapters", platform, relPath);
await installFile(file, destination, context);
}
}

Expand All @@ -36,12 +59,13 @@ export async function installCommand(target, options = {}) {
}

const context = { force: options.force, dryRun: options.dryRun, installed: [], conflicts: [] };
for (const name of ["AGENTS.md", "CLAUDE.md", "VERSION"]) {
await copyFileSafe(join(ROOT, name), join(target, name), context);
for (const name of ["AGENTS.md", "CLAUDE.md"]) {
await installFile(join(ROOT, name), join(target, name), context);
}
await copyTreeSafe(join(ROOT, "core"), join(target, "core"), context);
await copyFileSafe(join(ROOT, "VERSION"), join(target, WORKFLOW_DIR, "VERSION"), context);
await installTree(join(ROOT, "core"), join(target, RUNTIME_DIR), context);
await writeFileSafe(
join(target, ".ai-workflow", "state.json"),
join(target, WORKFLOW_DIR, "state.json"),
`${JSON.stringify(initialState(basename(target), workflowConfig.config), null, 2)}\n`,
context
);
Expand Down
Loading
Loading