@reforma/agentflow 0.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTFLOW.md ADDED
@@ -0,0 +1,85 @@
1
+ # AgentFlow
2
+
3
+ Use this loop for changes larger than an obvious quick fix:
4
+
5
+ ```text
6
+ Research → Grill → Plan → PR → Review → Commit
7
+ ↑ │
8
+ └──── Next PR ─────┘
9
+ ```
10
+
11
+ Research is optional. Small tasks can skip the plan. Write a handoff only when
12
+ the work moves to a fresh context.
13
+
14
+ ## 1. Learn how it works
15
+
16
+ Explore the existing feature, code, or technology before proposing a change.
17
+ Use `/research` when the findings must survive the current chat. Save reusable
18
+ findings under `.agentflow/<feature>/research/`.
19
+
20
+ Skip this step when the area and required change are already clear.
21
+
22
+ ## 2. Sharpen the task
23
+
24
+ Run `/grill`. List assumptions, unresolved decisions, what is in and out of the
25
+ task, and how the result will be checked.
26
+
27
+ Continue until no open decision can change how the work will be done. Then
28
+ proceed directly for a small task or load `/plan` for larger work.
29
+
30
+ ## 3. Plan PR-sized slices
31
+
32
+ Save the plan to `.agentflow/<feature>/plan.md`.
33
+
34
+ Each row is the smallest complete, independently shippable change that does one
35
+ useful thing and has one clear way to test it. Put lower-level pieces before the
36
+ code that uses them.
37
+
38
+ Common shapes:
39
+
40
+ - Full-stack feature: behavior-preserving refactoring, then shared types and
41
+ backend, then frontend integration.
42
+ - Frontend feature: reusable components, then shared runtime or wiring, then
43
+ user-facing interfaces.
44
+ - Small feature: one complete vertical slice.
45
+
46
+ Give a foundation its own row when it is independently useful. Keep
47
+ feature-local components and wiring with their first consumer. Split distinct
48
+ outcomes or architectural decisions that can ship separately.
49
+
50
+ Keep the plan current as implementation changes. Record scope changes and new
51
+ decisions in the plan instead of letting the active PR grow silently.
52
+
53
+ ## 4. Implement one PR
54
+
55
+ Implement the first unchecked row and nothing beyond it. Without a plan, keep
56
+ the change small enough to review as one useful result.
57
+
58
+ Load the relevant project skills. Use `/tdd` when the work should proceed
59
+ test-first.
60
+
61
+ Verify the slice using the checks named in the plan. Check its row only after
62
+ the implementation and verification are complete, then update later rows to
63
+ match what remains.
64
+
65
+ ## 5. Review
66
+
67
+ Run `/code-review` against the completed slice. Fix local findings and reduce
68
+ the change when the review verdict requires it.
69
+
70
+ Read the final diff yourself after the agent review.
71
+
72
+ ## 6. Commit
73
+
74
+ Commit the verified slice using the project's normal workflow. Then return to
75
+ the first unchecked row.
76
+
77
+ ## 7. Refresh context when needed
78
+
79
+ Continue in the current chat while its context remains useful. When it becomes
80
+ noisy, summarize it or start a fresh chat.
81
+
82
+ Run `/handoff` before moving unfinished work to a fresh context. Save the result
83
+ to `.agentflow/<feature>/handoff.md` with what shipped, what changed, and which
84
+ PR comes next. Bring the plan and handoff into the new context, then resume from
85
+ the first unchecked row.
package/README.md CHANGED
@@ -44,7 +44,7 @@ Reusable agent skills are published from `skills/`:
44
44
 
45
45
  ---
46
46
 
47
- ## The Loop
47
+ ## 🔄 The Loop
48
48
 
49
49
  Research helps when the agent does not know the area, and most larger tasks also need a plan. But almost every task goes through Grill. Small, obvious changes can go straight from Grill to implementation.
50
50
 
@@ -58,7 +58,12 @@ Research helps when the agent does not know the area, and most larger tasks also
58
58
 
59
59
  Repeat steps 4–7 until every PR in the plan is complete.
60
60
 
61
- ### Step 1. Learn how it works (optional)
61
+ AgentFlow keeps research, plans, handoffs, and local setup state under
62
+ `.agentflow/`. Version control is your choice: ignore the directory for a
63
+ private workflow, or commit it to share the work with your team like an
64
+ OpenSpec workspace.
65
+
66
+ ### 🔍 Step 1. Learn how it works (optional)
62
67
 
63
68
  Research does not require a skill. Even a simple prompt like "Find out how
64
69
  authentication works in this project" can make the implementation much easier.
@@ -73,7 +78,7 @@ context compaction or in a new chat.
73
78
 
74
79
  Even if you skip this step, Grill will fill in any gaps.
75
80
 
76
- ### Step 2. Sharpen the idea with Grill
81
+ ### 🔥 Step 2. Sharpen the idea with Grill
77
82
 
78
83
  Grill is the core of AgentFlow and the one step used for the most tasks.
79
84
 
@@ -84,10 +89,9 @@ decision points, and recommends an answer for each one. You confirm or correct
84
89
  that understanding. If your answers open new questions, the agent continues
85
90
  until nothing important is left unclear.
86
91
 
87
- This gives the implementation an agreed starting point instead of leaving the
88
- agent to fill in gaps on its own.
92
+ Now the agent does not have to fill in the gaps while coding.
89
93
 
90
- ### Step 3. Plan and slice the work into PRs
94
+ ### 🗂️ Step 3. Plan and slice the work into PRs
91
95
 
92
96
  For a larger task, planning usually follows Grill in the same chat. If you asked
93
97
  Grill to plan next, it loads `/plan` automatically. You can also run `/plan`
@@ -98,14 +102,14 @@ Native Plan mode, the agent uses its built-in planning flow and native plan
98
102
  artifact instead.
99
103
 
100
104
  The plan breaks the feature into PRs that can be shipped one by one. A PR is the
101
- smallest complete change with one coherent outcome and a clear way to verify it,
102
- not a fixed number of files or lines.
105
+ smallest complete change that does one useful thing and has a clear way to check
106
+ it, not a fixed number of files or lines.
103
107
 
104
- Larger work is usually sliced from foundations to consumers. A full-stack
105
- feature might start with behavior-preserving refactoring, continue with shared
106
- types and backend work, and finish with the frontend. A frontend feature might
107
- move from reusable components, through shared runtime or wiring, to the
108
- user-facing interface.
108
+ Larger work usually starts with lower-level pieces and moves to the code that
109
+ uses them. A full-stack feature might start with behavior-preserving
110
+ refactoring, continue with shared types and backend work, and finish with the
111
+ frontend. A frontend feature might move from reusable components, through
112
+ shared runtime or wiring, to the user-facing interface.
109
113
 
110
114
  These are examples, not a required template. A small feature stays as one
111
115
  vertical slice. Feature-local components and wiring stay with the interface
@@ -113,10 +117,7 @@ that first uses them instead of becoming placeholder PRs.
113
117
 
114
118
  Keep the plan updated as the work changes.
115
119
 
116
- **Done when:** someone can open the plan, find the next PR, and see how to
117
- verify it.
118
-
119
- ### Step 4. Implement one PR
120
+ ### 🛠️ Step 4. Implement one PR
120
121
 
121
122
  Implement the first unchecked PR and nothing beyond it. Without a plan, keep the
122
123
  change small enough to review. You can stay in the current chat, start a fresh
@@ -126,34 +127,28 @@ to another chat. Use `/tdd` for test-first work.
126
127
  Load any relevant skills named in `AGENTS.md`. If work spills into a later PR,
127
128
  update the plan instead of silently expanding the current one.
128
129
 
129
- **Done when:** the PR does what the plan promised, and the plan matches the work.
130
+ Before review, update `plan.md`: check the completed PR only after its checks
131
+ pass, then apply any scope changes to later rows.
130
132
 
131
- ### Step 5. Agent review
133
+ ### 🤖 Step 5. Agent review
132
134
 
133
135
  Run `/code-review` on the completed PR. It looks for code to reuse, unnecessary
134
136
  wrappers, and avoidable complexity. It fixes small local problems and returns a
135
137
  verdict: keep, shrink, or burn.
136
138
 
137
- **Done when:** the review has run and its local fixes are applied.
138
-
139
- ### Step 6. Your review, then commit
139
+ ### Step 6. Your review, then commit
140
140
 
141
141
  Read the diff yourself, then commit it using the project's normal workflow.
142
142
 
143
- **Done when:** the PR is reviewed and committed.
144
-
145
- ### Step 7. Refresh the context when needed
143
+ ### 🔄 Step 7. Refresh the context when needed
146
144
 
147
145
  Keep the current chat if it still has useful context. When it gets noisy,
148
146
  summarize it or start a fresh one. Run `/handoff` to save what shipped, what
149
147
  changed, and which PR comes next.
150
148
 
151
- Attach the plan and handoff to a fresh chat when they exist.
152
-
153
- **Done when:** you can start the next PR without reconstructing the previous
154
- work. Return to step 4.
149
+ Attach the plan and handoff to a fresh chat when they exist, then return to step 4.
155
150
 
156
- ## Install
151
+ ## 📦 Install
157
152
 
158
153
  Install the complete workflow in a project:
159
154
 
@@ -161,9 +156,22 @@ Install the complete workflow in a project:
161
156
  npx @reforma/agentflow init
162
157
  ```
163
158
 
164
- The command installs every AgentFlow skill, writes `AGENTFLOW.md`, and ignores
165
- the local `.agentflow/` artifacts. It prints a short pointer you can add to
166
- `AGENTS.md` when you want agents in that project to follow the full loop.
159
+ AgentFlow first asks which parts to install: the skills, the concise
160
+ `AGENTFLOW.md` loop, and a one-line pointer in `AGENTS.md`. When you choose the
161
+ skills, the `skills` CLI handles the skill picker, target agents, project or
162
+ global scope, and installation method.
163
+
164
+ Use its standard AgentFlow flags when the destination is already known:
165
+
166
+ ```bash
167
+ npx @reforma/agentflow init --global --agent cursor
168
+ ```
169
+
170
+ For automation, accept every default without prompts:
171
+
172
+ ```bash
173
+ npx @reforma/agentflow init --yes
174
+ ```
167
175
 
168
176
  Install only one skill without the workflow:
169
177
 
@@ -177,6 +185,10 @@ Update the complete workflow:
177
185
  npx @reforma/agentflow@latest update
178
186
  ```
179
187
 
188
+ Updates are non-interactive after setup and refresh only the AgentFlow parts
189
+ selected during initialization. In a project without AgentFlow, `update`
190
+ starts the same setup as `init`.
191
+
180
192
  Or update one independently installed skill:
181
193
 
182
194
  ```bash
@@ -185,24 +197,7 @@ npx skills update plan
185
197
 
186
198
  ---
187
199
 
188
- ## Why AgentFlow?
189
-
190
- Coding agents can handle large changes, but chat history is a poor place to
191
- keep requirements, scope, and decisions. AgentFlow moves that information into
192
- small files and gives each PR a clear boundary.
193
-
194
- - **Learn the ground before estimating the work** — the agent sees the existing
195
- behavior and code before discussing a solution.
196
- - **Resolve decisions before coding** — `/grill` exposes assumptions while they
197
- are still cheap to change.
198
- - **Keep changes reviewable** — the plan divides a large feature into PR-sized
199
- slices that are implemented and reviewed in order.
200
- - **Preserve context between sessions** — the review artifacts, plan and handoff tell the next agent what is true and what comes next.
201
- - **Use an opinionated workflow without heavy artifacts** — the sequence is
202
- fixed, while the documentation is limited to one plan and one current
203
- handoff.
204
-
205
- ### How we compare
200
+ ## ⚖️ How we compare
206
201
 
207
202
  OpenSpec and Spec Kit try to cover most of spec-driven development with their
208
203
  own commands, templates, and artifacts. AgentFlow does not try to be an
@@ -221,11 +216,11 @@ task lists. AgentFlow gives you an order of work without asking you to move the
221
216
  rest of your development process into the framework.
222
217
 
223
218
  **vs. an unstructured chat** — Working directly in chat is enough for a small
224
- fix. On larger changes, AgentFlow keeps decisions out of transient history,
225
- limits scope to one reviewable slice, and gives the next session a reliable
226
- starting point.
219
+ fix. On larger changes, AgentFlow keeps decisions out of chat history, limits
220
+ scope to one reviewable slice, and gives the next session enough context to
221
+ continue.
227
222
 
228
- ## Releasing
223
+ ## 🚀 Releasing
229
224
 
230
225
  Add a changeset with every publishable change:
231
226
 
@@ -238,9 +233,6 @@ updates its version and changelog, publishes it to npm through trusted
238
233
  publishing, and commits the release files back to `main`. A separate job then
239
234
  publishes the matching versioned Agent Skills release on GitHub.
240
235
 
241
- The npm trusted publisher for `@reforma/agentflow` must point at
242
- `reforma-dev/agentflow/.github/workflows/publish_npm.yml`.
243
-
244
236
  Validate a release locally without publishing:
245
237
 
246
238
  ```bash
@@ -249,4 +241,12 @@ bun run test
249
241
  bun publish --dry-run
250
242
  ```
251
243
 
244
+ ## 📖 License
245
+
252
246
  AgentFlow is available under the [MIT License](LICENSE).
247
+
248
+ ## 👤 Maintainer
249
+
250
+ <img src="https://github.com/kachurun.png" width="100" height="100" alt="@kachurun's avatar" style="border-radius: 50%;">
251
+
252
+ Maintained with ❤️ by [@kachurun](https://github.com/kachurun)
package/bin/agentflow.js CHANGED
@@ -1,20 +1,23 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli.ts
4
+ import { cancel, isCancel, multiselect } from "@clack/prompts";
4
5
  import { existsSync as existsSync2, readFileSync as readFileSync3 } from "node:fs";
5
- import { dirname as dirname2, resolve as resolve3 } from "node:path";
6
+ import { dirname as dirname3, resolve as resolve3 } from "node:path";
6
7
  import { fileURLToPath } from "node:url";
7
8
 
8
9
  // src/project.ts
9
10
  import {
10
11
  existsSync,
12
+ mkdirSync,
11
13
  readFileSync,
12
14
  renameSync,
13
15
  writeFileSync
14
16
  } from "node:fs";
15
- import { resolve } from "node:path";
17
+ import { dirname, resolve } from "node:path";
16
18
  var GENERATED_MARKER = "<!-- Generated by AgentFlow CLI. Run `npx @reforma/agentflow@latest update` to refresh. -->";
17
- var AGENTS_SNIPPET = "**Agent loop:** [AGENTFLOW.md](AGENTFLOW.md) optional research grill → usually `/plan` → sequential PRs (implement → `/code-review` → commit) → refresh context when needed.";
19
+ var AGENTS_POINTER = "Check @AGENTFLOW.md to follow the development workflow.";
20
+ var SETUP_COMPONENTS = ["skills", "workflow", "agents"];
18
21
  function generatedWorkflow(workflow) {
19
22
  return `${GENERATED_MARKER}
20
23
 
@@ -25,21 +28,37 @@ function isGeneratedWorkflow(path) {
25
28
  return existsSync(path) && readFileSync(path, "utf8").startsWith(GENERATED_MARKER);
26
29
  }
27
30
  function writeAtomically(path, contents) {
31
+ mkdirSync(dirname(path), { recursive: true });
28
32
  const temporaryPath = `${path}.agentflow-tmp`;
29
33
  writeFileSync(temporaryPath, contents);
30
34
  renameSync(temporaryPath, path);
31
35
  }
32
- function ensureIgnored(cwd) {
33
- const path = resolve(cwd, ".gitignore");
36
+ function ensureAgentsPointer(cwd) {
37
+ const path = resolve(cwd, "AGENTS.md");
34
38
  const current = existsSync(path) ? readFileSync(path, "utf8") : "";
35
- const alreadyIgnored = current.split(/\r?\n/).some((line) => /^\/?\.agentflow\/?$/.test(line.trim()));
36
- if (alreadyIgnored) {
39
+ if (current.split(/\r?\n/).some((line) => line.trim() === AGENTS_POINTER)) {
37
40
  return;
38
41
  }
39
42
  const separator = current.length === 0 || current.endsWith(`
40
43
  `) ? "" : `
41
44
  `;
42
- writeAtomically(path, `${current}${separator}.agentflow/
45
+ writeAtomically(path, `${current}${separator}${AGENTS_POINTER}
46
+ `);
47
+ }
48
+ function readSetupConfig(cwd) {
49
+ const path = resolve(cwd, ".agentflow/config.json");
50
+ if (!existsSync(path)) {
51
+ return null;
52
+ }
53
+ const config = JSON.parse(readFileSync(path, "utf8"));
54
+ if (config.version !== 1 || !Array.isArray(config.components) || config.components.some((component) => !SETUP_COMPONENTS.includes(component))) {
55
+ throw new Error(".agentflow/config.json is not a valid AgentFlow config.");
56
+ }
57
+ return config;
58
+ }
59
+ function writeSetupConfig(cwd, components) {
60
+ const config = { version: 1, components };
61
+ writeAtomically(resolve(cwd, ".agentflow/config.json"), `${JSON.stringify(config, null, 2)}
43
62
  `);
44
63
  }
45
64
 
@@ -47,7 +66,7 @@ function ensureIgnored(cwd) {
47
66
  import { spawnSync } from "node:child_process";
48
67
  import { readFileSync as readFileSync2 } from "node:fs";
49
68
  import { createRequire } from "node:module";
50
- import { dirname, resolve as resolve2 } from "node:path";
69
+ import { dirname as dirname2, resolve as resolve2 } from "node:path";
51
70
  var AGENTFLOW_SKILLS = [
52
71
  "research",
53
72
  "grill",
@@ -65,7 +84,7 @@ var runSkills = (args) => {
65
84
  if (!relativeBin) {
66
85
  throw new Error("The installed skills package does not expose a skills bin.");
67
86
  }
68
- const result = spawnSync(process.execPath, [resolve2(dirname(packagePath), relativeBin), ...args], { stdio: "inherit" });
87
+ const result = spawnSync(process.execPath, [resolve2(dirname2(packagePath), relativeBin), ...args], { stdio: "inherit" });
69
88
  if (result.error) {
70
89
  throw result.error;
71
90
  }
@@ -73,7 +92,7 @@ var runSkills = (args) => {
73
92
  };
74
93
 
75
94
  // src/cli.ts
76
- var packageRoot = resolve3(dirname2(fileURLToPath(import.meta.url)), "..");
95
+ var packageRoot = resolve3(dirname3(fileURLToPath(import.meta.url)), "..");
77
96
  var packageJson = JSON.parse(readFileSync3(resolve3(packageRoot, "package.json"), "utf8"));
78
97
  function parseOptions(args, command) {
79
98
  const forwarded = [];
@@ -119,18 +138,36 @@ Usage:
119
138
  agentflow --version
120
139
 
121
140
  Commands:
122
- init Install all AgentFlow skills and write AGENTFLOW.md
123
- update Update installed AgentFlow skills and refresh AGENTFLOW.md
141
+ init Choose and install AgentFlow components
142
+ update Update AgentFlow, installing it first when needed
124
143
 
125
- AgentFlow prints the AGENTS.md snippet for you to add manually.
144
+ The skills CLI handles skill, agent, scope, and installation choices.
126
145
  `;
127
146
  }
128
- function runCli(args, {
147
+ async function promptSetup() {
148
+ const selected = await multiselect({
149
+ message: "What do you want to install?",
150
+ options: [
151
+ { value: "skills", label: "AgentFlow skills" },
152
+ { value: "workflow", label: "AGENTFLOW.md" },
153
+ { value: "agents", label: "AGENTS.md pointer" }
154
+ ],
155
+ initialValues: [...SETUP_COMPONENTS],
156
+ required: true
157
+ });
158
+ if (isCancel(selected)) {
159
+ cancel("AgentFlow setup cancelled.");
160
+ return null;
161
+ }
162
+ return selected;
163
+ }
164
+ async function runCli(args, {
129
165
  cwd = process.cwd(),
130
166
  stdout = process.stdout,
131
167
  stderr = process.stderr,
168
+ promptSetup: selectSetup = promptSetup,
132
169
  runSkills: executeSkills = runSkills,
133
- workflow = readFileSync3(resolve3(packageRoot, "README.md"), "utf8")
170
+ workflow = readFileSync3(resolve3(packageRoot, "AGENTFLOW.md"), "utf8")
134
171
  } = {}) {
135
172
  const [command, ...optionArgs] = args;
136
173
  if (!command || command === "--help" || command === "-h") {
@@ -151,27 +188,42 @@ ${help()}`);
151
188
  try {
152
189
  const forwarded = parseOptions(optionArgs, command);
153
190
  const workflowPath = resolve3(cwd, "AGENTFLOW.md");
154
- if (existsSync2(workflowPath) && !isGeneratedWorkflow(workflowPath)) {
155
- throw new Error("AGENTFLOW.md is not managed by AgentFlow CLI. Move it or merge it manually before continuing.");
191
+ const config = readSetupConfig(cwd);
192
+ const legacyInstall = !config && isGeneratedWorkflow(workflowPath);
193
+ const installing = command === "init" || !config && !legacyInstall;
194
+ const assumeDefaults = forwarded.includes("--yes") || forwarded.includes("-y");
195
+ const components = installing ? assumeDefaults ? [...SETUP_COMPONENTS] : await selectSetup() : config?.components ?? ["skills", "workflow"];
196
+ if (!components) {
197
+ return 0;
156
198
  }
157
- if (command === "update" && !existsSync2(workflowPath)) {
158
- throw new Error("AgentFlow is not initialized here. Run `agentflow init`.");
199
+ if (components.includes("workflow") && existsSync2(workflowPath) && !isGeneratedWorkflow(workflowPath)) {
200
+ throw new Error("AGENTFLOW.md is not managed by AgentFlow CLI. Move it or merge it manually before continuing.");
159
201
  }
160
- const skillsArgs = command === "init" ? ["add", SKILLS_SOURCE, "--skill", "*", ...forwarded] : ["update", ...AGENTFLOW_SKILLS, ...forwarded];
161
- const status = executeSkills(skillsArgs);
162
- if (status !== 0) {
163
- stderr.write(`Agent skills ${command} failed with exit code ${status}.
202
+ if (components.includes("skills")) {
203
+ const installOptions = forwarded.filter((option) => option !== "--project" && option !== "-p");
204
+ const skillsArgs = installing ? [
205
+ "add",
206
+ SKILLS_SOURCE,
207
+ ...assumeDefaults ? ["--skill", "*"] : [],
208
+ ...installOptions
209
+ ] : ["update", ...AGENTFLOW_SKILLS, ...forwarded];
210
+ const status = executeSkills(skillsArgs);
211
+ if (status !== 0) {
212
+ const operation = installing ? "install" : "update";
213
+ stderr.write(`Agent skills ${operation} failed with exit code ${status}.
164
214
  `);
165
- return status;
215
+ return status;
216
+ }
217
+ }
218
+ if (components.includes("workflow")) {
219
+ writeAtomically(workflowPath, generatedWorkflow(workflow));
166
220
  }
167
- writeAtomically(workflowPath, generatedWorkflow(workflow));
168
- ensureIgnored(cwd);
169
- if (command === "init") {
221
+ if (components.includes("agents")) {
222
+ ensureAgentsPointer(cwd);
223
+ }
224
+ writeSetupConfig(cwd, components);
225
+ if (installing) {
170
226
  stdout.write(`AgentFlow initialized.
171
-
172
- Add this line to AGENTS.md:
173
-
174
- ${AGENTS_SNIPPET}
175
227
  `);
176
228
  } else {
177
229
  stdout.write(`AgentFlow updated.
@@ -186,4 +238,4 @@ ${AGENTS_SNIPPET}
186
238
  }
187
239
 
188
240
  // src/bin.ts
189
- process.exitCode = runCli(process.argv.slice(2));
241
+ process.exitCode = await runCli(process.argv.slice(2));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reforma/agentflow",
3
- "version": "0.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "An opinionated workflow for shipping production-ready changes with coding agents.",
5
5
  "author": "Reforma, Inc. <dev@reforma.ai>",
6
6
  "type": "module",
@@ -10,11 +10,13 @@
10
10
  "files": [
11
11
  "bin",
12
12
  "skills",
13
+ "AGENTFLOW.md",
13
14
  "README.md",
14
15
  "LICENSE"
15
16
  ],
16
17
  "scripts": {
17
- "build": "bun build src/bin.ts --target=node --outfile=bin/agentflow.js --external skills",
18
+ "prepare": "node -e \"if (process.env.CI === 'true' || process.env.SKIP_GIT_HOOKS === '1') process.exit(0); require('child_process').execSync('bunx simple-git-hooks', {stdio:'inherit'})\"",
19
+ "build": "bun build src/bin.ts --target=node --outfile=bin/agentflow.js --external skills --external @clack/prompts",
18
20
  "typecheck": "tsc --noEmit",
19
21
  "changeset": "bunx @changesets/cli",
20
22
  "version-packages": "bunx @changesets/cli version",
@@ -23,6 +25,9 @@
23
25
  "validate:skills": "gh skill publish --dry-run",
24
26
  "prepublishOnly": "bun run typecheck && bun run test && bun run build"
25
27
  },
28
+ "simple-git-hooks": {
29
+ "commit-msg": "bunx --no-install commitlint --edit \"$1\""
30
+ },
26
31
  "repository": {
27
32
  "type": "git",
28
33
  "url": "git+https://github.com/reforma-dev/agentflow.git"
@@ -44,12 +49,69 @@
44
49
  "access": "public"
45
50
  },
46
51
  "dependencies": {
52
+ "@clack/prompts": "1.7.0",
47
53
  "skills": "1.5.23"
48
54
  },
49
55
  "devDependencies": {
50
56
  "@changesets/cli": "3.0.1",
57
+ "@commitlint/cli": "21.2.2",
58
+ "@commitlint/config-conventional": "21.2.2",
51
59
  "@types/bun": "1.4.0",
52
60
  "@types/node": "26.4.0",
61
+ "simple-git-hooks": "2.14.0",
53
62
  "typescript": "7.0.2"
63
+ },
64
+ "commitlint": {
65
+ "extends": [
66
+ "@commitlint/config-conventional"
67
+ ],
68
+ "rules": {
69
+ "type-enum": [
70
+ 2,
71
+ "always",
72
+ [
73
+ "feat",
74
+ "fix",
75
+ "chore",
76
+ "refactor",
77
+ "docs",
78
+ "test",
79
+ "ci",
80
+ "perf",
81
+ "revert"
82
+ ]
83
+ ],
84
+ "type-case": [
85
+ 2,
86
+ "always",
87
+ "lower-case"
88
+ ],
89
+ "type-empty": [
90
+ 2,
91
+ "never"
92
+ ],
93
+ "subject-empty": [
94
+ 2,
95
+ "never"
96
+ ],
97
+ "subject-min-length": [
98
+ 1,
99
+ "always",
100
+ 4
101
+ ],
102
+ "body-max-line-length": [
103
+ 1,
104
+ "always",
105
+ 250
106
+ ],
107
+ "subject-case": [
108
+ 2,
109
+ "never",
110
+ [
111
+ "pascal-case",
112
+ "upper-case"
113
+ ]
114
+ ]
115
+ }
54
116
  }
55
117
  }
@@ -26,6 +26,10 @@ plan.
26
26
  ```markdown
27
27
  # <Feature>
28
28
 
29
+ > Keep this plan current during implementation.
30
+ > Check a PR only after its done-when and verification pass.
31
+ > Record scope changes before leaving the PR.
32
+
29
33
  **Goal:** one sentence
30
34
  **Approach:** 2–3 sentences — the chosen reading
31
35
  **Reuse:** existing APIs this plan calls (`path`)