ww-agentic-workflows 1.0.0.dev3__py3-none-any.whl

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.
Files changed (167) hide show
  1. ww/__init__.py +18 -0
  2. ww/_bundled_extensions/ww/git/extension.py +1728 -0
  3. ww/action_execution.py +887 -0
  4. ww/actions/__init__.py +94 -0
  5. ww/actions/command.py +444 -0
  6. ww/actions/contracts.py +699 -0
  7. ww/actions/extension.py +197 -0
  8. ww/actions/mcp.py +84 -0
  9. ww/actions/prompt.py +74 -0
  10. ww/actions/skill.py +62 -0
  11. ww/actions/slash_command.py +63 -0
  12. ww/agents.py +151 -0
  13. ww/amendments.py +54 -0
  14. ww/artifacts.py +93 -0
  15. ww/assessments.py +181 -0
  16. ww/assets/__init__.py +2 -0
  17. ww/assets/agent_instructions.md +49 -0
  18. ww/assets/docs/examples.md +879 -0
  19. ww/assets/docs/features.md +4639 -0
  20. ww/assets/docs/specification.md +1876 -0
  21. ww/assets/noww_skill.md +11 -0
  22. ww/assets/workflows/catchall.yaml +26 -0
  23. ww/assets/workflows/onboarding.yaml +586 -0
  24. ww/assets/workflows/scriptize.yaml +130 -0
  25. ww/assets/ww-automate_skill.md +23 -0
  26. ww/assets/ww-deduce-feedback_skill.md +38 -0
  27. ww/assets/ww-feedback-rules_skill.md +48 -0
  28. ww/assets/ww-learn-project_skill.md +22 -0
  29. ww/assets/ww-refresh_skill.md +26 -0
  30. ww/assets/ww-rule_skill.md +83 -0
  31. ww/assets/ww-rules-from-artifacts_skill.md +22 -0
  32. ww/assets/ww-scriptize_skill.md +33 -0
  33. ww/assets/ww-setup_skill.md +94 -0
  34. ww/assets/ww-solve_skill.md +23 -0
  35. ww/assets/ww-suggest_skill.md +32 -0
  36. ww/assets/ww-wizard_skill.md +105 -0
  37. ww/assets/ww_skill.md +59 -0
  38. ww/assignments.py +283 -0
  39. ww/bootstrap.py +405 -0
  40. ww/builtin_workflows.py +215 -0
  41. ww/changes.py +225 -0
  42. ww/child_coordination.py +482 -0
  43. ww/children.py +106 -0
  44. ww/claude_permissions.py +115 -0
  45. ww/cli/__init__.py +7 -0
  46. ww/cli/__main__.py +6 -0
  47. ww/cli/audit.py +129 -0
  48. ww/cli/catalogs.py +131 -0
  49. ww/cli/discover.py +607 -0
  50. ww/cli/initialization.py +898 -0
  51. ww/cli/lookup.py +287 -0
  52. ww/cli/main.py +1768 -0
  53. ww/cli/parser.py +1200 -0
  54. ww/cli/prompts.py +217 -0
  55. ww/cli/updates.py +117 -0
  56. ww/completion_artifacts.py +156 -0
  57. ww/completion_inputs.py +39 -0
  58. ww/config/__init__.py +582 -0
  59. ww/config/actions.py +591 -0
  60. ww/config/composition.py +571 -0
  61. ww/config/rules.py +511 -0
  62. ww/config/steps.py +1220 -0
  63. ww/config/values.py +223 -0
  64. ww/config_files.py +191 -0
  65. ww/config_writes.py +264 -0
  66. ww/contracts.py +155 -0
  67. ww/control.py +41 -0
  68. ww/defaults.py +130 -0
  69. ww/design_docs.py +32 -0
  70. ww/discovery.py +104 -0
  71. ww/documents.py +217 -0
  72. ww/errors.py +18 -0
  73. ww/executable.py +43 -0
  74. ww/execution_models/__init__.py +64 -0
  75. ww/execution_models/construction.py +148 -0
  76. ww/execution_models/decoding.py +38 -0
  77. ww/execution_models/plan_codec.py +565 -0
  78. ww/execution_models/records.py +1206 -0
  79. ww/execution_models/runs.py +266 -0
  80. ww/extensions/__init__.py +40 -0
  81. ww/extensions/api.py +559 -0
  82. ww/extensions/registry.py +864 -0
  83. ww/extensions/store.py +78 -0
  84. ww/feedback.py +342 -0
  85. ww/handler_repairs.py +57 -0
  86. ww/hooks/__init__.py +40 -0
  87. ww/hooks/agents.py +380 -0
  88. ww/hooks/install.py +168 -0
  89. ww/hooks/notices.py +206 -0
  90. ww/hooks/records.py +209 -0
  91. ww/hooks/runtime.py +266 -0
  92. ww/hooks/transcripts.py +183 -0
  93. ww/inspect.py +896 -0
  94. ww/instructions/__init__.py +17 -0
  95. ww/instructions/builder.py +1682 -0
  96. ww/instructions/commands.py +335 -0
  97. ww/instructions/handoff.py +149 -0
  98. ww/instructions/models.py +686 -0
  99. ww/instructions/policy.py +219 -0
  100. ww/instructions/text.py +168 -0
  101. ww/interactions.py +187 -0
  102. ww/interpolation.py +37 -0
  103. ww/item_passes.py +167 -0
  104. ww/items.py +99 -0
  105. ww/locking.py +207 -0
  106. ww/metadata_publication.py +230 -0
  107. ww/onboarding.py +229 -0
  108. ww/open_work.py +236 -0
  109. ww/operations.py +193 -0
  110. ww/operator_ui/__init__.py +16 -0
  111. ww/operator_ui/page.html +351 -0
  112. ww/operator_ui/server.py +215 -0
  113. ww/operator_ui/session.py +389 -0
  114. ww/operator_ui/sheet.py +104 -0
  115. ww/operator_ui/view.py +109 -0
  116. ww/output.py +339 -0
  117. ww/output_adapters/__init__.py +12 -0
  118. ww/output_adapters/base.py +25 -0
  119. ww/output_adapters/json_adapter.py +37 -0
  120. ww/output_adapters/markdown.py +2293 -0
  121. ww/output_adapters/rule_pages.py +337 -0
  122. ww/output_adapters/terminal.py +21 -0
  123. ww/package_updates.py +167 -0
  124. ww/plan/__init__.py +38 -0
  125. ww/plan/actions.py +207 -0
  126. ww/plan/compiler.py +1492 -0
  127. ww/plan/constructs.py +456 -0
  128. ww/plan/models.py +665 -0
  129. ww/project_config.py +752 -0
  130. ww/recovery.py +401 -0
  131. ww/replanning.py +367 -0
  132. ww/results.py +77 -0
  133. ww/rule_checks.py +230 -0
  134. ww/rule_conversion.py +331 -0
  135. ww/rule_disputes.py +148 -0
  136. ww/rule_store.py +456 -0
  137. ww/rule_verification.py +714 -0
  138. ww/rule_views.py +447 -0
  139. ww/rule_writes.py +920 -0
  140. ww/run_coordination.py +158 -0
  141. ww/runtimes.py +105 -0
  142. ww/service.py +4405 -0
  143. ww/setup_apply.py +428 -0
  144. ww/step_values.py +20 -0
  145. ww/storage.py +447 -0
  146. ww/storage_adapters/__init__.py +36 -0
  147. ww/storage_adapters/base.py +540 -0
  148. ww/storage_adapters/filesystem.py +370 -0
  149. ww/storage_adapters/memory.py +195 -0
  150. ww/storage_adapters/project_metadata.py +69 -0
  151. ww/storage_adapters/task_document.py +484 -0
  152. ww/task_ids.py +114 -0
  153. ww/task_references.py +124 -0
  154. ww/transitions.py +1619 -0
  155. ww/updates.py +399 -0
  156. ww/upgrade.py +95 -0
  157. ww/validation.py +168 -0
  158. ww/variables.py +275 -0
  159. ww/workflow_config.py +854 -0
  160. ww/workflow_update.py +239 -0
  161. ww/workflow_validation.py +1260 -0
  162. ww/workspace.py +50 -0
  163. ww_agentic_workflows-1.0.0.dev3.dist-info/METADATA +690 -0
  164. ww_agentic_workflows-1.0.0.dev3.dist-info/RECORD +167 -0
  165. ww_agentic_workflows-1.0.0.dev3.dist-info/WHEEL +4 -0
  166. ww_agentic_workflows-1.0.0.dev3.dist-info/entry_points.txt +2 -0
  167. ww_agentic_workflows-1.0.0.dev3.dist-info/licenses/LICENSE +674 -0
@@ -0,0 +1,4639 @@
1
+ # ww feature reference
2
+
3
+ This document is the design guide and feature reference for
4
+ `ww-agentic-workflows`. It is one of three authorities for designing workflows:
5
+ the [specification](specification.md) says exactly what the syntax, defaults and
6
+ failure semantics are, this guide says when to use what and why, and the
7
+ [examples](examples.md) are runnable. Start with [Designing a
8
+ workflow](#designing-a-workflow). For a short introduction, see
9
+ [README.md](../README.md); for internal design, component boundaries, and
10
+ persistence invariants, see [architecture.md](architecture.md).
11
+
12
+ An installation carries the same-version copies of all three: read them with
13
+ `ww docs specification`, `ww docs features` and `ww docs examples`.
14
+
15
+ ## Feature overview
16
+
17
+ - Read-only validation of `ww.yaml`, plus agent-specific workflow
18
+ planning in Markdown or JSON.
19
+ - A `ww.yaml` split across imported files, composed in memory.
20
+ - User, repo, and local configuration levels, resolved automatically, above
21
+ the workflows ww ships itself.
22
+ - A read-only profile of the checkout (`inspect`): branches, activity, fix
23
+ signals, hot paths, manifests and verify commands, and conventions.
24
+ - Onboarding state, and setup fragments that ww validates and places in the
25
+ shared or local configuration after asking.
26
+ - Built-in learning and setup workflows, started by the `ww-setup` skills:
27
+ ww learns about the operator, team, company and project, designs a setup
28
+ with the operator, and proposes it in full.
29
+ - An implicit, reserved `init` step that preserves task requirements.
30
+ - Resumable task execution from immutable plan snapshots.
31
+ - Agent-owned prompts, skills, slash commands, profiles, and MCP calls.
32
+ - ww-owned CLI handlers, output assertions, and lifecycle transitions.
33
+ - Global, workflow, and step hooks with filters and conditional prompts.
34
+ - Rules delivered on each step's page, and checks ww runs on the files a step
35
+ changed, which send the step back to its worker until they pass.
36
+ - Variables, durable task and project metadata, artifacts, and artifact
37
+ dependencies.
38
+ - Nested steps, dynamic per-item work, and parent/child task workflows.
39
+ - Sequential workflow runs and terminal handoffs between workflows.
40
+ - Configurable runtimes, models, reasoning levels, and modes.
41
+ - Per-step and per-handler working directories: the task workspace, the
42
+ project checkout, or the project root.
43
+ - Explicit manager/worker assignment handoff with durable continuation state.
44
+ - Qualified extensions, including bundled Git branch, worktree, and commit
45
+ automation.
46
+ - Atomic persistence, task-level concurrency control, interruption recovery,
47
+ execution logs, and lock cleanup.
48
+
49
+ ## Designing a workflow
50
+
51
+ Start with the smallest workflow that does the job and add structure only for a
52
+ concrete reason. This section is the guidance; the
53
+ [specification](specification.md) has the exact syntax and the
54
+ [examples](examples.md) have runnable versions of everything named here.
55
+
56
+ ### Start linear
57
+
58
+ A workflow is a list of steps in order. Write the work as steps, give them the
59
+ defaults, and stop there until something real asks for more. Items, several
60
+ item passes, loops, assessments, persistence, modes and reusable groups each
61
+ cost the reader something, so each needs a concrete reason: the work really
62
+ splits into independent pieces, a judgment really routes what follows, the
63
+ same list really returns every round, a preference really varies per task.
64
+ When `items: ~` is enough, do not write item stages; when one pass is enough,
65
+ do not add a second. [Example 1](examples.md#1-a-linear-workflow-with-an-automatic-check)
66
+ is a complete workflow.
67
+
68
+ ### Steps, handlers and hooks
69
+
70
+ - An **ordinary step** is the place for anything the workflow visibly does,
71
+ including a command ww runs itself (`argv` or `shell`). It appears in the
72
+ plan, in `status` and in the artifacts, it can fail and be repaired
73
+ (`on_failure: fix`), and readers find it where the work happens. Verifying a
74
+ change is such an operation: write it as a step, after the step that
75
+ changes the code.
76
+ - A **handler** is a named definition worth reusing: the same command in
77
+ several workflows, a reusable group of automatic commands, a loop used
78
+ by several workflows. Define one when the second use appears, not before. A step uses it
79
+ with `handler: <name>`.
80
+ - A **hook** attaches work to a lifecycle point of steps or workflows
81
+ without appearing as a step: it exists for invariants, things that must
82
+ hold around every matching step or workflow whatever the steps say, such as a
83
+ clean tree before any task starts or a commit when a workflow completes, or
84
+ a check that must pass whenever a code-changing step completes
85
+ (`before_complete` with `on_failure: fix`). A command being automatic does
86
+ not make it a hook, and putting visible operations in hooks hides the
87
+ workflow from the people who read it.
88
+
89
+ ### Conversation or assessment
90
+
91
+ Both involve a judgment but they belong to different people. An
92
+ **interactive step** is a conversation with the operator: discussing a design,
93
+ reviewing a change, performing a manual test. The operator talks and decides;
94
+ the step ends when their intent is clear, and `choices` only lists the answers
95
+ worth offering (`{{ww.choices}}` shows their labels in the instruction; it
96
+ guides, it never validates). An **assessment** (`assess`) is the agent's own
97
+ evaluation: it looks at the evidence, picks `positive`, `negative` or `mixed`
98
+ (or a label you declare) and the workflow routes on that. Use an assessment
99
+ to gate or branch on something the agent can decide; use an interactive step
100
+ where the operator's say matters. Prefer the compact and standard-branch
101
+ forms, and custom labels in `outcomes` only when positive and negative do not
102
+ say it.
103
+
104
+ ### Items: independent pieces of work
105
+
106
+ Use `items` when the work splits into pieces that are independently
107
+ completed, checked or reported: review comments, test cases, files to migrate.
108
+ `items: ~` gives every item one stage that analyzes, resolves and reports it.
109
+ Choose per-item stages (`items.steps`) only when the stages differ. When
110
+ several pieces are cheaper analyzed or fixed together but each still has to be
111
+ reported on its own, use a shared analysis or fix with one item per
112
+ independently reportable source: the workflow has one collection and several
113
+ passes over it, and ordinary steps between the passes run once for everyone
114
+ ([Several passes over the same items](#several-passes-over-the-same-items),
115
+ [example 4](examples.md#4-one-analysis-one-fix-one-report-per-comment)).
116
+ Make the item the unit that is reported: one item per source comment, even
117
+ when a hundred comments get one fix.
118
+
119
+ ### External items: IDs, reconciliation and restarts
120
+
121
+ When items mirror something outside ww, such as review comments on a pull
122
+ request, design for being run again:
123
+
124
+ - Give each item the source's own stable ID, as the item ID or in a field
125
+ that `identity` requires and `unique` keeps single. A rerun then recognizes
126
+ its comments instead of creating copies.
127
+ - Declare `persistent: true` when the same list returns every round. The
128
+ collection step then reconciles the stored items against the source
129
+ (`add-item`, `update-item --text`, `remove-item`) instead of splitting
130
+ again. Identity, text, references and custom fields carry over to the next
131
+ run; analysis, solution, `resolved` and `reported` start clear.
132
+ - Keep remote results in item fields, such as the reply ID. Pass the saved
133
+ value to the command that posts, `"{{ww.item.field.reply_id}}"`, so a
134
+ project-owned script can update the reply it already made instead of
135
+ creating another. A per-item command stage that declares
136
+ `saves: item.field.reply_id` stores the command's whole trimmed output
137
+ there, and the last report-stage item is marked `reported` in the same
138
+ commit, only after a zero exit.
139
+ - ww makes no exactly-once promise about remote effects. If the process dies
140
+ after a remote reply but before the result is saved, the next attempt runs
141
+ the command again. The handler or script owns idempotency, which is why it
142
+ takes the saved ID.
143
+ - `next --retry` after a failed stage, or `start --fresh-items` to forget the
144
+ stored list, are the restart tools; see
145
+ [Items that persist across runs](#items-that-persist-across-runs).
146
+
147
+ ### What needs the agent and what ww does itself
148
+
149
+ A shell or argv step runs without agent work. Values ww owns, such as
150
+ `{{ww.task.id}}`, `{{ww.git.branch}}` and `{{ww.item.field.<name>}}`, are
151
+ read by ww when the command runs, so using them never asks the agent for
152
+ anything. Only a required agent variable, a `variables` entry of the
153
+ `name: description` form, means input is needed: the agent supplies it with
154
+ `complete --variable`, and then ww runs the command. Dynamic values go to
155
+ commands as `args`, `env` or `argv` entries, never into shell source.
156
+
157
+ ### Modes and rules
158
+
159
+ Add a mode only for a preference that changes how an agent works, such as
160
+ brief updates or asking first, and a rule only for a convention no command
161
+ checks, on the steps it governs, with a one-line check where one exists. A
162
+ rule never restates its step, a preference or a command, and a step that
163
+ needs none gets none. Never redefine a workflow ww ships (`catchall`, `ww-*`).
164
+
165
+ ### Where to put workflows
166
+
167
+ Personal defaults belong in your global file, the team's in the project's
168
+ `ww.yaml`, and your own variation of a project workflow in `ww.local.yaml`; a
169
+ lower level replaces a same-named definition. `discover` names each
170
+ workflow's source, and where several fit, prefer local over project over
171
+ global unless the operator named one
172
+ ([example 6](examples.md#6-global-project-and-local-variants)).
173
+
174
+ ## Development package snapshots
175
+
176
+ Pushes to this repository's `dev` branch publish `1.0.0.devN` snapshots to PyPI
177
+ after the release gates pass and the final distribution files are validated.
178
+ Snapshots identify unreleased work; they do not create Git tags or GitHub
179
+ releases. Install an exact build, for example:
180
+
181
+ ```console
182
+ pip install ww-agentic-workflows==1.0.0.dev42
183
+ ```
184
+
185
+ Publishing requires the one-time Trusted Publisher setup described in
186
+ [development releases](development-releases.md). That guide also covers the
187
+ run-number sequence, retry behavior and opting into the latest snapshot.
188
+
189
+ ## Initialize a project
190
+
191
+ `ww-agentic-workflows init` is additive and safe to run after a partial checkout
192
+ or branch switch. It creates only missing files and root configuration keys,
193
+ preserves existing content, restores `.ww/tasks`, and reports created and
194
+ preserved parts. `--json` and `--no-input` use deterministic defaults for
195
+ automation.
196
+
197
+ The interactive wizard chooses UUID, numeric, or timestamp task IDs, written as
198
+ `task_format: "TASK-{{uuid}}"`, `"TASK-{{digit}}"`, or `"TASK-{{timestamp}}"`. When the
199
+ project contains `.git/`, it enables `ww/git`, prefers an existing `master`
200
+ branch and then `main`, enables separate task branches, and starts with
201
+ `feature/{{ww.task.id}}`. It asks for optional workflow-specific branch formats and
202
+ whether worktrees should be used. Enabled worktrees default to
203
+ `./git-worktrees/{{ww.task.id}}`, and the directory is created immediately.
204
+
205
+ The settings file init writes holds every root-level setting with its value,
206
+ so each option can be found and changed in place; the answers replace the
207
+ defaults. Without Git, and with the uuid format:
208
+
209
+ ```json
210
+ {
211
+ "enabled": true,
212
+ "runtime": "single",
213
+ "update_check": true,
214
+ "executable": "ww-agentic-workflows",
215
+ "task_format": "TASK-{{uuid}}",
216
+ "limits": {
217
+ "rounds": 3,
218
+ "fixes": 3
219
+ },
220
+ "agent_hooks": {
221
+ "check_unfinished": true,
222
+ "recent_days": 3
223
+ },
224
+ "rules": {},
225
+ "builtins": {
226
+ "init": {
227
+ "model": "cheapest",
228
+ "reasoning": "low"
229
+ },
230
+ "workflow_summary": {
231
+ "model": "auto",
232
+ "reasoning": "auto"
233
+ }
234
+ },
235
+ "workflows": {},
236
+ "projects": [],
237
+ "extensions": {}
238
+ }
239
+ ```
240
+
241
+ In an existing file init adds the keys that are missing, nested ones
242
+ included, with these defaults and keeps every value already there. A key
243
+ init does not ask about (`runtime`, `update_check`, `limits`, `agent_hooks`,
244
+ `rules`, `builtins`, `workflows`, `projects`) that the user or local settings file
245
+ already sets is not written, so a default in the repo file never hides it.
246
+
247
+ The wizard offers to keep `.ww` out of Git; without consent it only reports
248
+ that action. With consent it appends these lines to `.gitignore`:
249
+
250
+ ```gitignore
251
+ .ww/*
252
+ !.ww/project.md
253
+ ```
254
+
255
+ Everything under `.ww` is one checkout's state, except `project.md`, in which
256
+ ww records what it learned about the project: it is meant to be committed and
257
+ shared. Git cannot re-include a file inside
258
+ an ignored directory, which is why the directory's contents are ignored rather
259
+ than the directory. A line that ignores the directory whole, as `.ww/`, `.ww`,
260
+ `/.ww` or `/.ww/`, would keep the
261
+ shared files out too, so every such line is replaced by these lines, written
262
+ once where the first one stood. A `.ww/*` line gains the re-inclusions it
263
+ lacks, right after it; a re-inclusion only counts after the last `.ww/*` line,
264
+ since a later one ignores the file again. Every other line is left alone, and
265
+ the file keeps its line endings (CRLF stays CRLF).
266
+ The patterns `*ww.local.yaml`,
267
+ `*ww.local.json` and `ww-setup.local.yaml` are added without
268
+ asking, since [local configuration](#user-repo-and-local-configuration) belongs
269
+ to one checkout:
270
+ they are appended to an existing `.gitignore` once, never duplicated, and a
271
+ missing `.gitignore` is created for them only inside a Git repository. It also reports missing `@WW_AGENT_INSTRUCTIONS.md`
272
+ references in `AGENTS.md` and an existing `CLAUDE.md`, and reminds the user to
273
+ define workflows when the initialized `ww.yaml` is empty. Equivalent
274
+ non-interactive choices are available through `--task-format`, `--worktrees`,
275
+ `--worktree-dir`, repeated `--branch-format WORKFLOW=FORMAT`,
276
+ `--update-gitignore`, and `--skills`.
277
+
278
+ For every agent directory it finds, such as `.claude/` or `.codex/`, the wizard
279
+ offers to install the shipped skills at `<directory>/skills/<name>/SKILL.md`.
280
+ The `ww` skill lets a user ask explicitly to work through ww: it tells the
281
+ agent to run `discover` and follow ww from there. The `noww` skill is the way
282
+ out: invoked as `/noww`, it tells the agent not to use ww for the rest of the
283
+ conversation, `catchall` included. The `ww-rule` skill writes rules for ww's
284
+ steps from the operator's words; see [Writing rules with the ww-rule
285
+ skill](#writing-rules-with-the-ww-rule-skill). `--skills` installs them all
286
+ everywhere without asking and `--no-skills` skips them; an existing skill file is never
287
+ overwritten, and a skill a later ww version bundles is offered once on its
288
+ own, as described in [Installing the ww skills during
289
+ init](#installing-the-ww-skills-during-init).
290
+
291
+ For every hook-capable agent whose directory exists (Claude Code, Codex,
292
+ Cursor, Antigravity), init also offers ww's [agent hooks](#agent-hooks), once
293
+ per agent, and remembers the answer in `.ww/init-choices.json`. `--hooks`
294
+ installs them for all of those agents without asking and `--no-hooks` skips
295
+ them; without either flag or a saved answer, a non-interactive init leaves
296
+ hooks alone. A hook installation that fails, for example because the agent's
297
+ hooks file is not valid JSON, never fails init: the summary names the file and
298
+ prints the snippet to add by hand.
299
+
300
+ When Claude Code is set up (a `.claude` directory exists), init also asks, as an
301
+ opt-in question whose default is no, whether to write Bash allow rules for
302
+ ww's role commands into `.claude/settings.local.json`: the project wrapper's
303
+ absolute path (never a bare `ww`) followed by `instruction *`, `next *`,
304
+ `complete *`, `fail *`, `dispute *`, `check *`, `status *`, `artifacts *`,
305
+ `items *`, `item *`, `add-item *`, `update-item *`, `interact *`, `loop *`,
306
+ `lookup *`, `discover*` and `requirements *`. The file is created or merged
307
+ (every other key and rule stays as it was), `.gitignore` gets a line for it
308
+ unless Git already ignores it, and an unreadable file is left untouched with the
309
+ rules printed to add by hand. `--permissions` answers yes without asking and
310
+ `--no-permissions` no; a saved answer is reused, and `--force` asks again.
311
+ Without a terminal or a flag, nothing is written.
312
+
313
+ `init` also creates the [user configuration
314
+ directory](#user-repo-and-local-configuration) when it is missing, and lists it
315
+ under "Created or restored".
316
+
317
+ `init --force` runs every question again, ignoring the answers remembered in
318
+ `.ww/init-choices.json`, so agents, skills and hooks can be chosen anew and
319
+ more added. It only adds: skills, instruction references, hooks, `.gitignore`
320
+ lines and settings keys already in place are kept, never removed and never
321
+ written twice, and the new answers replace the remembered ones. Values the
322
+ settings files already hold, such as `enabled` or `task_format`, are
323
+ configuration rather than remembered answers, so they are not asked again.
324
+ `--force` reopens a question only when it can ask it: with `--no-input`, or
325
+ without a terminal, every remembered answer stands, a remembered "no"
326
+ included, and init only adds what those answers leave missing. A flag such as
327
+ `--update-gitignore` still decides without asking.
328
+
329
+ `enabled` is written to `ww.json` only from the repo level's
330
+ own answer: when your user or local settings file already sets it, init
331
+ neither asks nor commits that choice for the team.
332
+
333
+ Unless it was shown before, the summary ends with what to allow so your agents
334
+ run ww without asking for confirmation. For each agent set up in the project
335
+ whose permission format ww knows, it names the file and the exact entries,
336
+ covering the configured `executable`, `./ww` and the `ww` shortcut. For Claude
337
+ Code:
338
+
339
+ ```text
340
+ claudecode: merge these entries into .claude/settings.json
341
+
342
+ {
343
+ "permissions": {
344
+ "allow": [
345
+ "Bash(ww-agentic-workflows *)",
346
+ "Bash(./ww *)",
347
+ "Bash(ww *)"
348
+ ]
349
+ }
350
+ }
351
+ ```
352
+
353
+ Other agents get the command prefixes to allow in their own permission
354
+ settings. The notice also says what you trust by doing so: your
355
+ `ww.yaml` with its user and local levels. `--force` shows it
356
+ again.
357
+
358
+ Every `init` ends with the next step: run the `ww-setup` skill, which sets ww
359
+ up for you, your team and this project (in Claude Code, `/ww-setup`).
360
+ `--json` output lists it under `next_steps`.
361
+
362
+ ### Configuration file names
363
+
364
+ ww reads its configuration from two files at the project root, both named
365
+ after the tool: `ww.yaml` for the workflows and
366
+ `ww.json` for the project settings.
367
+
368
+ ## Discover how to start a task
369
+
370
+ `discover` is the entry point for agents. The embeddable agent instructions stay
371
+ short and send agents here, so every choice comes from the project's current
372
+ configuration:
373
+
374
+ ```console
375
+ ./ww discover
376
+ ./ww discover --json
377
+ ```
378
+
379
+ The Markdown is deliberately short. It lists the project's workflows with
380
+ their descriptions and default modes, each labeled with the configuration
381
+ level and source it came from and sorted local, then project, then global
382
+ (stable within a level), under this instruction: choose a workflow matching
383
+ the request; when several fit, prefer local over project over global; honor an
384
+ explicitly requested workflow; if the choice is still unclear, ask the
385
+ operator. The preference is guidance, not an automatic selector:
386
+
387
+ ```markdown
388
+ - review — [local: ww.local.yaml] Review incoming PR feedback.
389
+ - develop — [project: ww.yaml] Implement and verify a change.
390
+ - generic-fix — [global: ~/.config/ww/ww.yaml] General bug-fix workflow.
391
+ ```
392
+
393
+ After the workflows come the changes no workflow covers (the `catchall`,
394
+ started through `lookup`), the configured projects when there are any, the
395
+ modes (an automatic mode with where it is always on), and a multiline start
396
+ synopsis in which square brackets denote optional arguments. The task ID is
397
+ `<task-id>` where the project requires one and `[<task-id>]` otherwise, with
398
+ the external-ticket guidance; `--project` and `--branch-strategy` appear only
399
+ when projects or branch strategies are configured, with their values. A few
400
+ lines explain what is not obvious: explicit modes replace the defaults,
401
+ automatic modes apply themselves, `auto` honours per-step worker requests while
402
+ `single` records them, and `--model` and `--reasoning` describe your own
403
+ session. It ends with the resume and status commands and one optional plan
404
+ preview. ww's own workflows are not listed there: it points at `ww workflows`,
405
+ the catalog of every workflow. Every unfinished task is listed under
406
+ "Unfinished tasks", newest first, in the `session-start` hook's format with any
407
+ interruption notice, and `unfinished_tasks` in the JSON carries each one's
408
+ `task_id`, `workflow`, `agent`, `step`, `item_status`, `workspace`,
409
+ `updated_at`, `resume` command and whether it is `interrupted`. The Rules
410
+ suggestion is not part of the Markdown; `rules_notice` in the JSON and the
411
+ first page of `start` carry it, see
412
+ [How a rule becomes a check](#how-a-rule-becomes-a-check). The JSON keeps every
413
+ field, including the built-in catalogs, the roles and the guidance texts, which
414
+ are the same concise texts the Markdown shows; `explicit_task_id` states
415
+ whether the project requires a task ID. `discover` is read-only and leaves no audit record.
416
+
417
+ In JSON, each workflow entry also carries `source` and `source_level`, naming
418
+ the winning YAML definition and whether it came from the global user config,
419
+ project config, or local config. Imported files keep the level of the config
420
+ that imported them. `null` for both fields means a contribution without a
421
+ configured definition, such as a built-in or the catch-all that no
422
+ configuration file defines; one that a file does define reports that file.
423
+
424
+ A task whose state ww cannot read, such as one written by a build with another
425
+ state schema, does not break `discover`. It is listed
426
+ under "Unreadable tasks" with the error, and `unreadable_tasks` in the JSON
427
+ carries each `task_id` and `reason`. Other tasks and new work are unaffected;
428
+ commands addressing that task keep failing with the same error, and whether to
429
+ repair, reset, or delete its directory is the operator's decision.
430
+
431
+ ```markdown
432
+ ## Unreadable tasks
433
+
434
+ - `TASK-20` — invalid task state .ww/tasks/TASK-20/state.json: unsupported plan snapshot schema: 3
435
+
436
+ Other tasks and new work are unaffected. Commands addressing these tasks fail with the error shown; ask the operator, whose choice it is to repair, reset, or delete each task directory.
437
+ ```
438
+
439
+ Set `"runtime": "auto"` in `ww.json` to make `auto` the runtime
440
+ `start` uses when `--runtime` is omitted; `discover` then marks it as the
441
+ default. The setting lives in the JSON file because whether delegation is
442
+ available depends on the environment ww runs in, not on the workflows. A
443
+ workflow that only makes sense one way, such as a manual-testing workflow
444
+ whose every step is a conversation with the operator, may declare
445
+ `runtime: single` itself; that outranks the project default, and the flag on
446
+ the command line still wins over both.
447
+
448
+ Set `"enabled": false` in `ww.json` to switch ww off for a
449
+ project. `discover` then says only that ww is disabled and that the agent must
450
+ not use it, and `start` refuses to create a task.
451
+
452
+ Set `"enabled": "on_request"` to keep ww available but out of the way: an
453
+ agent uses it only when the user explicitly asks for it (says to use ww, names
454
+ a ww task, or invokes the `ww` skill), and otherwise works without ww and
455
+ without asking. `discover` opens with that rule, then lists the workflows so
456
+ an explicit request can proceed, and its JSON carries `"enabled":
457
+ "on_request"`. `start` and `lookup` work as usual, `lookup` reminding the agent
458
+ to go on only for an explicit request, and the `session-start` hook says that
459
+ ww is used here on request only. The static agent instructions and the `ww`
460
+ skill defer to `discover` for this choice. `init` asks which of the three
461
+ values to write, explaining each; without a terminal it writes `true`.
462
+
463
+ ```json
464
+ {"enabled": false, "extensions": {}}
465
+ ```
466
+
467
+ ## Onboarding state
468
+
469
+ ww keeps a little state about how far it is set up, each part where it
470
+ belongs:
471
+
472
+ | Key | Where | Means |
473
+ | --- | --- | --- |
474
+ | `explain` | `state.json` in the user configuration directory | whether the operator wants the agent to narrate what ww does while it learns; optional, absent until they say so |
475
+ | `setup.done` | `.ww/metadata.json`, as `ww.setup.done` | whether ww was set up in this project |
476
+ | `learned.project` | `.ww/metadata.json`, under `ww.learned` | when ww last learned about the project |
477
+
478
+ The project keys live in ww's own `ww.` namespace of project metadata, which
479
+ no workflow can save into, so they never collide with a workflow's values.
480
+
481
+ ```console
482
+ ./ww onboarding
483
+ ./ww onboarding --json
484
+ ./ww onboarding --set explain=true --set learned.project=now
485
+ ```
486
+
487
+ `--set` is repeatable and takes a known key: `explain=true|false`,
488
+ `setup.done=true|false`, `learned.project=now` or an ISO
489
+ timestamp. An unknown key or a malformed value is an error, and nothing is
490
+ written unless every assignment is valid. Setting records the operator's stated
491
+ preference, so it asks for no confirmation; it appears in the audit log, while
492
+ showing does not.
493
+
494
+ While `setup.done` is not recorded, `discover` adds a short "Onboarding"
495
+ notice: ww has not been set up in this project, setup is optional and never
496
+ blocks ordinary work, and the agent mentions the `ww-setup` skill only when the
497
+ operator asks to set ww up or what ww can do. It asks no question and starts
498
+ nothing. Its JSON carries `onboarding` with `setup_done`, `explain` and the
499
+ `guidance` lines. Under `"enabled": "on_request"` the notice only informs.
500
+
501
+ ## Apply a proposed setup
502
+
503
+ The setup skills propose configuration from what ww learned: workflows, modes,
504
+ handlers, hooks, rules, and settings. They never edit ww's configuration files
505
+ themselves; they write the proposal to a scratch file and hand it to ww:
506
+
507
+ ```console
508
+ ./ww setup apply proposal.yaml --for me --dry-run
509
+ ./ww setup apply proposal.yaml --for me --yes
510
+ ```
511
+
512
+ The file is a [setup fragment](specification.md#setup-fragments). `--for me`
513
+ places it in your local files, kept out of version control
514
+ (`ww-setup.local.yaml`, imported by `ww.local.yaml`, and
515
+ `ww.local.json`), so you can try it first; `--for team`
516
+ places it in the shared files (`ww-setup.yaml`, imported by
517
+ `ww.yaml`, and `ww.json`), committed with
518
+ the repository. Running it again refines the same setup file: definitions of
519
+ the same name are replaced, the rest kept, and a hook identical to one already
520
+ in its phase is skipped (the summary says so), so applying a fragment twice
521
+ adds nothing. The file is written as readable YAML, as a person would write
522
+ it: block style, a bare `- run-tests:` for a handler shorthand, long text
523
+ folded with `>-`, short lists such as `argv` inline, and a blank line between
524
+ sections and between workflows, so it can be reviewed and edited by hand.
525
+
526
+ ww first validates the fragment in memory: it loads the configuration as any
527
+ command would, reading the planned contents in place of the files they
528
+ change, so validating never touches the project and it only ever shows a
529
+ change that works. It then prints what it will write, file by file:
530
+
531
+ ```text
532
+ `ww setup apply --for team` writes for the team: files shared through the repository:
533
+ - ww-setup.yaml (new): adds workflow `review`, mode `gently`
534
+ - ww.yaml: adds ww-setup.yaml to imports
535
+ - ww.json: sets runtime
536
+ ```
537
+
538
+ and asks `Apply it? [y/N]` at a terminal. Without one, as in an agent's shell,
539
+ it needs `--yes`, given once the operator agreed; `--dry-run` prints the same
540
+ and writes nothing, and `--json` reports the files and changes for a program.
541
+ A setting that already holds a different value refuses the whole apply,
542
+ listing each conflict: ww never overwrites one. The files are written once,
543
+ after confirmation; a file that is a symbolic link is written through to its
544
+ target and keeps its permissions. When a write fails, ww puts back every file
545
+ it already wrote, removes its temporary file, and reports the error. Nothing
546
+ is committed.
547
+
548
+ `--dry-run --inspect <workflow> --agent <agent>` also compiles that workflow as
549
+ the change would leave it and prints its execution plan, so a draft can be
550
+ checked, in memory, before anything is asked or written: that automation is
551
+ ww-owned, that item scopes are valid, and that the operator meets only the
552
+ conversations intended.
553
+
554
+ ### Change a workflow that is already defined
555
+
556
+ `setup apply` adds definitions to ww's own setup files. To change a workflow
557
+ the configuration already defines, in its root `ww.yaml`, in a file it
558
+ imports, or at another level, write the complete changed workflow alone in a
559
+ fragment (`workflows` holding that one entry, named like the workflow) and
560
+ update it where it is written:
561
+
562
+ ```console
563
+ ./ww setup update review proposal.yaml --dry-run --inspect review --agent codex
564
+ ./ww setup update review proposal.yaml --level project --yes
565
+ ```
566
+
567
+ The definition that wins in the composed configuration is the one edited, and
568
+ the preview names its file and level. `--level local|project|global` selects
569
+ that level's definition instead, and ww refuses when a higher-precedence
570
+ definition hides it, because an edit there would report success and change
571
+ nothing; it tells which definition is in force. Only that list item's lines
572
+ are replaced, in ww's YAML style: the rest of the file, other definitions and
573
+ comments included, stays byte for byte. Comments inside the replaced entry
574
+ are lost, and the preview says so. ww checks that the file reloads as the old
575
+ data with exactly that entry swapped, validates the whole configuration in
576
+ memory, and checks that the workflow now comes from the file it wrote. The
577
+ preview is a diff; `--yes`, `--dry-run` and `--json` work as for `apply`. A
578
+ workflow only ww ships, or one defined nowhere, is refused: define or
579
+ override it with `setup apply`. Nothing is committed.
580
+
581
+ ## Inspect the project
582
+
583
+ `ww inspect` prints a read-only profile of the checkout: facts about how the
584
+ work is organised, each with the command or file it came from, or "not
585
+ found". It reads the working tree and the local Git history and nothing
586
+ else: no fetch, no network, nothing outside the checkout, and it writes no
587
+ file. It needs no `init`, so the setup workflows can run it on a fresh
588
+ project. `--json` prints the same profile as data, and `--commits N` reads
589
+ the last `N` commits instead of 300.
590
+
591
+ ```console
592
+ $ ./ww inspect
593
+ # Profile of shop
594
+
595
+ Read-only facts about this checkout; each names where it came from.
596
+
597
+ ## Repository
598
+
599
+ - Default branch: main (git symbolic-ref origin/HEAD)
600
+ - Integration branch: dev (merges on refs/remotes/origin/dev, git log --first-parent --merges)
601
+ - Branch patterns: feature/ 41, hotfix/ 6, release/ 3 (git branch -r, merge subjects)
602
+ - Merge commits: 22% (66 of 300 commits, git log -n 300)
603
+ ...
604
+
605
+ ## Fixes
606
+
607
+ - Fix share: 18% (42 of 234 non-merge commits, subject starts with fix, fixes, fixed, hotfix or revert, or names a regression, git log -n 300)
608
+ - Paths fixes touch: src/cart/totals.ts 9, src/cart/tax.ts 5, ... (paths the fix commits touch, git log -n 300 --numstat)
609
+ ...
610
+
611
+ ## Layout
612
+
613
+ - Manifests: package.json [12 scripts], apps/web/package.json [6 scripts] (root and two levels down, git ls-files)
614
+ - Verify commands: test: `pnpm run test` from package.json; lint: `pnpm run lint` from package.json (scripts and targets named test/lint/typecheck/check/format/build in the manifests)
615
+ ...
616
+
617
+ ## Conventions
618
+
619
+ - Ticket prefixes: SHOP 188, OPS 12 (git log -n 300; git branch -r, merge subjects)
620
+ - task_format candidate: `SHOP-{{digit}}` (the most frequent tracker key prefix)
621
+ - commit_format candidate: `{{ww.task.id}}: {{commit_message}}` (task ID first when half the subjects start with a key)
622
+ ...
623
+ ```
624
+
625
+ | Section | Facts |
626
+ | --- | --- |
627
+ | Repository | Default and integration branch, branch lanes (`feature/`, `hotfix/`, `release/`, …) with counts, remotes, shallow clone, share of merge commits and the merge style, pull request signals (template, `CODEOWNERS`, "Merge pull request" subjects), tags and the median days between the last ten. |
628
+ | Activity | Commits read, contributors and those active in 90 days, commits per week over the weeks the history spans (one to twelve, so a young history is not read as sparse), median files and lines per commit, median branch lifetime. Team shape: solo (one active contributor), small (2–5) or team (6+); cadence: daily (a median of five commits a week or more), weekly (one or more) or sparse. |
629
+ | Fixes | Share of non-merge commits whose subject starts with fix, fixes, fixed, hotfix or revert (after an optional tracker key, so `fix:` and `fix(scope):` count) or names a regression — "Add the fix loop" is not a fix; the five paths they touch most; the five most recent such subjects. |
630
+ | Hot paths | The ten most-changed files. |
631
+ | Layout | Manifests at the root and two levels down (`package.json`, `pyproject.toml`, `Makefile`, `composer.json`, `go.mod`, `Cargo.toml`, `Gemfile`, `pom.xml`, `build.gradle`), CI files, the verify commands as exact argv where a manifest names them (`package.json` and `composer.json` scripts, `Makefile` targets, `[tool.pytest]`, `[tool.ruff]` and `[tool.mypy]` in `pyproject.toml`), monorepo signals and the candidate `projects` they name. Sibling repositories a README links to are named, never read. |
632
+ | Conventions | Tracker key prefixes in subjects (upper case) and branch names (any case, so `hotfix/task-3` counts as `TASK`), with the `task_format` candidate; the share of subjects led by a key and of conventional-commit subjects, with the `commit_format` candidate; agent instruction files present. |
633
+
634
+ Outside a Git repository only the layout and the agent instruction files are
635
+ reported, under a line saying the Git facts are unavailable. An empty
636
+ repository, a shallow clone or one without remotes is reported as it is; a Git
637
+ call that fails or takes too long leaves only its own fact not found.
638
+
639
+ ## Setting ww up: learning and suggestions
640
+
641
+ ww can learn how the project works, and design a setup for the project with the
642
+ operator from that; it learns only the project, never who uses it. The
643
+ `ww-setup` skill guides the operator through it. `discover` mentions the skill
644
+ only when the operator asks to set ww up or what ww can do here, while
645
+ `setup.done` is not recorded (see [Onboarding state](#onboarding-state)). The
646
+ work itself is done by ww's own [built-in workflows](specification.md#built-in-workflows),
647
+ shipped as YAML and started like any workflow; each skill is a thin starter
648
+ for one of them.
649
+
650
+ | Skill | Workflow | Does |
651
+ | --- | --- | --- |
652
+ | `ww-setup` | — | The guide. Asks once, in its opening message, which path to take: Express (learn-project, then suggest told to derive defaults) or Guided (learn-project, then suggest, which asks a few process questions), and records `setup.done` at the end, also when everything is declined. Narration (`explain`) is never asked; it is recorded only when the operator says they want it. Once set up, it offers the ones below instead. |
653
+ | `ww-learn-project` | `ww-learn-project` | Learns the repository: what it is for, and how its work is organised. It reads an existing `project.md` first, so a rerun refreshes it. It starts from [`ww inspect`](#inspect-the-project)'s profile and reads only what the profile cannot see, such as what `AGENTS.md` allows and what the pull request template demands. First the setup facts, each with its evidence or "not found": the default and integration branches and the branch patterns in use, merge or rebase, required pull requests, the test, lint, type check, format and build commands as exact argument lists, how and where those commands run (on the host or through a container exec, virtual environment or task runner, given as an exact argument list, and whether each worktree has its own environment), the tracker's key format as a `task_format` candidate, the commit convention as a `commit_format` candidate, CI gates and releases, the workflows and conventions already in use, and what agents may already do. Then agent tooling, infrastructure and stack, other conventions, and recurring pitfalls, starting from the profile's fix commits and adding review comments where `gh`, `glab` or a tracker is signed in, each as a candidate rule with its evidence and, where a command could verify it, a check. `project.md` keeps the trimmed profile as its "Profile" section, above "Setup facts". Changes no project file but `project.md`. |
654
+ | `ww-suggest` | `ww-suggest` | Gathers the setup facts from `project.md`, running `ww inspect` when it has no profile, and reads the [specification](specification.md), this guide and the [examples](examples.md) for what a setup can be made of. In the guided path it asks a few process questions: what is painful, what outcome would help, where the operator wants to be involved and what may run automatically, skipping what the project already answers. Then it designs a minimal setup with the operator in one set of questions, proposes it in full, with the step features each kind of work calls for (an `items` step for cases, interactive steps and the operator page for what the operator performs, a document or item fields for a template such as a test case, a loop for work repeated until a condition holds), shows it with `setup apply --dry-run`'s list of changes, walks through a realistic task, and places it on confirmation; see below. It follows one method per proposed workflow: trigger, result and operator involvement; the smallest structure; concise YAML with a walkthrough and a failure path; validation with the compiled plan inspected; then apply. Commands come from repository evidence, never guessed. |
655
+ | `ww-refresh` | `ww-learn-project` | Runs the project learning again; see below. |
656
+ | `ww-wizard` | — | Shapes the setup with the operator: asks which of four branches (create a workflow, change an existing workflow, create or improve rules, choose an approach) unless the request says, adapts the depth of its questions, reads the `ww docs` sections, challenges needless complexity with a simpler alternative, drafts, validates with `--dry-run --inspect`, and places the change with `setup apply` or, for an existing workflow, `setup update` at the level `discover` reports. Rule work goes to the rules skills. |
657
+ | `ww-solve` | `ww-solve` | Listens to a problem, proposes the smallest change that addresses it, using the step features that fit the kind of work, and applies it for the operator or the team on confirmation. |
658
+ | `ww-rules-from-artifacts` | `ww-rules-from-artifacts` | Reads the artifacts of chosen steps across recent tasks and proposes rules from the lessons that recur, added with `rules add` on confirmation. |
659
+ | `ww-scriptize` | `ww-scriptize-rules` | Turns every rule with no check yet into checks for the whole project: collects the `unscriptized` rules and groups them into the fewest checks, agrees them with the operator in one conversation, builds and proves them (a deliberate violation, then a sample of real files, with real violations reported and a baseline offered), previews each `rules convert` and `rules decline` with `--dry-run` in a second conversation, and records the approved ones in a step of its own after it. It automatically creates a branch from `extensions.ww/git.base_branches.default`, which must be configured, and follows ww/git worktree settings, so its tool installs and configuration land on a branch of their own. The store it records into, `ww-rule-automation.json`, is in the main checkout: commit it there with, or right after, merging the run's branch; until then `is-git-clean` refuses the next task. |
660
+ | `ww-automate` | `ww-automate` | Looks at a step's instruction and past results for mechanical work a script could do, and proposes the script and a hook (or, for a workflow the configuration defines, the workflow with the step turned into a command step, placed with `setup update`); applies on confirmation. |
661
+
662
+ ww never interviews the operator about who they are, their role, their team
663
+ or their company. What a setup needs of the operator is a few questions about
664
+ the process, asked in `ww-suggest`: they are interactive steps, which open with
665
+ the questions in one numbered message, then converse until the operator's
666
+ intent to finish is clear, asking naturally if it is ambiguous. A pick between
667
+ a few answers goes through the host's native question tool when available.
668
+ The answers are ordinary conversation: they shape the proposal (modes, operator
669
+ stops, review, automation) and are not written to a file of their own. Every
670
+ question can be skipped, and setup never blocks ordinary work. `project.md` and
671
+ the setup are shown before they are written, and the shared file stays
672
+ uncommitted until the operator commits it. These workflows declare `runtime:
673
+ single` and give every step to the session that talks to the operator (`role:
674
+ manager`), so they work in agents without subagents. When `explain` is `true`,
675
+ the skills start them with the built-in `ww-narrate` mode, whose steps tell
676
+ the operator what each one does and why.
677
+
678
+ **Express or Guided.** The opening question offers two paths. Guided runs
679
+ `ww-learn-project`, then `ww-suggest`, which asks the process questions; it
680
+ takes about five replies: the opening question, the project review, the
681
+ process answers, the design and "apply". Express runs `ww-learn-project`, then
682
+ `ww-suggest` started with the requirement "Express setup": it asks no process
683
+ question, states the defaults the project supports, and asks only a
684
+ consequential choice the project leaves open. Both keep project learning: an
685
+ existing `project.md` is read first and refreshed, never silently replaced by a
686
+ generic template.
687
+
688
+ **What `ww-suggest` proposes.** Its `design` step asks, in one message with
689
+ a default for each answer taken from the profile, what the setup turns on,
690
+ and states as decided what the profile already answers: the integration
691
+ branch and the lanes, from the branch patterns present (no `hotfix` lane
692
+ without hotfix-like branches, unless the operator asks), the commands that
693
+ verify a change, their order and how they run, whether agents commit (following the
694
+ project's convention) and push (never), worktrees (on by default when several
695
+ contributors are active and the operator works on parallel tasks), the task ID
696
+ format, who reviews (for a solo project an agent self-review step rather than
697
+ an interactive review; for a team the operator keeps the review), the step
698
+ features a workflow whose work is not a plain code change uses, which of
699
+ the process answers become modes or operator stops, `projects` when the
700
+ layout found candidates (it asks for the sibling repositories' paths and never
701
+ scans them), a rule for a fix-prone path only when the fixes show a repeated
702
+ cause, and whether the setup is for the operator alone or the team. The proposal then
703
+ follows the project, within what this guide and the [specification](specification.md)
704
+ describe: `ww/git` settings for the branching and commit format, and one workflow
705
+ per lane, with `inherit` where lanes differ only in their base branch. The
706
+ verify commands become visible command steps of the workflow by default, as
707
+ [Designing a workflow](#designing-a-workflow) says; a check on every completion
708
+ of a step is proposed only where the project treats it as an invariant. Modes
709
+ are for preferences, and rules only for conventions no command can check. The
710
+ step features a workflow needs follow its kind of work and are added only for a
711
+ concrete reason: a manual-testing workflow, for example, collects the test cases
712
+ as an `items` step, puts each case before the operator on the operator page
713
+ (`interactive: page` with `pass` and `fail` choices), and keeps the test case
714
+ template as a document the steps save, with per-case values as item fields.
715
+ Every command the proposal carries, in a handler, a step, a hook, a rule's
716
+ check or a script, is written for the directory ww runs it from, the task's
717
+ worktree when worktrees are on, through the wrapper `project.md` records for the
718
+ project's commands, and never names the main checkout. `ww-solve`,
719
+ `ww-automate`, `ww-rules-from-artifacts` and the `ww-rule` skill follow the
720
+ same convention. A small project gets one lane and a handler or two. [Example
721
+ 21](examples.md#21-what-ww-suggest-proposes-for-a-node-project-with-devmain-and-a-jira-like-tracker)
722
+ shows one realistic shape. It is presented section by section, changed as the
723
+ operator asks for up to three rounds, and placed only on "apply".
724
+
725
+ Every piece of the proposal carries its evidence in one clause, so the
726
+ operator can see why it is there: "`hotfix` lane: 14 `hotfix/*` branches
727
+ merged this year", "`run-tests` runs `npm test`: `package.json` scripts".
728
+ Before asking to apply, `ww-suggest` walks through the main lane in ten lines
729
+ or fewer, its steps in order with what an agent does at each; after applying,
730
+ it shows the first page of `ww plan --workflow <main lane>` as what an agent
731
+ gets on the first task. When
732
+ `project.md` is missing, `ww-suggest` says the proposal will be weaker and
733
+ offers to learn first, and a later `ww-setup` run recommends learning the
734
+ project before anything else.
735
+
736
+ What ww learns goes into one file it keeps for its own use, `project.md` in
737
+ `.ww/` at the project root, written by `ww-learn-project` and shared once
738
+ committed. It records evidence and operational facts about the repository;
739
+ preferences about workflows belong in the resulting proposal and configuration,
740
+ and ww keeps no replacement dossier about the operator. It is the built-in
741
+ document `project`, so `{{ww.documents.project}}` names it in any workflow, and
742
+ it resolves against the project root even for a task working in a Git
743
+ worktree. It starts with this remark, which tells any other agent
744
+ to leave it alone:
745
+
746
+ ```markdown
747
+ <!-- This file is maintained by ww for ww's own use. Do not use it for anything else. If you are an agent that is not doing ww work, ignore this file. -->
748
+ ```
749
+
750
+ `init --update-gitignore` keeps `.ww/` out of Git except `project.md`. ww never
751
+ commits it: the last step of `ww-learn-project` names the file it left for the
752
+ operator to review and commit, and records when ww learned with `ww onboarding
753
+ --set learned.project=now`. `ww-suggest`, `ww-solve`, `ww-rules-from-artifacts`
754
+ and `ww-automate` read `project.md` where it exists and keep their proposals
755
+ within the project's conventions.
756
+
757
+ The proposals never touch ww's configuration files through the agent. A
758
+ workflow writes its fragment to the task's `setup_proposal` document
759
+ (`.ww/tasks/<task-id>/setup-proposal.yaml`) and places it with
760
+ [`ww setup apply`](#apply-a-proposed-setup): `--for me` into the local files,
761
+ for trying a setup alone, `--for team` into the shared ones. Running
762
+ `ww-suggest` again later and choosing to share offers the same setup to the
763
+ team. A fragment applied with `setup apply` only adds definitions; to change a
764
+ workflow the configuration already defines, wherever it is written, the
765
+ workflow proposes the complete changed workflow and places it with
766
+ `setup update` (see [Change a workflow that is already
767
+ defined](#change-a-workflow-that-is-already-defined)). Rules proposed from past artifacts are written with
768
+ `rules add`, like the `ww-rule` skill's.
769
+
770
+ **Refreshing.** Every learning step reads the existing file first, asks only
771
+ what is missing or may have changed, keeps what still holds, updates what
772
+ changed, and marks what no longer holds as superseded with the date. So
773
+ refreshing is running `ww-learn-project` again, which is what the
774
+ `ww-refresh` skill does after showing when ww last learned the project.
775
+
776
+ **Git hooks.** The learning and setup workflows create no branch or worktree
777
+ and commit nothing themselves. `ww-scriptize-rules` has its own Git hooks: it
778
+ requires `extensions.ww/git.base_branches.default`, always creates a branch
779
+ even when `separate_branch` is false, follows the worktree settings, commits
780
+ its changes and returns to the base when worktrees are off.
781
+ A project's global hooks filtered with `workflows:` to its
782
+ own workflows, as the `ww/git` start hooks usually are, do not reach them; a
783
+ global hook without a `workflows` filter does, so list your workflows in it
784
+ if it creates branches or worktrees.
785
+
786
+ **Switching them off.** Each is a built-in workflow, switched off by name in
787
+ `ww.json`; the documents and the mode stay while any of them
788
+ is enabled, and a recommendation of a switched-off one (`ww-learn-project` recommends
789
+ `ww-suggest`) is dropped:
790
+
791
+ ```json
792
+ {"workflows": {"ww-solve": {"enabled": false}, "ww-automate": {"enabled": false}}}
793
+ ```
794
+
795
+ A workflow of the same name in any `ww.yaml` level replaces the shipped one.
796
+ The `ww.json` workflow settings only switch built-ins on or off; scriptizing
797
+ needs no lane setting.
798
+
799
+ ## The catch-all workflow
800
+
801
+ Unless `enabled` is `"on_request"`, every change to files goes through ww,
802
+ including the small ones that fit no workflow: renaming a helper, fixing a typo, adjusting a setting. For those, ww
803
+ provides `catchall` to every project. It has one step, `work`, whose page tells
804
+ the agent that the workflow only records the request: it carries the work out
805
+ exactly as it would on a plain prompt, with the same judgement, tools,
806
+ subagents, skills, and project conventions, and completes the step with what it
807
+ changed.
808
+
809
+ `discover` lists it apart from the configured workflows, under "Changes no
810
+ workflow covers", together with the rules for using it, which the agent
811
+ instructions repeat. It is only for a change to files: questions,
812
+ explanations, reviews, investigations, status checks and other read-only work
813
+ never go through ww at all. The agent answers them without the ww skill and
814
+ without a task, and a conversation that begins as a question turns to ww only
815
+ once it reaches a change. It never replaces a matching workflow.
816
+
817
+ The agent does not start it directly. It first runs `lookup` with the task the
818
+ conversation works on, or with what the operator called the task, as they
819
+ wrote it, and without one when there is none:
820
+
821
+ ```console
822
+ ./ww lookup 12345 --agent claudecode
823
+ ```
824
+
825
+ `lookup` is read-only. It maps the reference onto the project's task IDs:
826
+ the exact ID in any letter case, the ID `task_format` builds from it, so
827
+ `12345` and `foobar-12345` both mean `FOOBAR-12345` under `FOOBAR-{{digit}}`, and,
828
+ failing both, the existing tasks whose ID ends in it after a separator, so
829
+ with tracker keys `12345` finds `FOOBAR-12345`. Then it answers with one next
830
+ step:
831
+
832
+ | Found | Next step |
833
+ |---|---|
834
+ | One task, with an unfinished run of another workflow | Continue that run: `./ww instruction FOOBAR-12345 --role manager`. The change belongs to it. |
835
+ | One task, otherwise | Start `catchall` on it; the printed `start` command is ready to run. |
836
+ | Several tasks | Ask the operator which one, then continue or start on it. |
837
+ | No task | Ask the operator to confirm creating the ID the reference names, `FOOBAR-99` for `99`. |
838
+ | No reference | Ask the operator whether to create a new task; under `"task_format": "explicit"` they give its ID. |
839
+
840
+ Asking goes through the agent's own choice menu, the same mechanism as an
841
+ interactive step's [choices](#interactive-steps), and every menu also offers
842
+ "Work without ww". Each choice comes with the command to run once it is
843
+ picked, and the page says to run nothing before then, so a task ww has never
844
+ seen is only created when the operator says so. A `catchall` start on a task
845
+ with an unfinished run of another workflow is refused, and the error names
846
+ the `instruction` command that continues it.
847
+
848
+ The workflow declares `runtime: auto` and its step `role: manager`: the
849
+ session that received the prompt does the work, and whether it uses subagents
850
+ along the way is its own choice, as without ww. It is `restartable`, so a new
851
+ request on the same task replaces one that was never finished, and it is not
852
+ interactive: a follow-up that changes more starts another `catchall` run on the
853
+ same task. Every run ends with the usual workflow summary.
854
+
855
+ The catch-all is one of ww's [built-in workflows](specification.md#built-in-workflows),
856
+ shipped as YAML with ww. A project replaces it by defining its own workflow
857
+ named `catchall` in `ww.yaml`, or switches it off in
858
+ `ww.json`:
859
+
860
+ ```json
861
+ {"workflows": {"catchall": {"enabled": false}}}
862
+ ```
863
+
864
+ ## Validate configuration and plan a workflow
865
+
866
+ `ww-agentic-workflows` turns `ww.yaml` into an explicit, inspectable
867
+ execution plan. Skills and slash commands are discovered only from the project's
868
+ shared `.agents/` directory and the selected agent's directory.
869
+
870
+ ```console
871
+ ww-agentic-workflows lint
872
+ ww-agentic-workflows plan --workflow task --agent codex
873
+ ww-agentic-workflows plan --workflow task --agent codex --task-id TASK-123 --json
874
+ ```
875
+
876
+ The workflow and agent options have `-w` and `-a` short forms. On `start`,
877
+ runtime also accepts `-r`.
878
+
879
+ `lint` validates the complete `ww.yaml` configuration without needing a
880
+ workflow or agent. It and `plan` are read-only: neither creates task state,
881
+ artifacts, commands, or execution log records. Markdown is for people; `--json`
882
+ returns a stable representation for tools. `--agent` is required because
883
+ automatic resolution depends on the agent’s project-local skills and slash
884
+ commands. `--task-id` is optional; when
885
+ omitted, `{{ww.task.id}}` remains visible as an unresolved plan dependency.
886
+
887
+ ## Split ww.yaml into several files
888
+
889
+ A large configuration can be split across files. `ww.yaml` stays the
890
+ required root file and lists the others under `imports`, its first key (only
891
+ `extends` may come before it). Paths are relative to the directory of the file
892
+ that lists them; every other relative path in the configuration still resolves
893
+ against the project root:
894
+
895
+ ```yaml
896
+ # ww.yaml
897
+ imports:
898
+ - workflows/shared.yaml
899
+ - workflows/local.yaml
900
+
901
+ handlers:
902
+ - name: test
903
+ argv: [python, -m, pytest, -q]
904
+
905
+ workflows:
906
+ - task: The standard development workflow.
907
+ steps:
908
+ - develop: Implement the change.
909
+ - test: ~
910
+ ```
911
+
912
+ ```yaml
913
+ # workflows/shared.yaml
914
+ handlers:
915
+ - name: test
916
+ argv: [pytest]
917
+ workflows:
918
+ - hotfix: Fix a production bug.
919
+ steps:
920
+ - fix: Fix it.
921
+ ```
922
+
923
+ ```yaml
924
+ # workflows/local.yaml
925
+ workflows:
926
+ - hotfix: Fix a production bug, verifying it first.
927
+ steps:
928
+ - reproduce: Reproduce it.
929
+ - fix: Fix it.
930
+ ```
931
+
932
+ An imported file can define anything `ww.yaml` can, except further
933
+ imports, so every file is listed in one place. Files apply in order, the root
934
+ file last, and a later definition overrides an earlier one of the same name:
935
+ here `ww.yaml`'s `test` handler replaces the shared one, and
936
+ `local.yaml`'s `hotfix` workflow replaces `shared.yaml`'s. Named entries of
937
+ `workflows`, `modes`, `documents`, `handlers`, and `profiles` are replaced one
938
+ by one, other entries from every file are kept, and `hooks` from every file are
939
+ combined, later files' entries running after earlier ones.
940
+
941
+ Overriding is never an error. `lint` reports each override as a notice:
942
+
943
+ ```console
944
+ $ ww-agentic-workflows lint
945
+ ww.yaml is valid.
946
+ Configuration files: workflows/shared.yaml, workflows/local.yaml, ww.yaml
947
+ Notice: workflow 'hotfix' from workflows/shared.yaml is overridden by workflows/local.yaml.
948
+ Notice: handler 'test' from workflows/shared.yaml is overridden by ww.yaml.
949
+ ```
950
+
951
+ ww composes the files in memory on every command into one document and reads
952
+ it exactly as a single `ww.yaml`, so every other rule applies unchanged
953
+ and there is no cache to refresh. `init` sees keys and workflows defined in
954
+ imported files too, and does not add them to `ww.yaml` again. The
955
+ [specification](specification.md#imports) has the exact rules.
956
+
957
+ ## User, repo, and local configuration
958
+
959
+ Both configuration files come in three levels, which ww finds and applies on
960
+ every command, top to bottom:
961
+
962
+ 1. user: `ww.yaml` and `ww.json` in
963
+ `~/.config/ww/` (under `$XDG_CONFIG_HOME` when that is
964
+ set), yours alone and shared by every one of your projects;
965
+ 2. repo: `ww.yaml` and `ww.json` in the
966
+ project root, checked in;
967
+ 3. local: `ww.local.yaml` and
968
+ `ww.local.json` in the project root, for one checkout and
969
+ kept out of version control.
970
+
971
+ The repo `ww.yaml` stays required: a user file alone never
972
+ makes a directory a ww project. `WW_USER_CONFIG_DIR` names another user
973
+ directory; the test suite points it at an empty one so a developer's own
974
+ configuration never leaks into tests. `init` creates the user directory when
975
+ it is missing and lists it under "Created or restored".
976
+
977
+ A lower level extends the levels above it with the same rules as
978
+ [imports](#split-wwyaml-into-several-files), and wins: named
979
+ workflows, modes, documents, handlers, and profiles are replaced one by one,
980
+ hooks are added per phase, and other keys take the lower value. Each level can
981
+ use `imports` of its own, resolved next to the file that lists them.
982
+
983
+ ```yaml
984
+ # ~/.config/ww/ww.yaml
985
+ handlers:
986
+ - name: test
987
+ argv: [pytest]
988
+ workflows:
989
+ - review: Review a change.
990
+ steps:
991
+ - review: Review it.
992
+ ```
993
+
994
+ ```json
995
+ // ww.local.json
996
+ {"task_format": "DEV-{{digit}}"}
997
+ ```
998
+
999
+ With the repo file defining its own `test` handler and its
1000
+ `ww.json` a `task_format`, the project gets the user's
1001
+ `review` workflow, the repo's `test` handler, and the local task format. `lint`
1002
+ lists the files it read, user to local, the YAML files first and the JSON
1003
+ ones after, and names the file behind each YAML override; `plan` ends with the
1004
+ same list:
1005
+
1006
+ ```console
1007
+ $ ww-agentic-workflows lint
1008
+ ww.yaml is valid.
1009
+ Configuration files: ~/.config/ww/ww.yaml, ww.yaml, ww.json, ww.local.json
1010
+ Notice: handler 'test' from ~/.config/ww/ww.yaml is overridden by ww.yaml.
1011
+ ```
1012
+
1013
+ A configured project's own `ww.json` and
1014
+ `ww.local.json` add one more level for tasks working there,
1015
+ limited to the `extensions` section and `task_format`; see
1016
+ [A project's own extension settings](#a-projects-own-extension-settings).
1017
+
1018
+ A level that should not build on the ones above sets `extends: false` in its
1019
+ root file or any of its imports; that level then starts afresh, and `lint`
1020
+ reports each file it leaves out. `extends: true` is allowed and changes
1021
+ nothing.
1022
+
1023
+ ```yaml
1024
+ # ww.local.yaml
1025
+ extends: false
1026
+ workflows:
1027
+ - task: My own way of working.
1028
+ steps:
1029
+ - develop: Do it.
1030
+ ```
1031
+
1032
+ ```console
1033
+ $ ww-agentic-workflows lint
1034
+ ww.yaml is valid.
1035
+ Configuration files: ww.local.yaml, ww.json
1036
+ Notice: ~/.config/ww/ww.yaml is not applied: a lower level sets extends: false.
1037
+ Notice: ww.yaml is not applied: a lower level sets extends: false.
1038
+ ```
1039
+
1040
+ The JSON settings are always deep-merged and take no `extends` key: nested
1041
+ objects merge key by key, while strings, numbers, booleans, lists, and `null`
1042
+ from a lower level replace the value above. A user file can, for example,
1043
+ set `{"runtime": "auto"}` for every project while one checkout's
1044
+ `ww.local.json` sets
1045
+ `{"extensions": {"ww/git": {"worktrees": false}}}` without repeating the rest of
1046
+ the repo's `ww/git` settings.
1047
+
1048
+ `init` writes only the repo-level files, and decides what to add from the
1049
+ composed result: it adds no default workflow to the YAML, and no `task_format`
1050
+ to the JSON, when another level already provides them.
1051
+
1052
+ ## Configuration
1053
+
1054
+ Every mode is a mapping with a required `name` and an optional description.
1055
+ Workflows, handlers, and steps support that long form plus a shorthand whose
1056
+ first key is the name and whose string or null value is the description.
1057
+ `handlers` is the reusable global catalog. A step is also a handler, with
1058
+ optional workflow hooks.
1059
+
1060
+ ```yaml
1061
+ handlers:
1062
+ - update-yaml-specification: Update specification.md.
1063
+ - no-description: ~
1064
+
1065
+ workflows:
1066
+ - task: The standard development workflow.
1067
+ steps:
1068
+ - develop: Implement and test the change.
1069
+ ```
1070
+
1071
+ A step can copy a root handler definition with `handler: <name>`, and a step
1072
+ that has no content of its own, `- fetch_requirements: ~`, copies the root
1073
+ handler of the same name without saying so, exactly as a bare hook entry does;
1074
+ settings such as `profile` or `model` on that step still override the copy.
1075
+ This is a hard link at configuration time, not another execution phase: the
1076
+ plan contains one ordinary step under the step's own name. Its description and
1077
+ explicitly declared handler fields override the copied definition. Root handlers may also
1078
+ hold a complete step container, so a loop or nested step sequence can be named
1079
+ once and reused by referencing steps.
1080
+
1081
+ ```yaml
1082
+ handlers:
1083
+ - name: shared-check
1084
+ argv: [pytest, -q]
1085
+
1086
+ workflows:
1087
+ - name: task
1088
+ steps:
1089
+ - verify: Run the project verification.
1090
+ handler: shared-check
1091
+ ```
1092
+
1093
+ A reusable handler can contain the whole step structure. For example, define a
1094
+ review loop once and use it as a workflow step:
1095
+
1096
+ ```yaml
1097
+ handlers:
1098
+ - code-review:
1099
+ loop:
1100
+ - code-review: Perform the code review.
1101
+ break: There are no meaningful review remarks.
1102
+ profile: code-reviewer
1103
+ - fix: Fix the review findings.
1104
+ profile: developer
1105
+
1106
+ workflows:
1107
+ - name: task
1108
+ steps:
1109
+ - code-review: ~
1110
+ handler: code-review
1111
+ ```
1112
+
1113
+ The same shorthand works for singular hook actions and entries inside a hook's
1114
+ ordered `handlers` list. If a mapping contains `name`, ww preserves the existing
1115
+ long-form interpretation.
1116
+
1117
+ ### Profiles
1118
+
1119
+ Profiles tailor the agent's approach without implying that another agent will
1120
+ be spawned. Define them at the root and apply one to a workflow or one of its
1121
+ steps. A profile is inherited along the same chain as agent, model, and
1122
+ reasoning: from the workflow, through every enclosing step, to the step itself,
1123
+ so a loop wrapper or a parent step sets it for its whole body and any nested
1124
+ step may override it. Hooks, modes, and handlers cannot declare profiles.
1125
+
1126
+ ```yaml
1127
+ profiles:
1128
+ developer: >-
1129
+ You are a senior Symfony developer. Prefer small, well-tested changes.
1130
+ code-reviewer: ~
1131
+
1132
+ handlers:
1133
+ - name: git-stage
1134
+ argv: [git, add, .]
1135
+ - name: git-commit
1136
+ variables:
1137
+ - name: commit_message
1138
+ description: A concise commit message.
1139
+ argv: [git, commit, -m, "{{ww.task.id}}: {{commit_message}}"]
1140
+
1141
+ hooks:
1142
+ before_complete:
1143
+ - steps: [develop]
1144
+ handlers:
1145
+ - name: git-stage
1146
+ - name: git-commit
1147
+
1148
+ workflows:
1149
+ - name: task
1150
+ steps:
1151
+ - name: develop
1152
+ description: Implement and verify the requested change.
1153
+ profile: developer
1154
+ ```
1155
+
1156
+ ### Implicit requirements step
1157
+
1158
+ Every workflow begins with an artifact-producing `init` step supplied by ww.
1159
+ Do not declare it in `steps`: `init` is a reserved step name, including inside
1160
+ nested and per-item steps. Its fixed prompt asks the agent only to preserve the
1161
+ passed requirements, correcting grammar and style without adding analysis,
1162
+ reasoning, or a work plan. It uses low reasoning and does not inherit a workflow
1163
+ profile, keeping the saved requirements independent of later execution choices.
1164
+
1165
+ `init` otherwise has the same lifecycle and persistence behavior as a declared
1166
+ step. The workflow-wide `before_start_workflow` boundary runs once before it and
1167
+ does not accept a step filter:
1168
+
1169
+ ```yaml
1170
+ hooks:
1171
+ before_start_workflow:
1172
+ - name: check-clean
1173
+
1174
+ workflows:
1175
+ - name: task
1176
+ steps:
1177
+ - name: develop
1178
+ artifact_from: init
1179
+ ```
1180
+
1181
+ Each workflow run gets its own `init`, including handoff targets and child-task
1182
+ workflows. `ww plan` includes it in the exact execution order. `start` requires
1183
+ `--requirements` and stores that normalized requirements text immediately in
1184
+ the built-in artifact before returning the first declared step; it never assigns
1185
+ `init` to a worker or requires a subsequent `next`/`complete` cycle.
1186
+
1187
+ ### Commands
1188
+
1189
+ Command handlers canonically put a structured argument vector at their root,
1190
+ for example `argv: [git, status, --porcelain]`. Each argument is interpolated
1191
+ independently and execution never invokes a shell.
1192
+
1193
+ When shell behavior is intentional, declare it explicitly. Shell source is not
1194
+ interpolated; dynamic workflow values must enter through `env` or `args`:
1195
+
1196
+ ```yaml
1197
+ shell: printf '%s' "$MESSAGE" > message.txt
1198
+ env:
1199
+ MESSAGE: "{{commit_message}}"
1200
+ ```
1201
+
1202
+ `assert` adds a list of output conditions to the root command action, all of
1203
+ which must hold: `assert: [empty]`, or `assert: [{equals: clean}]`. A handler
1204
+ is one action; use a hook's ordered `handlers` list for multiple commands.
1205
+
1206
+ `idempotent: true` declares that running the handler again is harmless. It
1207
+ changes one thing: when ww is interrupted while the handler runs, the next
1208
+ locked `next` replays the interrupted and unrun commands under the same
1209
+ operation identity and carries on, instead of stopping at the recovery
1210
+ boundary for an operator decision. The default is `false`, which keeps the
1211
+ unknown outcome until `next --retry` or a checker settles it; see [Interrupted automatic handlers](#interrupted-automatic-handlers).
1212
+ Declare it on test runs, linters, and checks that only read; leave it off
1213
+ anything that publishes, commits, or sends. `lint` rejects it without `argv`
1214
+ or `shell`, the saved plan carries it, and `plan` shows it under
1215
+ **Recovery**:
1216
+
1217
+ ```yaml
1218
+ handlers:
1219
+ - name: tests
1220
+ argv: [python, -m, pytest, -q]
1221
+ idempotent: true
1222
+ ```
1223
+
1224
+ ### Handler types and ownership
1225
+
1226
+ Set `kind: skill`, `kind: slash_command`, `mcp: <connection>`, `argv`, `shell`,
1227
+ or `kind: prompt` to select a handler kind explicitly; the registry form
1228
+ `action: {type: <action>, ...}` selects any registered action by its
1229
+ identifier. The handler description is the instruction for prompt and MCP
1230
+ work. Use an `assess` step when a decision must control workflow routing.
1231
+ Without an explicit action, resolution is deterministic:
1232
+
1233
+ 1. A matching project-local skill is an agent skill handler.
1234
+ 2. A matching project-local slash command is an agent slash-command handler.
1235
+ 3. Otherwise the name/description becomes an agent prompt.
1236
+
1237
+ ### Automated handler groups
1238
+
1239
+ A reusable handler can contain `handlers`, an ordered sequence of actions
1240
+ that ww executes itself. Use `steps` for a sequence that includes agent work
1241
+ or needs separate step lifecycles.
1242
+
1243
+ ```yaml
1244
+ handlers:
1245
+ - build: ~
1246
+ shell: npm run build
1247
+ - verify-build: ~
1248
+ on_failure: fix
1249
+ on_failure_instruction: Fix the reported build or output errors.
1250
+ handlers:
1251
+ - build: ~
1252
+ - argv: [test, -d, dist]
1253
+
1254
+ workflows:
1255
+ - name: task
1256
+ steps:
1257
+ - verify-build: ~
1258
+ ```
1259
+
1260
+ Members run in order under the enclosing step or hook's lifecycle. They may
1261
+ be inline automatic actions, catalog references (including later declarations),
1262
+ or nested automated groups. Empty groups, reference cycles, agent-owned
1263
+ actions, and actions requiring agent input are rejected. A group cannot also
1264
+ declare a direct action or a step container.
1265
+
1266
+ Groups supply defaults for the working directory, repair worker guidance,
1267
+ failure policy, and failure instruction; members can override them. Each
1268
+ member uses normal ww execution and recovery. If a command with
1269
+ `on_failure: fix` fails, its agent repairs the cause and ww retries that member,
1270
+ preserving successful preceding members.
1271
+
1272
+ Hooks can reference these groups and keep their existing phase and filters.
1273
+ Eligible `before_complete` members with `on_failure: fix` become completion
1274
+ checks. Existing hook `handlers` lists remain compatible, including their
1275
+ support for agent actions; reusable automated groups require every member to
1276
+ be fully automatic.
1277
+
1278
+ ### Outcome-based assessments
1279
+
1280
+ Use `assess` when an agent's judgment should route the remainder of a workflow.
1281
+ The agent should choose `positive` or `negative` whenever possible, reserving
1282
+ `mixed` for material uncertainty. After completing the assessment, select the
1283
+ declared route with `ww next <task-id> --outcome <label> --role manager`.
1284
+
1285
+ ```yaml
1286
+ - assess:
1287
+ question: Does recent development warrant refactoring?
1288
+ outcomes:
1289
+ positive:
1290
+ handler: refactor-plan
1291
+ negative:
1292
+ steps:
1293
+ - record: No refactoring is needed now.
1294
+ mixed:
1295
+ steps:
1296
+ - investigate: Gather the missing evidence.
1297
+ ```
1298
+
1299
+ Every outcome uses one ordinary step shape: a global `handler`, an inline
1300
+ action, `handlers`, or nested `steps`. Outcome work types are mutually
1301
+ exclusive. After the chosen outcome's work, the workflow continues with the
1302
+ step after `assess`. An outcome that should end the run instead is
1303
+ `stop_workflow: true` on its own:
1304
+
1305
+ ```yaml
1306
+ - assess:
1307
+ question: Were conflicts resolved in non-trivial code?
1308
+ outcomes:
1309
+ positive:
1310
+ steps:
1311
+ - review: Review the resolutions.
1312
+ negative:
1313
+ stop_workflow: true
1314
+ ```
1315
+
1316
+ Choosing it completes the workflow, skipping every later step and hook. An
1317
+ assessment needs at least one outcome with work; one that only stops is the
1318
+ compact form.
1319
+
1320
+ A gate declares only the outcome that has work. `positive`, `negative`, and
1321
+ `mixed` are accepted whether declared or not, and an undeclared one runs nothing
1322
+ and continues after the assessment:
1323
+
1324
+ ```yaml
1325
+ - assess:
1326
+ question: Were conflicts resolved in non-trivial code?
1327
+ outcomes:
1328
+ positive:
1329
+ steps:
1330
+ - review: Review the resolutions.
1331
+ - verify: Run the tests.
1332
+ ```
1333
+
1334
+ Here `negative` and `mixed` go straight to `verify`. A label of your own, such
1335
+ as `partial`, is accepted only when declared. For a simple gate, `- assess: <question>` accepts `positive` or
1336
+ `negative`; positive continues normally and negative completes the workflow.
1337
+
1338
+ The standard branches can also sit directly beside `question`:
1339
+
1340
+ ```yaml
1341
+ - assess:
1342
+ question: Does recent development warrant refactoring?
1343
+ positive:
1344
+ handler: refactor-plan
1345
+ negative:
1346
+ steps:
1347
+ - record: No refactoring is needed now.
1348
+ ```
1349
+
1350
+ Direct branches and `outcomes` cannot be combined; use `outcomes` for custom
1351
+ labels.
1352
+
1353
+ The agent sees the choice before it answers: the assessment's page lists each
1354
+ outcome and what it does, for example "`negative` — ends the workflow here".
1355
+ Once the assessment is complete, the next page asks for the outcome and shows
1356
+ one `next --outcome <label>` command per outcome, never a plain `next`, which
1357
+ ww would refuse. An outcome made of an automatic command runs only after its
1358
+ outcome is chosen; ww pauses at a pending assessment rather than running any
1359
+ branch. A delegating manager chooses it itself; no worker preview is
1360
+ shown until the outcome decides which work comes next.
1361
+
1362
+ `profile` may be a name or a mapping containing `name` and/or `description`.
1363
+ The mapping form supplies an inline description. ww resolves a named profile by
1364
+ first checking the selected agent directory's `agents/` folder (for example,
1365
+ `.codex/agents/developer.md`), then using the inline or root `profiles` text,
1366
+ and finally instructing the agent to use the profile by name when it has no
1367
+ description. A discovered file is always named explicitly in the instruction.
1368
+
1369
+ CLI handlers and workflow transitions are owned by `ww`; skills, slash commands,
1370
+ and prompts are owned by the agent. The plan exposes this ownership for every
1371
+ item. It also exposes an explicit execution mode:
1372
+
1373
+ - A CLI handler is `automatic`: ww runs it. It is shown in the plan for
1374
+ information and an agent must not run its command directly.
1375
+ - A CLI handler with `variables` entries of the `name: description` form is
1376
+ still automatic, but first has
1377
+ `requires_agent_input: true`. The preceding agent completion instruction
1378
+ collects those values and then ww runs the command itself.
1379
+ - Skills, slash commands, prompts, and MCP prompts are `agent_instruction`
1380
+ items.
1381
+ - A workflow transition is a `workflow_transition`, owned by the coordinator but
1382
+ not an automatically run CLI command.
1383
+
1384
+ If an agent-owned item cannot be completed, its worker uses
1385
+ `ww fail <TASK-ID> --role worker --error "<functional error>"`. The task enters
1386
+ a failed state. The worker reports it to the manager, and the manager reports it
1387
+ to the ww operator for manual intervention.
1388
+
1389
+ An artifact-enabled workflow step must be completed with a non-empty
1390
+ `--artifact`. Set `artifact: false` on a step that has no useful durable result.
1391
+ This prevents a successful-looking completion from silently losing the agent's
1392
+ work.
1393
+
1394
+ ## Modes and execution settings
1395
+
1396
+ Modes add reusable guidance to a workflow. Define defaults on the workflow and
1397
+ add more when starting a task:
1398
+
1399
+ ```yaml
1400
+ modes:
1401
+ - name: economy
1402
+ description:
1403
+ - Keep responses concise.
1404
+ - Prefer lighter reasoning where appropriate.
1405
+
1406
+ workflows:
1407
+ - name: task
1408
+ modes: [economy]
1409
+ model: gpt-5
1410
+ reasoning: high
1411
+ steps:
1412
+ - name: implement
1413
+ model: gpt-5-mini
1414
+ ```
1415
+
1416
+ ```console
1417
+ ww-agentic-workflows start TASK-123 --workflow task --agent codex --role manager \
1418
+ --requirements="Implement the requested change." \
1419
+ --mode economy --runtime auto --model gpt-5 --reasoning high
1420
+ ```
1421
+
1422
+ Each agent step's page lists the modes it works in under **Modes**, with
1423
+ their descriptions, so the guidance reaches whoever performs the step. The
1424
+ same pages get modes as get rules: not `init`, hooks, verifiers, or the
1425
+ workflow summary.
1426
+
1427
+ A mode may also apply by itself. Give it `workflows`, `steps`, or both, in the
1428
+ same shape as a hook's filters (`"*"` or a list of names), and it applies
1429
+ automatically to every step they admit, in addition to the selected modes:
1430
+
1431
+ ```yaml
1432
+ modes:
1433
+ - name: tdd
1434
+ description: Write the failing test first.
1435
+ workflows: [task, bugfix]
1436
+ steps: [develop]
1437
+ ```
1438
+
1439
+ Here every `develop` step of `task` and `bugfix` (and of workflows inheriting
1440
+ them) works in `tdd`, whatever `--mode` says: `--mode` replaces only the
1441
+ workflow's default modes. A mode without either key applies only when
1442
+ selected. `[]` on a mode means all, as on a hook. `discover` marks automatic
1443
+ modes with where they are always on. The modes of each step are fixed when
1444
+ the run starts; a later change to the configuration does not alter a running
1445
+ task's pages.
1446
+
1447
+ `single` uses one session for manager and worker responsibilities. `auto`
1448
+ lets a manager dispatch assignments to separate workers; it does not make `ww`
1449
+ launch models. Both runtimes use the same command exchange and persisted state.
1450
+ Workflow and step `model` and `reasoning` values are recorded with the work, and
1451
+ step values override workflow values. Use `modes`, `runtimes`, and `agents` to
1452
+ inspect the available choices.
1453
+
1454
+ ### Steps the manager performs
1455
+
1456
+ `role` says who performs a step: `worker`, the default, is delegated in the
1457
+ `auto` runtime; `manager` keeps the step in the managing session in every
1458
+ runtime, such as a review whose judgement the manager keeps for itself. The
1459
+ step's profile, agent, model, and reasoning settings are deliberately ignored
1460
+ for a manager's step, whether set on it or inherited, and `lint` notes them.
1461
+ The manager's pages say so: the dispatch page states that no worker is
1462
+ selected and shows a plain `next`, and the page after it tells the manager to
1463
+ perform the step itself, with no worker bootstrap. An interactive step is
1464
+ always the manager's, since only its session can talk to the operator.
1465
+
1466
+ `role` is inherited like `profile`: set on a workflow, a group of steps, or a
1467
+ loop wrapper, it applies to everything inside, and a nested step overrides it.
1468
+ A step ww runs itself, such as a command, has no role; setting one on it is an
1469
+ error, while an inherited role passes over it.
1470
+
1471
+ ```yaml
1472
+ workflows:
1473
+ - name: task
1474
+ model: gpt-5
1475
+ steps:
1476
+ - develop: Implement the change.
1477
+ - name: review-loop
1478
+ role: manager
1479
+ loop:
1480
+ - review: Review the diff and list the findings.
1481
+ break: There are no findings.
1482
+ - fix: Apply the findings.
1483
+ role: worker
1484
+ ```
1485
+
1486
+ ### Steps without subagents
1487
+
1488
+ `subagents: false` says that whoever performs a step does all of its work
1489
+ alone: no subagent for research, tests, review, or anything else. It is
1490
+ independent of `role` and of the model: a delegated step with its own model can
1491
+ forbid helpers, and so can a step the manager performs. The step's page states
1492
+ the rule in its work instruction. It is inherited like `profile`, so on a group
1493
+ it covers every step inside, and a nested step may set `subagents: true` again.
1494
+
1495
+ ```yaml
1496
+ - name: develop
1497
+ model: opus
1498
+ subagents: false # nobody working on develop's steps spawns subagents
1499
+ steps:
1500
+ - research: Find what the change touches.
1501
+ - implement: Implement it.
1502
+ model: sonnet # its own model, still no subagents
1503
+ ```
1504
+
1505
+ ## Manager and worker assignments
1506
+
1507
+ Caller role describes responsibility for one command. It is explicit workflow
1508
+ coordination rather than authentication. The manager owns `start`, `next`, and
1509
+ recovery. A worker may inspect status and complete or fail active work. Scripts and
1510
+ direct service callers may omit the role; every execution command ww prints
1511
+ includes one.
1512
+
1513
+ One manager `next` dispatches a structural assignment. For a leaf step, that
1514
+ assignment contains its preparation hooks, main action, and completion hooks.
1515
+ Each worker completion records one agent result, runs eligible automatic work,
1516
+ and activates the next agent-owned workflow hook in the same assignment. The response exposes
1517
+ `continue_worker`, `handoff_manager`, `blocked`, or `awaiting_operator`
1518
+ together with `next_role`. `blocked` means ww is waiting on its own work, such
1519
+ as a child workflow, a loop boundary, or a running automatic handler, and the
1520
+ manager continues. `awaiting_operator` means a human must decide; see
1521
+ [Awaiting the operator](#awaiting-the-operator).
1522
+ At handoff only the manager runs the displayed `next --role manager` command.
1523
+ In the `auto` runtime the manager's delegate page and the requested worker
1524
+ describe the step that drives selection, not whichever hook the cursor is on,
1525
+ and both the manager and the worker are told every item the assignment covers.
1526
+ A worker moving to a later item of the same assignment is told so explicitly,
1527
+ and the end of an assignment says to stop and return to the manager.
1528
+
1529
+ An assignment that holds no agent step, only an automatic handler waiting for
1530
+ values, such as a commit hook that needs its message after a loop boundary, is
1531
+ not delegated. The manager has just read the outcome it would summarize, so
1532
+ the `awaiting_input` instruction is addressed to the manager, its command
1533
+ carries `--role manager`, and the preview before it says that no worker is
1534
+ selected. Every pending-input page also lists, under "Work these values
1535
+ describe", the handovers of the steps completed since that handler last ran
1536
+ in the run, so a commit message names this round's work rather than repeating
1537
+ an earlier one. The first page of each session shows the requirements saved by
1538
+ `init` in full under "Task requirements", so the user's wording reaches the worker
1539
+ without the manager adding commentary: the manager's first page that asks for
1540
+ work, the first page of every delegated worker assignment (each is a fresh
1541
+ session; `pages.worker_requirements` in `ww.json` set to `pointer` swaps it for
1542
+ the pointer), or, in the `single` runtime, the first agent step. Later pages of
1543
+ the same session, such as the following stages of one assignment, carry a
1544
+ one-line pointer to
1545
+ `ww requirements <task>`, which prints them again (JSON pages keep
1546
+ `task_requirements` and add `requirements_in_full` and `requirements_command`).
1547
+ A paragraph the work instruction already quotes verbatim is shown there only.
1548
+ `ww amend <task> --requirements "<text>" [--role ROLE]` appends a short
1549
+ (at most 1000 characters), timestamped amendment recording who made it (the
1550
+ caller role, or `operator`) and never rewrites the original; every page lists the
1551
+ amendments, newest last, under "Task requirements" (JSON: `task_amendments`), and
1552
+ `ww requirements` prints them after the original. A completed task refuses an
1553
+ amendment. Each page also states that ww writes the artifact
1554
+ from the completion command, never the worker under `.ww`. It then shows, under
1555
+ "Previous step result", the handover of the step completed most recently
1556
+ before this one. Completing an ordinary step requires
1557
+ `--summary`, one or two sentences on what was done and what the
1558
+ next step must know, at most 500 characters (a longer one is refused); ww stores it on the step record and shows it to the next
1559
+ step together with the artifact's path, so the full result stays in the
1560
+ artifact and is read only when the summary is not enough. Hooks, `init`,
1561
+ and the built-in summary do not take one. Only ordinary steps count: hook results,
1562
+ the built-in summary, and `init` are never chosen, and the history of earlier
1563
+ loop rounds is included, so the first step of a later round sees the previous
1564
+ round's last step. `artifact_from` remains the way to point a step at a specific
1565
+ earlier artifact when the immediately previous one is not the right input.
1566
+
1567
+ An active step's Markdown instruction also names its later sibling steps. This
1568
+ gives the worker a lightweight scope boundary without repeating those steps'
1569
+ descriptions or prescribing a strict prohibition:
1570
+
1571
+ ```markdown
1572
+ ### Next steps
1573
+
1574
+ Leave to them the work they cover:
1575
+
1576
+ - run-tests
1577
+ - check-code-quality
1578
+ ```
1579
+
1580
+ The JSON instruction exposes the same ordered names in `next_steps`. Hooks do
1581
+ not receive the list, and a step with no later siblings omits the section.
1582
+
1583
+ Parent-only preparation hooks form their own dispatch before descendants.
1584
+ Completion hooks on a parent trail the last descendant, and the built-in final
1585
+ summary trails the final assignment. A newly materialized item, child-workflow
1586
+ coordinator, workflow transition, or successor execution instance is always a
1587
+ manager boundary.
1588
+
1589
+ On a failure or an interruption, the response reports `awaiting_operator`
1590
+ and states whether a preceding worker result was already saved.
1591
+ `instruction --role worker` reconstructs the same continuation or handoff from
1592
+ persisted state after a restart. Caller roles do not change the concurrency
1593
+ guarantees; a stale worker is stopped by its [assignment
1594
+ token](#assignment-tokens).
1595
+
1596
+ ### Assignment tokens
1597
+
1598
+ In the `auto` runtime every assignment the manager hands out carries a short
1599
+ token. The bootstrap command gives it to the worker, and every command a
1600
+ worker page prints repeats it:
1601
+
1602
+ ```console
1603
+ ./ww instruction TASK-7 --run 01-task --role worker --assignment 3f9a1c07
1604
+ ./ww complete TASK-7 --role worker --assignment 3f9a1c07 --artifact="..." --summary="..."
1605
+ ```
1606
+
1607
+ `instruction`, `complete`, `loop`, `fail`, `interact`, and `dispute` with
1608
+ `--role worker` accept a call only when its token is the open assignment's,
1609
+ so a worker whose assignment ended, or that holds another assignment's token,
1610
+ cannot act. When the assignment ends, at a handoff to the manager, a return
1611
+ from a loop, or a failure, ww closes the token. A worker command after that is
1612
+ refused with "your assignment has ended", and one without a token is sent back
1613
+ to the manager. While no assignment is open, a worker's `instruction` still
1614
+ answers with the page that only sends it back.
1615
+
1616
+ The manager needs no token, and it never has to remember one. After a context
1617
+ compaction, `instruction <task> --role manager` shows the open assignment and
1618
+ its bootstrap command with the same token, so a worker still holding it
1619
+ carries on. `next <task> --role manager --reassign` issues a new token for the
1620
+ open assignment and closes the old one, for a worker that was lost or must be
1621
+ replaced. A step the manager performs itself, `role: manager` or interactive,
1622
+ is an assignment of its own with its own token, which no worker page ever
1623
+ shows. The worker's first page of an assignment says it is addressed to the
1624
+ worker, that running the commands it displays is expected even where they name
1625
+ the parent task, and that the worker changes only its own branch and worktree. Its page gives a manager completion command, `complete <task> --role
1626
+ manager`, and ww refuses `complete` or `loop` with `--role worker` on it ("this
1627
+ step is the manager's"), even with the step's token. The manager keeps every
1628
+ override: it may still complete or recover any other step.
1629
+
1630
+ When the step after a manager's `complete --role manager` is also the manager's
1631
+ own (`role: manager`, so no worker is selected), `complete` performs the dispatch
1632
+ that `next --role manager` would and prints that step's work page under a
1633
+ one-line note, so the separate `next` is unnecessary. It never does so when a
1634
+ worker must be selected, when the task stops or waits for the operator, for an
1635
+ assessment's outcome choice, at a loop boundary or a child coordinator, or for
1636
+ `--role worker`; `complete --no-dispatch` keeps the pending page.
1637
+
1638
+ Tokens guard against a confused agent, not a hostile one: a worker that runs
1639
+ the manager's commands is still not stopped. The `single` runtime, where one
1640
+ session does every step, uses no tokens.
1641
+
1642
+ A handler that failed inside an assignment keeps the assignment open. When
1643
+ `next --retry` asks again for the values the handler takes, the completion
1644
+ command on that page carries the open token, so the worker supplies them with
1645
+ the assignment it holds.
1646
+
1647
+ ### Handoff to manager
1648
+
1649
+ In the `auto` runtime the manager does not take a worker's word for what
1650
+ happened. When a worker's command ends its assignment (its last `complete` or
1651
+ `loop`, a `fail`, or a `dispute`), the page ends with a "Handoff to manager"
1652
+ block that ww writes from the saved state:
1653
+
1654
+ ```text
1655
+ Handoff to manager · assignment 3f9a1c07
1656
+
1657
+ Steps:
1658
+ - review: completed
1659
+ artifact: /repo/.ww/tasks/TASK-7/runs/01-task/steps/03-review.md
1660
+ - fix: completed
1661
+ artifact: /repo/.ww/tasks/TASK-7/runs/01-task/steps/04-fix.md
1662
+ checks: develop/sh passed
1663
+ fix rounds: 1
1664
+
1665
+ Files changed:
1666
+ - src/app.py
1667
+
1668
+ Worker summary: Both findings fixed; the parser test covers the second.
1669
+
1670
+ Manager: continue with `./ww next TASK-7 --role manager`
1671
+ ```
1672
+
1673
+ It lists every agent item the worker performed in the assignment with its
1674
+ outcome (`completed`, `loop break`, `loop continue`, `held for verification`,
1675
+ `failed` with the error, or `not completed`), each artifact's path, the checks
1676
+ of the last attempt with their status, the checks the operator waived, and the
1677
+ number of fix rounds. "Files changed" is the change set since the first step of
1678
+ the assignment with rules or checks began; without such a step, or without git,
1679
+ it reads "not tracked". A failed handler's error is shown too. The worker's
1680
+ own judgment reaches the manager only through its `--summary`.
1681
+ The worker page tells the worker to return the block verbatim as its final
1682
+ message and nothing else, and prints no further command for it. The manager's
1683
+ bootstrap page names the block by the assignment's token, so the manager knows
1684
+ which block answers which assignment. The JSON instruction carries the same
1685
+ facts in `handoff_block`. The `single` runtime has no block.
1686
+
1687
+ ### Confirmations
1688
+
1689
+ `next --retry`, `next --force`, a `next --replan` that reruns finished steps,
1690
+ `rules prune`, `rules revoke`, `rules convert` and `rules decline` ask the
1691
+ operator to confirm, because they can repeat an external effect, skip work,
1692
+ record a command that will run from then on, or change the shared
1693
+ rule-automation store. ww asks only at a terminal. An
1694
+ agent's shell has none, so there ww refuses at once and names `--yes`, and it
1695
+ never reads an answer from a pipe. The pages that show these choices print
1696
+ them with `--yes`, since the agent runs one only after the operator chose it;
1697
+ the effect is still printed, and the task's audit record notes whether the
1698
+ operator confirmed at a terminal or an agent did with `--yes`.
1699
+
1700
+ ### Awaiting the operator
1701
+
1702
+ The operator is the human running the agent. When only they can decide how a
1703
+ task goes on, the response says so in a machine-readable way instead of in
1704
+ prose: `control` is `awaiting_operator`, `next_role` is `operator`, and
1705
+ `operator_reason` says why.
1706
+
1707
+ | `operator_reason` | When |
1708
+ | --- | --- |
1709
+ | `handler_failed` | An automatic handler failed. |
1710
+ | `work_failed` | An agent step was recorded with `fail`, or the bootstrap failed. |
1711
+ | `child_failed` | A child task failed. |
1712
+ | `handler_interrupted` | An automatic handler was interrupted and its outcome is unknown. |
1713
+ | `loop_limit` | A loop reached its round limit: its `max_rounds`, else `limits.rounds`. |
1714
+ | `fix_limit` | A step's check failed as many times as its rule's `max_fixes`, else `limits.fixes`, allows; see [Rules and checks](#rules-and-checks). |
1715
+ | `check_disputed` | A step's worker disputed a check that rejected its completion; see [Checking early and disputing a check](#checking-early-and-disputing-a-check). |
1716
+ | `value_unavailable` | An agent step reads a `{{ww.<namespace>.<name>}}` value its extension cannot give for the task yet, such as `{{ww.git.branch}}` before the task has a branch; the step has not started. `next --retry` checks again, `next --force` skips it. |
1717
+ | `pass_incomplete` | An `items` pass finished its stages, but some items lack what those stages declare, such as an analysis or `reported`; see [Several passes over the same items](#several-passes-over-the-same-items). The next step has not started. Record the missing values with `update-item`, then `next --retry` checks again; the gate cannot be forced. |
1718
+ | `plan_changed` | The workflow's definition changed since the run's plan was saved; see [When the workflow changes mid-run](#when-the-workflow-changes-mid-run). |
1719
+
1720
+ An interrupted handler declared `idempotent: true` is not a reason: `next`
1721
+ replays it without asking anyone, so the task stays `blocked` for the manager.
1722
+ `operator_reason` is `null` whenever `control` is anything else. The same three
1723
+ fields appear in `instruction` and `status` JSON:
1724
+
1725
+ ```json
1726
+ {
1727
+ "control": "awaiting_operator",
1728
+ "next_role": "operator",
1729
+ "operator_reason": "handler_failed"
1730
+ }
1731
+ ```
1732
+
1733
+ Markdown heads the page with the decision, for example
1734
+ `## Operator decision: the automatic handler failed`, and tells the agent to
1735
+ stop and ask the operator. The recovery commands, `next --retry` and
1736
+ `next --force --reason`, are still shown, as the operator's choices; the
1737
+ agent runs one only after the operator picks it. A delegated worker is not told
1738
+ to ask anyone: it returns to its manager, and the manager asks.
1739
+
1740
+ The operator is someone ww waits for, not a caller: `--role` still accepts only
1741
+ `manager` and `worker`, and `--role operator` is rejected.
1742
+
1743
+ ### When the workflow changes mid-run
1744
+
1745
+ A run works from the plan it compiled when it started. When the workflow's
1746
+ definition changes afterwards, say a hook's command was wrong and stopped the
1747
+ task, and the operator fixed it in `ww.yaml`, the manager's next `next` (and
1748
+ its `instruction` page) compiles the workflow again and compares it with the
1749
+ saved plan, step by step and hook by hook. If anything differs, ww stops
1750
+ before doing anything else, with `operator_reason: plan_changed`, and lists
1751
+ each changed, added or removed step or hook, with the fields that changed,
1752
+ before and after. This comes ahead of `--retry` too, so the fixed command is
1753
+ offered instead of the old one being run again. The operator picks one of two
1754
+ answers:
1755
+
1756
+ ```console
1757
+ ./ww next TASK-1 --replan --role manager
1758
+ ./ww next TASK-1 --keep-plan --role manager
1759
+ ```
1760
+
1761
+ - `--replan` takes the new definition from the first changed item on. Items
1762
+ before it keep what they did; the first changed item and everything after
1763
+ it are the new ones, with fresh records, and `next` goes on from there.
1764
+ When the first change is in a step or hook that already finished, the run
1765
+ rewinds to it and runs it, and everything after it, again. The page names
1766
+ those steps, and `next --replan` asks the operator to confirm, or takes
1767
+ `--yes` once they have agreed. Earlier attempts move to the run's history,
1768
+ so their artifacts and output stay readable.
1769
+ - `--keep-plan` carries on with the saved plan and is not asked again for
1770
+ the same configuration.
1771
+
1772
+ A change that leaves the run's own workflow as it is, such as a new workflow
1773
+ beside it, is taken silently. A configuration that does not load stops
1774
+ nothing: the run goes on with its saved plan, and `ww lint` shows the error.
1775
+ Two changes cannot be applied to a running task, and the page says why,
1776
+ offering only `--keep-plan`: a change to per-item or per-child stages that
1777
+ the run has already expanded for its items or children, and a rewind past a
1778
+ children step whose child tasks already exist. For those, reset the task and
1779
+ start it again. A worker's pages never stop for a changed plan; the manager
1780
+ decides, between assignments.
1781
+
1782
+ ## Lock cleanup and command attempts
1783
+
1784
+ ww keeps lock sidecar paths in `.ww/locks`; a file there is not evidence of a
1785
+ currently held lock. Remove inactive sidecars with:
1786
+
1787
+ ```console
1788
+ ww-agentic-workflows cleanup
1789
+ ```
1790
+
1791
+ Cleanup waits until active and waiting ww operations have left their lock gate,
1792
+ then removes the old sidecars safely. The execution log records `started`
1793
+ before a command runs and records its final `ok` or `error` result afterwards,
1794
+ so an interrupted operation is visible as a `started` entry without a terminal
1795
+ record.
1796
+
1797
+ ## Projects: one ww instance over several repositories
1798
+
1799
+ Projects are optional. Without them a task works in the project root, where
1800
+ `ww.yaml` and `.ww` live. With a `projects` list in
1801
+ `ww.json`, that root can be a workspace directory above
1802
+ several repositories, and each task or child chooses the repository it works
1803
+ in. Projects live in the JSON settings rather than in `ww.yaml` because
1804
+ their locations are machine-specific, while the workflows are shared:
1805
+
1806
+ ```json
1807
+ {
1808
+ "projects": [
1809
+ {"name": "backend", "path": "./backend", "description": "Python API service."},
1810
+ {"name": "frontend", "path": "./frontend"}
1811
+ ]
1812
+ }
1813
+ ```
1814
+
1815
+ | Key | Required | Meaning |
1816
+ | --- | --- | --- |
1817
+ | `name` | yes | Unique normalized name; the value of `--project`. |
1818
+ | `path` | yes | The directory, resolved against the root when relative. It must exist when a task starts there. |
1819
+ | `description` | no | Shown by `discover` and in the children collection step. |
1820
+
1821
+ A checkout laid out differently can list its own projects in
1822
+ `ww.local.json`; the list replaces the repo's whole, and its
1823
+ relative paths still resolve against the root.
1824
+
1825
+ ```console
1826
+ ww-agentic-workflows start PROJ-123 --workflow feature --project backend ...
1827
+ ww-agentic-workflows add-child EPIC-1 --text "Web part" --project frontend
1828
+ ```
1829
+
1830
+ The chosen project's directory becomes the task's working directory: commands
1831
+ and hooks run there, `{{ww.task.workspace_dir}}` points at it, `{{ww.project.name}}`
1832
+ holds the name, `{{ww.project.dir}}` the directory, and `{{ww.project.names}}` lists
1833
+ every configured project name, joined by commas. `ww-agentic-workflows projects` prints the list as JSON.
1834
+ Configuration, state, and artifacts stay in the root, so one
1835
+ task's requirements, plan, and reviews are kept together even when its children
1836
+ touch several repositories. `discover` lists the projects, and the children
1837
+ collection step lists them so the agent can pass `--project` per child. A handoff
1838
+ successor run keeps its project. A task without `--project` works in the
1839
+ root.
1840
+
1841
+ The `ww/git` extension follows the working directory: branches, worktrees, and
1842
+ commits act on the repository the task works in, and a task in a worktree still
1843
+ resolves to that repository's primary checkout. A repository whose conventions
1844
+ differ from the root's states them in its own settings file, described next.
1845
+
1846
+ **Which configuration is in force.** Every command, child launches included,
1847
+ reads `ww.yaml`, `ww.json`, and their imports from the primary checkout, never
1848
+ from a task's worktree: ww's `.ww` state lives there too. Editing a worktree's
1849
+ copy changes nothing, so when a task's worktree holds a `ww.yaml` whose content
1850
+ differs from the primary's, the task's instruction pages (the `notices` field in
1851
+ JSON) say in one line that the primary checkout's file is the one in force.
1852
+
1853
+ ### A project's own extension settings
1854
+
1855
+ A configured project may carry `ww.json` and
1856
+ `ww.local.json` in its own directory. Of those files ww reads
1857
+ exactly two keys, repo file then local file: the `extensions` section, applied
1858
+ over the root's effective section for the same extension with the same rule as
1859
+ between configuration levels (nested objects merge key by key, any other value
1860
+ replaces the root's), and `task_format`, which replaces the root's for tasks
1861
+ started in that project. A project therefore states only what differs:
1862
+
1863
+ ```json
1864
+ {
1865
+ "task_format": "WEB-{{digit}}",
1866
+ "extensions": {
1867
+ "ww/git": {
1868
+ "base_branches": {"default": "master"},
1869
+ "commit_format": "[{{ww.task.id}}] {{commit_message}}",
1870
+ "worktrees": true,
1871
+ "worktree_dir": "../frontend-worktrees"
1872
+ }
1873
+ }
1874
+ }
1875
+ ```
1876
+
1877
+ With that file, `start --workflow feature --project frontend` without a task
1878
+ ID generates `WEB-1`, `WEB-2`, and so on, and `add-child ... --project
1879
+ frontend` without `--id` names the child the same way under its parent, while
1880
+ tasks started without `--project`, or in a project that sets no format, keep
1881
+ the root's. A project may set `"task_format": "explicit"` to require an ID for
1882
+ its tasks while the root generates them, and the other way round. `lookup`
1883
+ resolves references with the root's format. `discover` names a project's
1884
+ format after its entry when it has one of its own.
1885
+
1886
+ Every other key of a project's file (`enabled`, `runtime`, `executable`,
1887
+ `projects`, `workflows`, and anything else) is ignored here: those describe
1888
+ the project as a ww root of its own, which it may also be when used on its
1889
+ own, and the workspace root owns them. A project file never marks a ww root,
1890
+ and a project without such files, or a task started without `--project`, gets
1891
+ the root's settings unchanged. The root stays the only place that decides
1892
+ which extensions are configured: a project section naming an extension that is
1893
+ not installed is an error that names the project's file, for example
1894
+ `frontend/ww.json (project 'frontend') configures unknown
1895
+ extension 'acme/notes'`.
1896
+
1897
+ The settings follow the directory a step or hook acts on, not the task as a
1898
+ whole, and are frozen into the plan when the task starts like every extension
1899
+ setting. An item working in the task workspace or the project directory
1900
+ (`workdir` `task` or `project`) gets the project's settings; one working in the
1901
+ root (`workdir: root`) gets the root's. Relative paths inside a project's
1902
+ section, such as `worktree_dir`, resolve against that project's repository,
1903
+ never the workspace root. Generated task IDs also reserve a project's worktree
1904
+ paths under the project's settings when the task starts with `--project`.
1905
+
1906
+ `lint` validates every project's sections and, like `plan`, lists the project
1907
+ files it read after the root's:
1908
+
1909
+ ```console
1910
+ $ ww-agentic-workflows lint
1911
+ ww.yaml is valid.
1912
+ Configuration files: ww.yaml, ww.json
1913
+ Project frontend extension settings: frontend/ww.json, frontend/ww.local.json
1914
+ ```
1915
+
1916
+ `plan --project <name>` compiles a workflow as a task in that project would
1917
+ get it, `extension ww/git settings --project <name>` prints the settings such
1918
+ a task's handlers receive, and `discover` names each project's branch
1919
+ strategies when they differ from the root's, and its task ID format when it
1920
+ has one.
1921
+
1922
+ One consequence of per-project worktrees: run ww through the root launcher
1923
+ `./ww` or with `--root`. Invoked from inside a project's checkout or worktree
1924
+ without either, ww resolves the root through the Git common directory to that
1925
+ project's own checkout, not to the workspace.
1926
+
1927
+ ### Choosing where a step works
1928
+
1929
+ By default every step and hook works in the task workspace: the Git worktree
1930
+ when one was selected, otherwise the `--project` directory, otherwise the
1931
+ project root. Some work belongs elsewhere, such as updating shared or
1932
+ git-ignored files in the root checkout rather than in a task worktree. Set
1933
+ `workdir` on a step or on a handler to choose its directory:
1934
+
1935
+ | Value | Directory |
1936
+ | --- | --- |
1937
+ | `task` | The task workspace; the default, unchanged when `workdir` is omitted. |
1938
+ | `project` | The `--project` directory's own checkout, never the worktree made from it; the project root for a task without `--project`. |
1939
+ | `root` | The project root, where the configuration and `.ww` live. |
1940
+
1941
+ ```yaml
1942
+ handlers:
1943
+ - name: refresh-shared-config
1944
+ argv: [make, shared-config]
1945
+ workdir: root
1946
+
1947
+ workflows:
1948
+ - name: feature
1949
+ steps:
1950
+ - develop: Implement the change.
1951
+ - update-local-notes: Record the decisions in {{ww.task.workspace_dir}}/notes/.
1952
+ workdir: root
1953
+ hooks:
1954
+ after_complete:
1955
+ - refresh-shared-config: ~
1956
+ - name: lint
1957
+ argv: [make, lint]
1958
+ workdir: project
1959
+ ```
1960
+
1961
+ An extension handler entry, such as `- ext/ww/git/handlers:git-commit: ~`,
1962
+ may carry `workdir` as well, and nothing else: the extension defines the rest.
1963
+ For `update-local-notes`, the instruction's working-directory `cd` names the
1964
+ root and `{{ww.task.workspace_dir}}` resolves to it; an `argv` or `shell` step
1965
+ runs its command there. Nested steps, loop bodies, and per-item stages inherit
1966
+ the value from their enclosing step and may set their own. A hook does not
1967
+ inherit its step's directory: it uses its own `workdir`, then that of the root
1968
+ handler it names, and otherwise the task workspace, so above
1969
+ `refresh-shared-config` runs in the root and `lint` in the `--project` checkout.
1970
+
1971
+ ww does nothing special with Git for such a step: its changes are not part of
1972
+ the task's commits and are left for the operator.
1973
+
1974
+ ## External task IDs
1975
+
1976
+ An MCP-backed first declared step can establish the task identity without a new
1977
+ Jira-specific setting. When `start` is called without a task ID and that step
1978
+ declares exactly the variable `task_id`, ww starts it as a short bootstrap request before the
1979
+ implicit `init`. Complete it with the ID returned by the tracker; only then does
1980
+ ww create `.ww/tasks/<external-id>/`, run normal start hooks and `init`, and continue
1981
+ the rest of the workflow.
1982
+
1983
+ ```yaml
1984
+ workflows:
1985
+ - name: jira-task
1986
+ steps:
1987
+ - name: create-jira
1988
+ mcp: jira
1989
+ description: Create the Jira issue and return its key.
1990
+ variables:
1991
+ - name: task_id
1992
+ - name: develop
1993
+ description: Implement {{task_id}}.
1994
+ ```
1995
+
1996
+ The bootstrap step must be the first declared flat workflow step and cannot have
1997
+ hooks, nested work, or other variables. Its artifact is retained with the
1998
+ task's run artifacts. If an ID is passed explicitly to `start`, it is
1999
+ authoritative: ww supplies it as `{{task_id}}` and never accepts a replacement
2000
+ from an agent.
2001
+
2002
+ ### Children that bind their own IDs
2003
+
2004
+ The same step lets each child of a parent task obtain its own external ID, for
2005
+ example one Jira story per child of an epic. When the child workflow's first
2006
+ step declares the variable `task_id`, the parent's collection step tells the agent to record
2007
+ children without `--id`; ww names each one by a temporary request ID until it
2008
+ starts:
2009
+
2010
+ ```console
2011
+ ww-agentic-workflows add-child EPIC-1 --text "Story one" --project backend
2012
+ ww-agentic-workflows start-child EPIC-1 REQUEST-20260923101500123456
2013
+ ww-agentic-workflows next REQUEST-20260923101500123456 --role manager
2014
+ ww-agentic-workflows complete REQUEST-20260923101500123456 --role worker \
2015
+ --variable task_id=PROJ-456 --artifact "Created PROJ-456."
2016
+ ```
2017
+
2018
+ `start-child` opens the identity request instead of a run, and the parent's
2019
+ instruction points at it while it is in progress. Completing the request with
2020
+ the tracker's key creates the child as `EPIC-1/PROJ-456` in its project
2021
+ directory, with the identity step already done, and renames the parent's child
2022
+ record. Each story is therefore created by its own step with its own retry and
2023
+ failure handling: a crash halfway through the split cannot leave stories
2024
+ without children, and a retried request that already bound its child simply
2025
+ reports the bound task. A child added with an explicit `--id` skips the request,
2026
+ as an explicit ID does for `start`.
2027
+
2028
+ ## Inheriting a workflow
2029
+
2030
+ A workflow that should do exactly what another does, but branch or merge
2031
+ differently, inherits it instead of repeating it:
2032
+
2033
+ ```yaml
2034
+ workflows:
2035
+ - hotfix: Fix a bug on main.
2036
+ steps:
2037
+ - investigate: Find the cause.
2038
+ - fix: Fix it.
2039
+ - bugfix: Fix a bug on dev.
2040
+ inherit: hotfix
2041
+ ```
2042
+
2043
+ `bugfix` gets `hotfix`'s steps, workflow hooks, modes, runtime, and every other
2044
+ setting. Its own keys replace the copied ones, so it can change its
2045
+ description, runtime, or recommendation; it cannot declare `steps` or `hooks`,
2046
+ because a workflow with other steps is a workflow of its own. A global hook
2047
+ filtered to `workflows: [hotfix]` also runs for `bugfix`, and for anything that
2048
+ inherits `bugfix` in turn. Only the name differs, and that is the point:
2049
+ `ww/git` reads `branch_name_formats.bugfix` and `base_branches.bugfix`, so the
2050
+ copy branches from and names its branches after its own entries. `discover`
2051
+ marks the copy with "Same steps as `hotfix`."
2052
+
2053
+ ## Recommending the next workflow
2054
+
2055
+ A workflow that is usually followed by another names it:
2056
+
2057
+ ```yaml
2058
+ - hotfix: Fix a bug on main.
2059
+ recommended_next_workflow: merge-to-dev
2060
+ steps:
2061
+ - fix: Fix it.
2062
+ ```
2063
+
2064
+ When a `hotfix` run completes, its page tells the agent not to start anything
2065
+ on its own but to ask the operator, through its choice menu, whether to start
2066
+ `merge-to-dev` on the same task, and shows the `start` command to run if they
2067
+ agree. Nothing starts without that answer. An inheriting workflow keeps the
2068
+ recommendation unless it sets its own, or `recommended_next_workflow: ~` to
2069
+ clear it. A handoff workflow (one with a workflow transition) already starts
2070
+ its successor and cannot recommend one.
2071
+
2072
+ ## Rules and checks
2073
+
2074
+ A **rule** is a sentence a step's agent must follow, such as "Keep the public
2075
+ CLI unchanged." A **check** is evidence ww collects itself: a command it runs
2076
+ when the step completes. A rule may carry its own check, and a
2077
+ `before_complete` hook with `on_failure: fix` is one too. The agent that did
2078
+ the work never grades it: a claim that can be a command is run by ww.
2079
+
2080
+ Rules live in Markdown files grouped under the root `rules`, or inline in a
2081
+ step's `rules` list; the [specification](specification.md#rules) has the
2082
+ format. A group applies where its `workflows` and `steps` filters allow (each
2083
+ `"*"` or a list of names, as on hooks), and a step may name a group to get it
2084
+ regardless.
2085
+
2086
+ ```yaml
2087
+ rules:
2088
+ python: [rules/python/]
2089
+ workflows:
2090
+ - name: task
2091
+ steps:
2092
+ - name: develop
2093
+ description: Implement it.
2094
+ rules:
2095
+ - Keep the public CLI unchanged.
2096
+ hooks:
2097
+ before_complete:
2098
+ - argv: [pytest, -q]
2099
+ on_failure: fix
2100
+ ```
2101
+
2102
+ ### On the step page
2103
+
2104
+ Every agent step lists its rules after the work instruction, each with its ID,
2105
+ its globs, and its first sentence; the IDs of rules with a check are collected
2106
+ on one line, "Checked automatically when you complete". The section names
2107
+ `ww check <task>`, to see the checks' result at any time without completing,
2108
+ and `ww rule <task> <id>`, to read a rule in full. The page asks the
2109
+ worker to say in its artifact, under a **Rules** heading, which rules it
2110
+ applied and any deviation. `init`, hooks, and the workflow summary get no
2111
+ rules. In the `auto` runtime the worker's page carries the section. JSON
2112
+ output lists them as `rules`, each with `id`, `summary`, `paths`,
2113
+ `has_command`, `hook`, `check`, `interpretation`, and `missing`.
2114
+
2115
+ A rule without a check is judged after completion by a verifier, never by the
2116
+ worker; the page says so. A rule whose wording already has a converted
2117
+ derived check is listed with the checked ones, and a judged rule shows the
2118
+ store's interpretation under it.
2119
+
2120
+ ### The fix loop
2121
+
2122
+ `complete` runs the step's checks before recording anything. When one fails,
2123
+ the completion is rejected: nothing is saved, the artifact is kept only as a
2124
+ draft, the step stays in progress with its worker, and `complete` exits
2125
+ non-zero. The response is the fix page, `## Fix required: 2 of 5 checks failed
2126
+ (attempt 1 of 3)`, with each failed check's rule text, command, and the last 40
2127
+ lines it printed, then the same completion command; `fix_required` in JSON.
2128
+ The worker fixes the causes and completes again with a revised artifact.
2129
+
2130
+ A failed check always goes back to the worker, never to the operator, until
2131
+ it has failed `max_fixes` times: the rule's own value, else `limits.fixes` in
2132
+ `ww.json`, default 3. Then the task stops with
2133
+ `operator_reason: fix_limit` and the last failures on the page. The operator
2134
+ chooses:
2135
+
2136
+ - `next --retry` gives the worker another round: the count starts again, and
2137
+ the next `next` hands the step back.
2138
+ - `next --force --reason "<why>"` waives the checks: the worker completes
2139
+ the step once more without them, and its artifact records the waiver.
2140
+
2141
+ Both ask for confirmation; `next --yes` confirms for an agent that carries out
2142
+ what the operator said.
2143
+
2144
+ A hook without `on_failure: fix` fails like any handler, stopping the task with
2145
+ `operator_reason: handler_failed`.
2146
+
2147
+ ### The change set
2148
+
2149
+ A check sees the files the step changed in `WW_STEP_CHANGED_FILES`,
2150
+ newline-separated and relative to the step's directory, narrowed to its
2151
+ `paths`; a check whose globs match none of them is not applicable and does not
2152
+ run. ww measures the change set with git: when the step begins it records the
2153
+ tree of everything in the working directory, tracked or not, using a temporary
2154
+ index, so the real index, the stash, and the files are untouched; at
2155
+ completion it takes a second tree and compares. Work that was uncommitted
2156
+ before the step cancels out, a commit made during it still counts, and
2157
+ deleted files, ww's own `.ww` state, and `ww-rule-automation.json` are left
2158
+ out. Without git there is no
2159
+ change set: the globs select every file in the directory, `.git` and `.ww`
2160
+ excepted.
2161
+
2162
+ In a shell check a bare `$WW_STEP_CHANGED_FILES` splits on whitespace, which
2163
+ suits `grep -L foo $WW_STEP_CHANGED_FILES` and `xargs`; paths with spaces need
2164
+ `printf '%s\n' "$WW_STEP_CHANGED_FILES" | xargs -d '\n' …`. A check's full
2165
+ output is a command-output artifact: `ww artifacts` lists it under the step
2166
+ with a `check` field naming the check.
2167
+
2168
+ ### In the artifact
2169
+
2170
+ The step's artifact gains a `## Rules` section after `## Result`: one line per
2171
+ rule with its status, `passed`, `not applicable`, `failed`, which only a
2172
+ waiver lets through, `verified pass (by <verification item>)` for a rule a
2173
+ verifier judged, or `passed (check <name>)` for one a derived check covers;
2174
+ hook checks carry `(hook)`. A rule is `self-declared` only when the operator
2175
+ waived it, which skips its verification too. The section ends with the
2176
+ waived IDs and the operator's reason for each, if any, and how many
2177
+ completions ww rejected before this one.
2178
+
2179
+ ### How a rule becomes a check
2180
+
2181
+ A rule without a command is judged by another agent, a verifier, unless the
2182
+ rule-automation store has a converted check for its wording: then ww runs
2183
+ that check, for every step and task that has the rule. Verifiers only judge.
2184
+ Building checks is the job of `ww-scriptize-rules`, a project task of its
2185
+ own; see [Recording checks outside a task](#recording-checks-outside-a-task).
2186
+
2187
+ What ww knows lives in `ww-rule-automation.json` at the project root, a file
2188
+ to commit, keyed by each rule's text hash; `checks` there are named, and one
2189
+ check may cover many rules, the usual case for an ecosystem tool such as
2190
+ deptrac, PHPStan, import-linter, ruff, or eslint, whose one configuration
2191
+ expresses several rules. When a step begins, each of its rules without a
2192
+ command is settled once: `converted`, checked by its store check where the
2193
+ check's configuration files exist, or `judged`. A store written by an earlier
2194
+ ww may still hold the interim entries verifiers once wrote inside tasks, such
2195
+ as an approach or a proposed check; ww reads them, and their rules are judged.
2196
+
2197
+ When a step's worker completes and its checks pass, ww holds the completion:
2198
+ nothing is recorded, the artifact is kept as a draft, and **verification
2199
+ items** are inserted before the step, one per distinct worker the rules ask
2200
+ for through `agent`, `model`, and `reasoning` (else the step's). Each is its
2201
+ own assignment: under `auto` the manager hands it to a new worker; under
2202
+ `single` the same session performs it, and its page says to read the change
2203
+ as a reviewer would. The verification page lists each rule, the step's
2204
+ changed files and the `git diff` that shows them, and the path of the held
2205
+ artifact. The verifier gives each rule a verdict, `pass` or `fail` with
2206
+ `file:line — what` evidence, as one `--rule-result` per rule,
2207
+ `{"id": "<rule>", "status": "judged", "verdict": "pass"}`, and writes
2208
+ nothing to the store. A failing verdict is a rejected completion: the step
2209
+ goes back to its worker with the fix page, and it counts toward the rule's
2210
+ `max_fixes` like a failed check. Once every rule passes, ww records the held
2211
+ completion as submitted.
2212
+
2213
+ `discover --json` (`rules_notice`) and the first page of `start` say how many
2214
+ declared rules have no check yet and suggest the `ww-scriptize` skill, which starts
2215
+ `ww-scriptize-rules`. The notice never blocks a task; it is left out
2216
+ while `ww-scriptize-rules` is switched off, and on the pages of
2217
+ `ww-scriptize-rules` itself. `ww lint` warns with the IDs of those rules,
2218
+ suggesting `ww-scriptize-rules` only while it is switched on, and
2219
+ lists store entries whose wording no rule has any more; only
2220
+ `ww rules prune`, after listing them and asking the operator, deletes the
2221
+ orphans.
2222
+
2223
+ ### Guiding the checks: `rules.check_guidance`
2224
+
2225
+ `rules.check_guidance` is free text, in the operator's own words, for whoever
2226
+ builds a check, such as how the project runs its tools:
2227
+
2228
+ ```json
2229
+ "rules": {
2230
+ "check_guidance": "Development and quality checks run inside the docker container, on the worktree. Write every new check to run inside the container and act on the worktree, never on the host. Run a check on the host only when it uses nothing but the standard Linux tools, or when the host's tool versions, such as PHP, match the container's."
2231
+ }
2232
+ ```
2233
+
2234
+ `ww rules --json` carries it as written, as `check_guidance`, and
2235
+ `ww-scriptize-rules` follows it for every check it builds; it wins over ww's
2236
+ defaults there. Like any setting, it can live in `ww.local.json` for the
2237
+ operator alone. The `ww-rule` skill and ww's setup workflows honour it for
2238
+ the checks they write, and `ww-suggest` proposes it when `project.md` records
2239
+ a wrapper, such as a container, that checks must go through.
2240
+
2241
+ A project that wants no checks built leaves `ww-scriptize-rules` unused, or
2242
+ switches it off with `"workflows": {"ww-scriptize-rules": {"enabled":
2243
+ false}}`, which also silences the notice; its rules without a command are
2244
+ judged on every completion. A check the team finds wrong can be undone at
2245
+ any time:
2246
+
2247
+ ```console
2248
+ ./ww rules revoke deptrac --reason "too slow for every step"
2249
+ ```
2250
+
2251
+ `rules revoke` shows the check, asks (`--yes` skips the question, and
2252
+ without a terminal it refuses), and rejects the check and the rules it
2253
+ covers, so they are judged by a verifier from then on. It changes only the
2254
+ store: the YAML, the rule files, and the check's configuration files, such
2255
+ as `deptrac.yaml` and an installed dev dependency, stay for you to keep or
2256
+ remove.
2257
+
2258
+ ### Checking early and disputing a check
2259
+
2260
+ A worker need not complete to learn what the checks say: `ww check <task>`
2261
+ runs the step's checks against what it changed so far and prints the
2262
+ failures as the fix page would, or `All checks pass`, plus the rules a
2263
+ verifier will judge once it completes. Nothing is recorded: no attempt
2264
+ counts, and the output is not kept. It exits 1 when a check fails.
2265
+
2266
+ A check can be wrong for a change. After a rejection, instead of bending its
2267
+ work around the check, the worker may dispute it with
2268
+ `ww dispute <task> --rule <id> --reason "<why>"`, naming the ID the fix page
2269
+ shows. The task stops with `operator_reason: check_disputed`; the page shows
2270
+ the check, its last output, and the worker's argument. The operator decides:
2271
+
2272
+ - `next --retry`: the check stands. The rejection still counts toward
2273
+ `max_fixes`, and the step goes back to its worker with the fix page.
2274
+ - `next --force --reason "<why>"`: the check is waived for this step
2275
+ only; the worker completes again without it, and the artifact records the
2276
+ waiver.
2277
+
2278
+ A dispute changes nothing in the rule-automation store. Every dispute is also
2279
+ kept in `.ww/rule-disputes.json`, and `ww lint` lists each disputed ID with
2280
+ how often and where it was last disputed, since a check disputed again and
2281
+ again deserves a look at its wording or command.
2282
+
2283
+ ### Recording checks outside a task
2284
+
2285
+ A check is built once for the project and recorded outside any task's
2286
+ verification, by `ww-scriptize-rules` or by hand:
2287
+
2288
+ ```console
2289
+ ./ww rules convert phpstan --covers php/no-new-services php/typed-returns \
2290
+ --config phpstan.neon --proven \
2291
+ --check-argv -- vendor/bin/phpstan analyse --configuration phpstan.neon
2292
+ ./ww rules decline docs/tone --reason "A matter of review."
2293
+ ```
2294
+
2295
+ `--check-argv -- <arg>...` goes last: everything after `--` is the check's
2296
+ argv, so the tool's own options, such as `--configuration` or `--select E`,
2297
+ are not taken for ww's. Without `--`, `--check-argv` takes the arguments up
2298
+ to the next option.
2299
+
2300
+ `ww-scriptize-rules` (the `ww-scriptize` skill) does this for every rule that
2301
+ needs it, on a branch of its own. `rules convert` shows the check with its command in full, its config files,
2302
+ the rules it covers with where each stands now, and anything else it
2303
+ changes, and asks; `--yes` stands for the operator's answer,
2304
+ and without a terminal it refuses. It creates the check, or replaces an
2305
+ existing one's command, configuration and coverage; a rule it no longer
2306
+ covers goes back to not scriptized. `rules decline` records rules as not
2307
+ convertible: a verifier judges them, and `ww-scriptize-rules` leaves them out
2308
+ from then on. Both
2309
+ take `--dry-run`. `rules --json` gives each rule's `scriptize` state:
2310
+ `command`, `converted`, `not_convertible`, `rejected` or `unscriptized`.
2311
+
2312
+ A converted check runs in a step only when all of its `config` files exist in
2313
+ the directory the step's checks run in. A check built on a branch that is not
2314
+ merged yet therefore does not run in another task's worktree: its rules are
2315
+ judged there, and the step page, like the verifier page, says why, naming
2316
+ the missing file.
2317
+
2318
+ ### Reading the rules
2319
+
2320
+ `ww rule <task> <id>` prints one rule or check of a task as the task's plan
2321
+ froze it: its full text, globs, rule file, command, and the steps that carry
2322
+ it, and for a rule without a command what the store knows about its wording.
2323
+ `ww rules` lists the project's declared groups, with their filters and each
2324
+ rule's ID and first sentence, and each step's own rules; `--json` gives the
2325
+ same for a program. `ww rules prune` deletes store entries no declared rule
2326
+ needs any more, after listing them and asking; `--yes` skips the question.
2327
+ `ww rules revoke <check>` rejects a converted or proposed check and its rules
2328
+ the same way.
2329
+
2330
+ ### Writing rules with the ww-rule skill
2331
+
2332
+ Rules are easiest to add in conversation. Invoked as `/ww-rule`, or when you
2333
+ ask an agent to add or change a rule, the `ww-rule` skill carries the
2334
+ judgment: it reads the groups (`ww rules --json`) and the real workflow and
2335
+ step names (`ww discover`), splits what you said into atomic obligations,
2336
+ tells a new rule from an amendment of an existing one or a change of where a
2337
+ group applies, gives a rule globs only when it names a kind of file and
2338
+ counts what each matches, places it in a group whose filters fit, and
2339
+ rewrites it as one imperative sentence with the rationale below. It shows
2340
+ you one confirmation block, with each rule's ID, group, filters, globs and
2341
+ match counts, sentence, and whether it is new or replaces an existing one,
2342
+ and writes nothing before you answer. `/ww-rule split <file>` does the same
2343
+ for every item of a prose document, in one batch; `/ww-rule from-review`
2344
+ turns the lasting conventions in a task's last review or fix page into
2345
+ rules.
2346
+
2347
+ The skill writes only through `ww rules` commands, which validate every
2348
+ write: each loads the configuration as ww would once the write is made, and
2349
+ when that fails, or the write would not have its effect, every file is put
2350
+ back and the command reports why. `--dry-run` runs the same validation and
2351
+ writes nothing. Nothing is committed.
2352
+
2353
+ ```console
2354
+ $ ww rules add --group php --dir rules/php --workflows task --steps develop
2355
+ Added rule group `php` (rules/php/) to ww-rules.yaml.
2356
+ Added ww-rules.yaml to imports in ww.yaml.
2357
+ Warning: rules/php holds no rule yet, and git does not keep an empty directory: add one with `rules add php --text ...` before committing.
2358
+ Reaches these steps (an agent step's page shows it):
2359
+ - task: develop
2360
+ $ ww rules add php --text "Put every \`*Service.php\` under \`src/Service/\`." --paths "src/**/*.php"
2361
+ Created rules/php/put-every-service-php-under.md: rule `php/put-every-service-php-under`.
2362
+ `src/**/*.php` matches 14 file(s) now.
2363
+ Reaches these steps (an agent step's page shows it):
2364
+ - task: develop
2365
+ ```
2366
+
2367
+ - `rules add <group> --text "<sentence and body>"` creates a rule file in the
2368
+ group's first directory, named after the first five words of its first
2369
+ sentence unless `--id` names it, with `--paths` globs and a check from
2370
+ `--check-shell` or `--check-argv` and `--assert empty|eq:<value>`. It never
2371
+ overwrites a file.
2372
+ - `rules add --group <name> --dir <path>` adds a root group, with optional
2373
+ `--workflows` and `--steps` filters. ww never rewrites
2374
+ `ww.yaml`: the group goes into `ww-rules.yaml` next to
2375
+ it, a file ww owns and rewrites whole, and the repo file gains one entry
2376
+ under `imports` the first time, checked to change nothing else.
2377
+ - `rules edit <id> --text ... --paths ...` replaces a rule file's body or
2378
+ globs and keeps every other line. A new wording has a new hash, so the
2379
+ command says which rule-automation store entry stops matching and, when
2380
+ the old wording had an approved check, that `rules promote` keeps it.
2381
+ - `rules move <id> <group>` moves the file, unchanged, into another group's
2382
+ directory; its wording, and so what the store knows about it, stays.
2383
+ - `rules filter <group> --workflows ... --steps ...` changes where a group of
2384
+ `ww-rules.yaml` applies (`--workflows '*'` writes `"*"`; `--all-workflows`
2385
+ and `--all-steps` remove a filter, which also means all); a group declared elsewhere is yours, and the command says what to
2386
+ write there.
2387
+ - `rules promote <check>` copies an approved store check into the `check`
2388
+ frontmatter of every rule file it covers and removes the check and those
2389
+ rules' entries from the store, since a rule with its own command is never
2390
+ looked up there. It refuses a check that is not converted, or that has a
2391
+ pending revision an earlier ww left, and a rule written in a step's own
2392
+ `rules` list.
2393
+
2394
+ Each command ends with the steps the rule or group now reaches. `ww rules`
2395
+ names the approved store check of a rule without a command of its own
2396
+ (`store_check` in `--json`), which is what a promotion would copy.
2397
+
2398
+ In the `auto` runtime a worker that keeps asking for its page after its
2399
+ assignment ended is not given the manager's own work: its assignment token no
2400
+ longer opens anything (see [Assignment tokens](#assignment-tokens)), and for a
2401
+ `role: manager` or interactive step `instruction --role worker` names the step
2402
+ as the manager's and offers no completion command.
2403
+
2404
+ ### Rules from extensions
2405
+
2406
+ An extension may ship rule groups through its `rules`, each a
2407
+ `RuleGroupContribution` naming the group, its absolute paths or other group
2408
+ names, and optional filters. A project gets them by listing the extension in
2409
+ the root `ww.json` `extensions`, even with an empty section;
2410
+ a group name also declared in the YAML is an error.
2411
+
2412
+ `ww lint` ends with `Rules: N groups, M rules` when the configuration declares
2413
+ any, after a notice for each absolute rule path.
2414
+
2415
+ ## Workflow hooks, variables, and transitions
2416
+
2417
+ ### Workflow hook scopes and ordering
2418
+
2419
+ These are workflow hooks, the lifecycle phases of `ww.yaml`;
2420
+ the agent's own hooks, installed with `ww hook`, are
2421
+ [agent hooks](#agent-hooks). Workflow hooks share the same handler syntax. Global hooks can filter with `workflows`
2422
+ and, for step lifecycle phases, `steps`; workflow hooks can filter step lifecycle
2423
+ phases with `steps`; step hooks cannot use either filter. The workflow boundary
2424
+ positions are `before_start_workflow` and `before_complete_workflow`. They run
2425
+ once in global → workflow order, cannot use `steps`, and cannot be declared at
2426
+ step scope. Step lifecycle positions are `before_start`,
2427
+ `before_complete`, and `after_complete`, and run in global → workflow → step
2428
+ order for every matching step.
2429
+ Step filters accept bare names at any nesting level or slash-separated logical
2430
+ paths such as `plan-and-fix/fix` when only one substep should match.
2431
+ Hooks, rule groups and automatic modes take one filter shape: `workflows` and `steps` are each
2432
+ `"*"` for all or a list of names (`workflows: [task, bugfix]`); a bare name is
2433
+ not a list, and `"*"` cannot be mixed with names. One difference: `[]` on a
2434
+ hook means all, like omission, while on a rule group it means the group applies
2435
+ only where a step names it. The
2436
+ [specification](specification.md#workflow-and-step-filters) has the table.
2437
+
2438
+ A singular hook is written directly as the normal handler shape; there is no
2439
+ `handler` wrapper. A name-only mapping references a catalog handler, while
2440
+ action keys define an inline handler. Use `handlers` only to run multiple
2441
+ ordered handlers under shared `workflows` and `steps` filters. Each grouped
2442
+ entry uses that same handler shape, including the named-entry shorthand, and may
2443
+ carry its own action selection. Put `handoff_to: "{{workflow}}"` directly on a
2444
+ hook to declare a transition.
2445
+
2446
+ ### Variables and metadata
2447
+
2448
+ Interpolations use `{{name}}`, with double braces everywhere. Every value ww
2449
+ provides lives under `ww.`, so a name without it is always a variable a step
2450
+ handed back: `{{ww.task.id}}` is the task's ID and `{{ww.task.workflows}}` the
2451
+ ordered workflow-name list, joined by commas.
2452
+ The core `{{ww.task.workspace_dir}}` variable is always the canonical directory for
2453
+ the task: the project root by default, the configured project directory when a
2454
+ task was started with `--project`, or the selected task checkout when an
2455
+ extension such as `ww/git` supplies one. A step or handler with a
2456
+ [`workdir`](#choosing-where-a-step-works) other than `task` reads the directory
2457
+ it chose instead. `{{ww.project.name}}` is that project's name
2458
+ and `{{ww.project.dir}}` its directory, both empty for a task in the root;
2459
+ `{{ww.project.dir}}` keeps pointing at the project even after a worktree moves
2460
+ the task workspace. `{{ww.project.names}}` lists every configured project name, joined
2461
+ by commas. `{{ww.executable}}` is how the commands ww prints invoke ww, `./ww`
2462
+ or the configured [`executable`](#choosing-the-ww-binary), so a step's text can
2463
+ name a ww command as ww's own pages do: ``Run `{{ww.executable}} onboarding` ``.
2464
+ Values under `{{ww.<namespace>.*}}` come from a configured extension, such
2465
+ as [`ww/git`'s branch](#template-values-from-wwgit); a variable may not be
2466
+ named `ww` or start with `ww.` (or `__`).
2467
+ A handler's `variables` list declares what the step hands back, read later as
2468
+ `{{name}}`. Each entry supports either `name` plus an optional `description`,
2469
+ or the same compact `name: description` shorthand as handlers and steps, and
2470
+ the performer passes it with `complete --variable name=<value>`. A bare string,
2471
+ `- name`, is a value an automatic action returns itself. A step's values are
2472
+ available to its completion hooks and later plan items.
2473
+
2474
+ When several automatic completion hooks request the same variable with the
2475
+ same description, ww asks for it once and gives that value to each hook.
2476
+ For example, project and workflow commit hooks share one `commit_message`.
2477
+ Different descriptions for the same name are a conflict: the error names the
2478
+ variable and both requesting plan items. A supplied `--variable` still appears
2479
+ only once in the completion command.
2480
+
2481
+ ```yaml
2482
+ variables:
2483
+ - workflow: The workflow name corresponding to one of {{ww.task.workflows}}.
2484
+ ```
2485
+
2486
+ Use `saves` on an agent-owned handler or step to retain values. Each entry is a
2487
+ prefixed path with an instruction: `metadata.<path>` keeps a value across
2488
+ workflow runs of one task, `project_metadata.<path>` shares it with every task
2489
+ in the project, `documents.<name>` updates a [document](#documents), and
2490
+ `item.field.<name>` sets a [custom item field](#custom-item-fields). The path
2491
+ after the prefix is the storage path, and the prefix is the scope:
2492
+
2493
+ ```yaml
2494
+ steps:
2495
+ - name: create-jira
2496
+ mcp: jira
2497
+ description: Create the issue and retain its ID.
2498
+ saves:
2499
+ - metadata.integrations.jira.issue_id: The ID of the created Jira issue.
2500
+ - name: inspect-jira
2501
+ description: Inspect {{ww.metadata.integrations.jira.issue_id}}.
2502
+ ```
2503
+
2504
+ The completion instruction includes every required value as a named argument,
2505
+ its path written as in `saves` without the `metadata.` prefix:
2506
+
2507
+ ```console
2508
+ ww-agentic-workflows complete TASK-123 --role worker \
2509
+ --metadata integrations.jira.issue_id="PROJ-456" --artifact="<result>"
2510
+ ```
2511
+
2512
+ Shell and argv handlers automatically retain stdout when they declare
2513
+ metadata entries in `saves`. For example, this handler finds an existing PR or
2514
+ creates one, then stores its URL for later steps:
2515
+
2516
+ ```yaml
2517
+ handlers:
2518
+ - create-github-pr: ~
2519
+ shell: |-
2520
+ set -eu
2521
+ branch=$1
2522
+ base=$2
2523
+ repo=$(gh repo view --json nameWithOwner --jq .nameWithOwner)
2524
+ url=$(gh pr list --repo "$repo" --head "$branch" --base "$base" \
2525
+ --state open --json url --jq '.[0].url // empty')
2526
+ if [ -z "$url" ]; then
2527
+ url=$(gh pr create --repo "$repo" --head "$branch" --base "$base" --fill)
2528
+ fi
2529
+ printf '%s\n' "$url"
2530
+ args: ["{{ww.git.branch}}", "{{ww.git.base_branch}}"]
2531
+ saves:
2532
+ - metadata.github.pr_url: The pull request URL.
2533
+ ```
2534
+
2535
+ Later steps use `{{ww.metadata.github.pr_url}}`. ww saves the full stdout with
2536
+ outer whitespace removed only after successful execution and assertions.
2537
+ Send diagnostic messages to stderr to keep them out of the saved value.
2538
+ `project_metadata.<path>` and `append: true` also work: an append entry receives
2539
+ the whole output as one list value. Interrupted publication resumes from the
2540
+ committed result without rerunning the command.
2541
+
2542
+ Metadata is task-scoped rather than workflow-scoped. `ww` stores it as a nested
2543
+ object under `metadata` in `.ww/tasks/<task-id>/metadata.json`; a later run can use the
2544
+ same `{{ww.metadata.<path>}}` reference. Metadata leaves are strings. A new value
2545
+ may replace the same path, while a leaf/object path collision is rejected.
2546
+ Inspect the complete object as JSON with `ww-agentic-workflows metadata TASK-123`.
2547
+
2548
+ A leaf declared with `append: true` is a list that grows across completions and
2549
+ runs. Each completion passes the path once per value, or not at all, and ww
2550
+ appends the values to what is stored, dropping repeats, without touching other
2551
+ keys. The leaf interpolates as a comma-separated list, and as an empty string
2552
+ before anything was saved, so a prompt never shows a raw placeholder. This is
2553
+ how one task remembers the pull request threads it already handled across
2554
+ several review passes:
2555
+
2556
+ ```yaml
2557
+ - process_pull_request: Create one work item per unresolved reviewer thread.
2558
+ items:
2559
+ report: Reply in the thread and resolve it.
2560
+ saves:
2561
+ - metadata.pull_request.handled_comments: The root comment id of the thread you just resolved.
2562
+ append: true
2563
+ - get_pull_request_comments: >-
2564
+ Threads whose root comment id is in {{ww.metadata.pull_request.handled_comments}}
2565
+ are already handled; list them as needing no work.
2566
+ ```
2567
+
2568
+ ```console
2569
+ ww-agentic-workflows complete TASK-123 --role worker \
2570
+ --metadata pull_request.handled_comments=4711 \
2571
+ --metadata pull_request.handled_comments=4718 \
2572
+ --artifact="<result>" --summary="<handover>"
2573
+ ```
2574
+
2575
+ Under `items`, `saves` belongs to the built-in `handle-item` stage; with
2576
+ configured stages, declare it on the stage that produces the value.
2577
+
2578
+ Use a `project_metadata.<path>` entry for values shared by every task in the
2579
+ project. Project metadata has an explicit interpolation namespace so the
2580
+ ownership of a value is visible where it is consumed:
2581
+
2582
+ ```yaml
2583
+ steps:
2584
+ - name: discover-environment
2585
+ description: Determine the shared staging URL.
2586
+ saves:
2587
+ - project_metadata.environments.staging.url: The staging environment URL.
2588
+ - name: deploy
2589
+ description: Deploy to {{ww.project_metadata.environments.staging.url}}.
2590
+ ```
2591
+
2592
+ The completion command still uses `--metadata`, with the path written as in
2593
+ `saves`: `--metadata project_metadata.environments.staging.url=<value>`. Project metadata is stored as nested JSON in
2594
+ `.ww/metadata.json` and can be inspected with
2595
+ `ww-agentic-workflows metadata --project`. Project metadata is resolved live;
2596
+ copy a value into task metadata when a task needs a stable snapshot. The `ww.`
2597
+ namespace of project metadata is ww's own, holding its [onboarding
2598
+ state](#onboarding-state); a `saves` entry under `project_metadata.ww.` is a
2599
+ configuration error. Metadata
2600
+ is plain runtime state and should not be used for secrets.
2601
+
2602
+ Every workflow also receives ww's built-in `update-workflow-summary` handler as
2603
+ its final `before_complete_workflow` action. It asks the agent for a concise
2604
+ goal/result summary, and ww writes that value to the task run ledger when the
2605
+ run completes. No `ww.yaml` configuration is needed. Its instruction
2606
+ lists every ordinary step's handover of this run in order, each with its
2607
+ artifact, and tells the agent to build the summary from those alone, so the
2608
+ summary cannot borrow counts or statuses from other runs or stale material. It
2609
+ requests the run's ordinary worker selection (`auto`), unlike `init`, which
2610
+ requests `cheapest` / `low`; `builtins.workflow_summary` in
2611
+ `ww.json` overrides that.
2612
+
2613
+ ## Interactive steps
2614
+
2615
+ Some work is a conversation with the person operating ww: agreeing an
2616
+ architecture, or performing a manual test case and reporting what happened.
2617
+ Mark such a step `interactive: true`:
2618
+
2619
+ ```yaml
2620
+ - think_about_architecture: >-
2621
+ Set up the architecture. Discuss it with the operator: listen, ask
2622
+ questions, clarify edge cases.
2623
+ interactive: true
2624
+ ```
2625
+
2626
+ The conversation comes first and is held in the session that can talk to the
2627
+ operator. The agent presents, asks, listens, responds to questions and
2628
+ corrections, and records nothing while they talk. Clear contextual completion,
2629
+ such as "done", "I'm done", "looks good, continue", or an appropriate final
2630
+ choice, lets the agent finish; if intent is ambiguous, it asks naturally
2631
+ whether to continue or finish. "Done for today" can mean pause, leaving the
2632
+ interaction open to resume later. One command records both sides, verbatim,
2633
+ and ends the interaction:
2634
+
2635
+ ```console
2636
+ ww-agentic-workflows interact TASK-123 --role manager --transcript - --end <<'EOF'
2637
+ Agent: Proposed: a listener dispatches a queued job per upload.
2638
+ Operator: Resize through the queue; upload never waits.
2639
+ Agent: Agreed: the upload returns before any image work starts.
2640
+ EOF
2641
+ ```
2642
+
2643
+ `--transcript` reads a file, or stdin with `-`. A line starting with `Agent:`
2644
+ or `Operator:` (also bold, as `**Operator:**`, in any case) starts an entry,
2645
+ and the lines up to the next marker belong to it; text before the first
2646
+ marker is refused. The entries keep their order and carry one recording time.
2647
+ `--operator-said` and `--agent-said` record a single entry, and `--end` alone
2648
+ ends an interaction whose entries are already recorded.
2649
+
2650
+ Every entry is appended to one file per task,
2651
+ `.ww/tasks/<task-id>/interactions.md`, never rewritten, each headed by the time,
2652
+ run, step, the item when the step is a per-item stage, and speaker, so the file
2653
+ reads as the task's whole history of operator involvement;
2654
+ `ww-agentic-workflows interactions TASK-123` prints it. The step's page shows
2655
+ the conversation recorded for it so far.
2656
+ Completing an interactive step is refused until at least one entry was recorded
2657
+ and the interaction was ended. The step's artifact and handover are written as
2658
+ usual; what goes into them is the agent's judgement.
2659
+
2660
+ For work where the operator wants to follow each action and edit, set
2661
+ `explicit: true` on a workflow or step. The agent describes each meaningful
2662
+ operation before it begins and shows the concrete edits for every changed file
2663
+ afterward. Large edits can use a focused diff artifact; the agent still names
2664
+ each changed file and redacts secrets. Structural groups, loops, item stages,
2665
+ and child stages inherit the setting, and a nested step can turn it off with
2666
+ `explicit: false`. The compiled plan preserves the resolved value across
2667
+ resumption. WW-owned automatic handlers continue to show their command and
2668
+ result through ww's existing output.
2669
+
2670
+ When the operator's answer is one of a few outcomes, declare them as `choices`
2671
+ and ww turns them into a real pick rather than free text:
2672
+
2673
+ ```yaml
2674
+ items:
2675
+ analyze: Show the test case to the operator.
2676
+ interactive: true
2677
+ choices:
2678
+ - pass: The test case passed.
2679
+ - fail: The test case failed; no comment.
2680
+ - fail and give comment: The test case failed; the operator explains why.
2681
+ - skip: Skip this test case.
2682
+ ```
2683
+
2684
+ The page lists choices in order and tells the agent to use the host's native
2685
+ choice tool when available, following its actual schema, and otherwise show a
2686
+ numbered list in chat. For Codex, inspect the available question-tool schema
2687
+ and use its supported structured options when offered; use a text-only
2688
+ question only when required by that tool. Keep the pick pending until the
2689
+ operator explicitly answers. A timeout, dismissal, or preselected value is not
2690
+ an answer. The named tools for other
2691
+ integrations include `AskUserQuestion` in Claude Code, `ask_user` in Gemini
2692
+ CLI, `AskQuestion` in Cursor, `ask_question` in Antigravity, and
2693
+ `ask_user_question` in Grok CLI. Kimi, DeepSeek, and custom agents get the
2694
+ numbered list. The tool names come from the
2695
+ [askmux](https://github.com/iShaldam/askmux) question-tool matrix (MIT,
2696
+ Copyright (c) 2026 iShaldam) and the Gemini CLI documentation. The pick goes in the
2697
+ same recording call, `interact --transcript - --choice "<label or number>"
2698
+ --end`, a comment the operator adds is part of the transcript, and ending the
2699
+ interaction is refused until a choice was recorded. The chosen label is kept on the step record and in the interactions
2700
+ file.
2701
+
2702
+ The limitation to know: a delegated worker is a subagent and cannot talk to the
2703
+ operator. An interactive step is therefore always performed by the session that
2704
+ holds the conversation, the manager in the `auto` runtime: it is a
2705
+ `role: manager` step, and the step's profile, agent, model, and reasoning
2706
+ are ignored. For a manual-testing workflow, put `interactive: true` on the
2707
+ per-item stage: the manager presents each test case, waits for the operator's
2708
+ result, records it, ends the interaction, and completes the item.
2709
+
2710
+ When a session ends in the middle of a conversation, the `interrupt` hook
2711
+ recovers what it can (see [Agent hooks](agent-hooks.md)). For Claude Code and
2712
+ Codex it reads the session's own transcript file, keeps the operator's typed
2713
+ messages and the agent's text replies since the step's attempt started, and
2714
+ appends them to the interactions file under the speakers `operator (recovered)`
2715
+ and `agent (recovered)`. The next session's notice says how many entries were
2716
+ recovered, and the step's page shows them, so the agent continues from the
2717
+ last unanswered point. The transcript formats are the agents' internal ones,
2718
+ so recovery is best effort; for other agents the conversation is not recorded
2719
+ and the notice says to ask the operator where they were.
2720
+
2721
+ ### The operator page
2722
+
2723
+ A per-item stage declared with `interactive: page` is answered in the
2724
+ browser, on an answer sheet over every item of the run, and ww applies the
2725
+ answers itself. It is valid on one per-item stage per `items` step, because the page is shaped for items: other structures would
2726
+ need a page of their own, and none exists yet.
2727
+
2728
+ ```yaml
2729
+ items:
2730
+ analyze: Show the test case to the operator.
2731
+ interactive: page
2732
+ choices:
2733
+ - pass: The test case passed.
2734
+ - fail: The test case failed; the operator explains why.
2735
+ ```
2736
+
2737
+ The page is an extra on top of the engine. The core knows it by
2738
+ `interactive: page` alone: the stage's page tells the agent to run one command, and
2739
+ everything else lives in the `operator_ui` package, which drives the task
2740
+ only through the public commands an agent uses.
2741
+
2742
+ ```console
2743
+ ww-agentic-workflows interact TASK-123 --role manager --await
2744
+ ```
2745
+
2746
+ The command applies any answers left over from an earlier wait, serves the
2747
+ page on `127.0.0.1` for as long as it runs, opens the browser unless a tab is
2748
+ already polling, waits, and then applies what was answered. It returns when
2749
+ every item is answered, when the operator presses "I'm done for now", when
2750
+ the operator closes the page, or after `WW_OPERATOR_WAIT` seconds with
2751
+ nothing new. The port is derived from the task ID, so the tab survives
2752
+ between waits and reconnects by itself; `WW_OPERATOR_PORT` fixes it. There
2753
+ is no daemon. After the step's page, the command prints how the wait ended,
2754
+ which items it applied, how many are answered, and whether to wait again or
2755
+ stop.
2756
+
2757
+ How the agent runs the wait depends on what its shell can do, and the step's
2758
+ page says which, from the same kind of per-agent table as the choice
2759
+ mechanisms. Claude Code has a background shell, so the page tells it to run
2760
+ the command with `run_in_background` and go on with the conversation: the
2761
+ operator can talk to the agent in the session while the page is open, and
2762
+ the command's output reaches the agent when the wait ends. Such a wait may
2763
+ be long, so the page puts `WW_OPERATOR_WAIT=1800` in front of the command.
2764
+ While it runs, the agent must not run commands that change the task, because
2765
+ the wait applies the answers the moment it ends; `status` and `instruction`
2766
+ are fine. Any other agent blocks on the command, so the default wait is `90`
2767
+ seconds, under its shell timeout, and the agent runs it again while items
2768
+ remain.
2769
+
2770
+ The page lists every item with its text and analysis. The operator answers
2771
+ the items in any order, each with the stage's choices when it declares them
2772
+ and a comment, and can revise an answer until ww has applied it. An answer
2773
+ is recorded the moment it is given, as one atomic replacement of the answer
2774
+ sheet, `.ww/operator-ui/<task-id>.json`, under the task lock and before the
2775
+ browser is told it went through. It does not touch the task's state. A
2776
+ failed submission comes back to the page as an error next to the item and
2777
+ the draft stays; an answer given while no agent is waiting is kept in the
2778
+ tab and sent when a wait is back, and is lost if the tab is closed first.
2779
+ Drafts survive a reload. The sheet remembers when its task was created, so a
2780
+ sheet left behind by a reset task is discarded rather than applied to the
2781
+ task that reuses the ID.
2782
+
2783
+ Applying walks the plan in order from the current stage. For every
2784
+ `interactive: page` stage whose item has an answer on the sheet, ww records the pick and the
2785
+ comment and ends the interaction with `interact`, writes the answer onto
2786
+ the item with `update-item` as its `actual_solution` (the pick, then the
2787
+ comment after a colon) and marks it resolved for a `handle-item` or
2788
+ `item_phase: resolve` stage and reported for a `handle-item` or
2789
+ `item_phase: report` stage, completes the stage with `complete` and an artifact written from the
2790
+ answer, and only then takes the answer off the sheet, so a wait that is
2791
+ killed mid-way leaves at most a stale entry that the next wait drops. A
2792
+ document the stage promised to update is the one thing ww cannot write: the
2793
+ printed result names such documents and tells the agent to record the
2794
+ answers of the applied items in them first. When the operator closes the
2795
+ page, the result tells the agent not to open it again on its own. The walk stops at the first stage whose item has no answer, at any
2796
+ stage that is not an `interactive: page` stage, and wherever ww needs the agent. Items are
2797
+ therefore completed one by one in plan order whatever order the operator
2798
+ answered in; an answer for a later item waits on the sheet. The applied
2799
+ answer is what an agent would have recorded: the stage's chosen label, the
2800
+ comment in the interactions file, and the artifact. The agent's loop is:
2801
+ wait, read the printed result, wait again while items remain.
2802
+
2803
+ A pause is the operator saying they are done for now, from the page or
2804
+ recorded by the agent with `interact --pause`. It is kept on the task, and
2805
+ the page's pause is recorded after the answers given before it were applied.
2806
+ The step's page then tells the agent to stop, without waiting again, and to
2807
+ show the step with `instruction` when the operator returns. Only the
2808
+ operator's own words lift a pause: an answer on the page or an
2809
+ operator entry, whether from a transcript, `--operator-said` or `--choice`, not the
2810
+ agent's words and not the ending of a step.
2811
+
2812
+ ## Documents
2813
+
2814
+ Metadata holds small values that steer a workflow. A document is the durable,
2815
+ free-format counterpart: a file a workflow builds up and returns to across
2816
+ runs, such as the test cases derived from an issue that a second run refines
2817
+ after the issue changed and a `build-test-report` workflow reads later.
2818
+ Declare documents once at the root; a task-scoped document lives under the
2819
+ task directory, a `scope: project` one under `.ww/documents`, and a `scope:
2820
+ user` one in the user configuration directory, shared by every project of the
2821
+ user, unless `path` places it elsewhere in the
2822
+ project (for a user document, elsewhere in the user directory), for example
2823
+ `documentation/issues/{{ww.task.id}}/notes.md`, which then resolves inside the
2824
+ task's worktree when the run has one:
2825
+
2826
+ ```yaml
2827
+ documents:
2828
+ - test_cases: The test cases derived from the issue, kept current across runs.
2829
+ workflows:
2830
+ - name: derive-tests
2831
+ steps:
2832
+ - derive: Analyze the issue and derive test cases.
2833
+ saves:
2834
+ - documents.test_cases: One checklist item per case; keep items that still hold.
2835
+ - name: build-test-report
2836
+ steps:
2837
+ - report: Build the report from {{ww.documents.test_cases}}.
2838
+ ```
2839
+
2840
+ A step whose `saves` names a `documents.<name>` entry sees a "Documents to update" section
2841
+ naming each document, its absolute path, whether it exists yet, and the
2842
+ instruction. Its worker edits the file in place, the one exception to the rule
2843
+ against writing under `.ww`. On completion ww checks that each promised file
2844
+ exists and journals who updated it, run, step, time, and content hash, in the
2845
+ task's `documents.json` or the project's. `{{ww.documents.<name>}}` resolves to the
2846
+ absolute path for the current filesystem, like the worktree path does, so a
2847
+ task started on the host reads correctly inside a container. `reset` removes a
2848
+ task's journal and the documents kept under its `.ww` directory, as it removes
2849
+ the task's metadata; a document declared with a `path` is the workflow's own
2850
+ file and stays in place.
2851
+
2852
+ `ww-agentic-workflows documents TASK-123` lists every declared document with
2853
+ its scope, path, whether it exists, and its last update; without a task ID it
2854
+ lists the project-scoped ones.
2855
+
2856
+ ## Artifacts and dependencies
2857
+
2858
+ Agent-owned steps save their full Markdown result as an artifact by default.
2859
+ Use `artifact: false` for work that has no durable output. A loop wrapper also
2860
+ saves the final result supplied by its successful stop command as its main
2861
+ artifact; `artifact: false` on the wrapper disables that file independently of
2862
+ its body-step artifacts. `artifact_from` names an earlier artifact-producing step
2863
+ and adds that artifact to the later step's instruction; execution still
2864
+ follows the written step order.
2865
+
2866
+ A nested step, in a group, a loop body, an assessment outcome, or a per-item
2867
+ stage, may also name an earlier step of any enclosing level. The nearest match
2868
+ wins: an earlier sibling first, then an earlier step of the parent's level,
2869
+ and so on up to the workflow's top-level steps and `init`. An outcome may name
2870
+ its assessment and a per-item stage its `items` step, whose work has finished
2871
+ by then, and gets that step's own artifact; a loop body cannot name its own
2872
+ running loop. The instruction names the dependency by its step path, such as
2873
+ `review/check`, which is how `ww artifacts` lists it.
2874
+
2875
+ `artifact_from` may also name a plain group, which saves no artifact of its
2876
+ own, or an assessment from a step after it. The later step then gets the
2877
+ artifact of the latest step inside it that saved one in its current round:
2878
+ for an assessment, a step of the outcome that was chosen. Loop rounds,
2879
+ per-item stages, and per-child stages inside count, so the latest round's
2880
+ artifact wins, and a loop wrapper that saves its own result counts when it
2881
+ completes. A container that is itself inside a loop counts only the current
2882
+ iteration of that loop: an artifact an earlier round saved is never handed
2883
+ over. The instruction names that step and gives the artifact's file path.
2884
+ When the chosen outcome saved nothing, for example an outcome with no steps of
2885
+ its own, an assessment supplies its own artifact if it saved one. Otherwise
2886
+ the instruction
2887
+ says that no artifact is available and the step goes on without one.
2888
+ Validation accepts such a dependency only when some path inside it can save an
2889
+ artifact; an assessment whose outcomes cannot supplies its own answer.
2890
+
2891
+ ```yaml
2892
+ handlers:
2893
+ - name: analyse
2894
+ steps:
2895
+ - assess:
2896
+ question: Is the cause clear?
2897
+ outcomes:
2898
+ positive: {handler: investigate}
2899
+ negative: {handler: research}
2900
+ workflows:
2901
+ - name: medium-task
2902
+ steps:
2903
+ - name: analysis
2904
+ handler: analyse
2905
+ - name: develop
2906
+ description: Implement the change.
2907
+ artifact_from: analysis # investigate's or research's artifact
2908
+ ```
2909
+
2910
+ Filesystem artifact names begin with each step's one-based declaration ordinal
2911
+ among its siblings. Nested containers reset the ordinal for their children, so
2912
+ a workflow with `init`, `investigate`, and a `plan-and-fix` group is stored as:
2913
+
2914
+ ```text
2915
+ steps/
2916
+ 01-init.md
2917
+ 02-investigate.md
2918
+ 03-plan-and-fix/
2919
+ 01-plan.md
2920
+ 02-fix.md
2921
+ ```
2922
+
2923
+ Loop bodies add an `iteration-NN` directory beneath each loop wrapper. Every
2924
+ round therefore keeps its own step and hook artifacts instead of overwriting
2925
+ the files from an earlier round:
2926
+
2927
+ ```text
2928
+ steps/
2929
+ 02-review-and-fix.md
2930
+ 02-review-and-fix/
2931
+ iteration-01/
2932
+ 01-review.md
2933
+ 02-fix.md
2934
+ iteration-02/
2935
+ 01-review.md
2936
+ ```
2937
+
2938
+ These prefixes describe the workflow hierarchy, not the flat lifecycle-plan
2939
+ position. Hook artifacts use their plan position within the target step's
2940
+ `.hooks/<phase>/` directory.
2941
+
2942
+ ```yaml
2943
+ workflows:
2944
+ - name: task
2945
+ steps:
2946
+ - name: research
2947
+ description: Investigate the change and record the findings.
2948
+ - name: implement
2949
+ description: Implement the change.
2950
+ artifact_from: research
2951
+ - name: review-and-fix
2952
+ loop:
2953
+ - name: fix
2954
+ description: Fix what the review found.
2955
+ artifact_from: research
2956
+ break: Nothing is left to fix.
2957
+ - name: notify
2958
+ description: Report that implementation is complete.
2959
+ artifact: false
2960
+ ```
2961
+
2962
+ ## Dynamic per-item workflows
2963
+
2964
+ One `items` step collects a runtime list of work items and then runs a fresh
2965
+ lifecycle for every item. The step's own work is the collection: the agent
2966
+ splits it into items with `add-item`. In the minimal form, every item then gets
2967
+ one built-in stage that analyzes, resolves, and reports it:
2968
+
2969
+ ```yaml
2970
+ workflows:
2971
+ - name: handle-feedback
2972
+ steps:
2973
+ - review: Review the pull request.
2974
+ items: Split based on the comments retrieved from the Bitbucket pull request.
2975
+ ```
2976
+
2977
+ The string is splitting guidance shown to the collecting agent. Use `items: ~`
2978
+ when no guidance is needed.
2979
+
2980
+ The built-in stage can take guidance for each of its phases without declaring
2981
+ stages. Under `items`, `analyze`, `resolve`, and `report` are
2982
+ strings appended to the `handle-item` prompt as "When analyzing it", "When
2983
+ resolving it", and "When reporting the outcome"; the item is still handled in
2984
+ one pass with one artifact:
2985
+
2986
+ ```yaml
2987
+ - process_pull_request: Split the work by comment and sub-comment.
2988
+ items:
2989
+ assignment: together
2990
+ report: Reply in the same Bitbucket comment thread, then resolve the thread.
2991
+ ```
2992
+
2993
+ To control the stages, list them under `items.steps`. Mark stages with
2994
+ `item_phase: analyze`, `item_phase: resolve`, or `item_phase: report` when they
2995
+ update those standard item fields. `item_phase` is valid only on an acting
2996
+ step inside a per-item stage (nested loops, groups, and assessment outcomes
2997
+ count). On an `assess` step itself, or on a step outside any per-item stage, it
2998
+ would do nothing, so validation and `lint` reject it: put it on the outcome
2999
+ steps that do the work. `steps: []` collects items without processing them, for
3000
+ example when a later step reads them.
3001
+
3002
+ ```yaml
3003
+ workflows:
3004
+ - name: handle-feedback
3005
+ steps:
3006
+ - review: Review the pull request.
3007
+ items:
3008
+ description: Split by pull request comment.
3009
+ steps:
3010
+ - analyze: Analyze this comment.
3011
+ item_phase: analyze
3012
+ - fix: Resolve this comment.
3013
+ item_phase: resolve
3014
+ model: opus
3015
+ - reply: Report the outcome.
3016
+ item_phase: report
3017
+ ```
3018
+
3019
+ Worker settings cascade from the `items` step, to `items`, to each stage. The
3020
+ step's `agent`, `model`, `reasoning`, `profile`, and `role` apply to
3021
+ collection and are inherited by the stages; the same keys under `items` apply
3022
+ only to the stages, and a stage's own value wins.
3023
+
3024
+ ### One worker per item or for all items
3025
+
3026
+ In the `auto` runtime, `assignment` decides how many manager-dispatched
3027
+ assignments the per-item stages become. By default one worker keeps going
3028
+ through every stage of every item:
3029
+
3030
+ ```yaml
3031
+ - review: Review the change and record each finding as an item.
3032
+ items:
3033
+ assignment: per_item # or together
3034
+ model: sonnet
3035
+ steps:
3036
+ - analyze: Analyze this finding.
3037
+ item_phase: analyze
3038
+ - fix: Resolve this finding.
3039
+ item_phase: resolve
3040
+ - reply: Report the outcome.
3041
+ item_phase: report
3042
+ ```
3043
+
3044
+ - `together`, the default, keeps one worker for every stage of every item.
3045
+ - `per_item` keeps one worker for all stages of one item; the next item is a
3046
+ new assignment.
3047
+ - `per_step` hands every stage back to the manager.
3048
+
3049
+ The manager's preview names the scope before dispatching. The first stage of
3050
+ the assignment tells the worker which stages it covers and to do them one at a
3051
+ time. Each later stage arrives as a short instruction with only the new stage's
3052
+ work and its completion command, because the worker already has the role,
3053
+ workspace, profile, and item context. Every stage is still completed, saved,
3054
+ and recoverable on its own, so `next`, `status`, reloads, and interrupted-hook
3055
+ recovery behave exactly as with separate assignments. Because one worker
3056
+ performs the shared stages, a stage that requests a different agent, model,
3057
+ reasoning, or profile, or is the manager's (`role: manager`), starts a new assignment,
3058
+ exactly as a loop body step does. The setting has no effect in
3059
+ the `single` runtime.
3060
+
3061
+ ### Several passes over the same items
3062
+
3063
+ A workflow has one item collection, and each `items` step is a pass over it.
3064
+ Analysis and fixes that are cheaper together can run once between passes,
3065
+ while every source comment is still checked and reported on its own:
3066
+
3067
+ ```yaml
3068
+ - collect: Record one item per comment with its stable source ID.
3069
+ items:
3070
+ steps: []
3071
+ - analyze-together: Analyze all collected comments together.
3072
+ - confirm-analysis: Reuse the collected items.
3073
+ items:
3074
+ steps:
3075
+ - analyze: Reuse the shared analysis; confirm and fill gaps.
3076
+ item_phase: analyze
3077
+ - fix-together: Implement and verify the fixes for all analyzed items.
3078
+ - finish: Reuse the collected items.
3079
+ items:
3080
+ steps:
3081
+ - verify-resolution: Verify the result and record actual_solution.
3082
+ item_phase: resolve
3083
+ - report: Report the result for this original comment.
3084
+ item_phase: report
3085
+ ```
3086
+
3087
+ Each pass expands its own stages when its collection step completes, for the
3088
+ items recorded by then; an item added later joins the next pass. Passes share
3089
+ the items' records, so the analysis written by the batch step is there for the
3090
+ quick analyze checkpoints, and nothing an earlier pass recorded is cleared.
3091
+ Inside a loop a pass is expanded again every round.
3092
+
3093
+ A pass with `steps: []` only collects or reconciles; `items: ~` stays the
3094
+ shorthand for a single pass with the whole built-in lifecycle.
3095
+
3096
+ Leaving a pass requires only what its stages declare: an analyze stage needs
3097
+ the item's analysis, a resolve stage its actual solution and `resolved`, a
3098
+ report stage `reported`, and the built-in `handle-item` stage both `resolved`
3099
+ and `reported`. So an analysis-only pass can lead into a batch fix, and a
3100
+ workflow that only analyzes can end there. A linked comment reuses its
3101
+ canonical item's analysis and fix but is reported itself. When a pass ends
3102
+ with an `assess` stage, the check waits for the answer: the chosen outcome's
3103
+ work is part of the pass, and an outcome that stops the workflow ends the run.
3104
+ A pass whose items still lack something stops for the operator with
3105
+ `operator_reason: pass_incomplete`, naming each item and what it lacks; record
3106
+ it with `update-item` and run `next --retry`. `next --force` is refused at a
3107
+ pass gate; the missing values must be recorded. An `items` step nested inside
3108
+ another's per-item stages is rejected.
3109
+
3110
+ Automatic saves into item fields belong to per-item stages. A command on the
3111
+ collecting `items` step itself cannot save item fields (one output cannot be
3112
+ distributed among several items), and that is rejected; every field a stage
3113
+ declares receives the same whole trimmed output. A report stage in which ww runs
3114
+ nothing, one done by the agent alone, still marks its item reported with
3115
+ `update-item --reported=true`.
3116
+
3117
+ `persistent`, `identity`, and `unique` describe the one collection, so the
3118
+ first `items` step decides them. Later passes leave them out or repeat the
3119
+ same values; a later pass that sets a different value fails `lint` and names
3120
+ both steps.
3121
+
3122
+ ### Items that persist across runs
3123
+
3124
+ Some item lists are the task's, not one run's: the test cases of a manual
3125
+ test plan are the same in round one and round two. Declare the flow
3126
+ `persistent` and the items outlive the run:
3127
+
3128
+ ```yaml
3129
+ - collect: >-
3130
+ Read the test cases in docs/test-cases.md. Compare them with the stored
3131
+ items and make the items match: add missing cases, remove cases that
3132
+ are gone, reword cases that changed. Keep the item ID equal to the
3133
+ case's heading.
3134
+ items:
3135
+ persistent: true
3136
+ interactive: page
3137
+ choices:
3138
+ - pass: The test case passed.
3139
+ - fail: The test case failed; the operator explains why.
3140
+ ```
3141
+
3142
+ ww keeps the task's canonical list in `.ww/tasks/<task-id>/items.json` and
3143
+ refreshes it whenever a run adds, changes, or resolves an item, so it always
3144
+ holds the latest outcome of every item. Each run still keeps its own copy in
3145
+ its record, so round one's results stay readable after round two. A new run,
3146
+ whether the task is started again or a handoff enters the workflow, starts
3147
+ from the stored items with their outcome fields cleared: every round is a
3148
+ fresh round over the same cases.
3149
+
3150
+ The collection step then reconciles instead of splitting. Its page lists
3151
+ the stored items and carries the commands to make the list match the
3152
+ source: `add-item` for new cases, `remove-item` for cases that are gone,
3153
+ and `update-item --text` to reword one. Removing and rewording are allowed only while the
3154
+ collection step is in progress, and an item that other items refer to
3155
+ cannot be removed. Stable IDs matter: an item that changed is reworded under
3156
+ its ID, not replaced, so its history lines up across rounds. When nothing
3157
+ changed, the agent completes the step as it is. With nothing stored yet, the
3158
+ same page reads as a plain split.
3159
+
3160
+ ```console
3161
+ ww-agentic-workflows remove-item TASK-123 --id case-7
3162
+ ww-agentic-workflows update-item TASK-123 --id case-3 --text "Upload a 25 MB image."
3163
+ ```
3164
+
3165
+ To start over from the source, `start --fresh-items` forgets the stored
3166
+ items before the run begins, and the collection step splits anew. `reset`
3167
+ removes the store with the task.
3168
+
3169
+ ### Custom item fields
3170
+
3171
+ An item carries the standard analysis and outcome fields, and any custom
3172
+ fields a workflow needs: the ID of the source comment, the ID of the reply
3173
+ posted for it, a flag. Values are strings. They are set with the item
3174
+ commands, several in one call, and read back with `item` or `items`:
3175
+
3176
+ ```console
3177
+ ww-agentic-workflows add-item TASK-123 --id c1 --text "Rename it." --field bitbucket_comment_id=100
3178
+ ww-agentic-workflows update-item TASK-123 --id c1 --field bitbucket_reply_id=200 --field bitbucket_thread_resolved=true
3179
+ ww-agentic-workflows item TASK-123 --by bitbucket_reply_id=200
3180
+ ```
3181
+
3182
+ A step declares the fields it sets as `item.field.<name>` entries of `saves`,
3183
+ beside its metadata and document entries, and ww refuses to complete the step
3184
+ while any of them is empty on the step's item, or on every item when the
3185
+ step is the collection. Such a save needs an item: it belongs on an `items`
3186
+ step or on a step, hook, or reused handler that runs within a per-item stage.
3187
+ `lint` rejects one on an ordinary step, such as a batch fix between passes,
3188
+ which updates items with `update-item` instead:
3189
+
3190
+ ```yaml
3191
+ - reply: Reply in the Bitbucket thread, then resolve it.
3192
+ item_phase: report
3193
+ saves:
3194
+ - item.field.bitbucket_reply_id: The ID of the reply you posted.
3195
+ - item.field.bitbucket_thread_resolved: Set to true once the thread is resolved.
3196
+ ```
3197
+
3198
+ Per-item stage prompts can read the stage's own item: `{{ww.item.id}}`,
3199
+ `{{ww.item.text}}`, `{{ww.item.field.<name>}}`, and the lifecycle values
3200
+ `{{ww.item.processed_item}}`, `{{ww.item.proposed_solution}}`,
3201
+ `{{ww.item.actual_solution}}`, `{{ww.item.resolved}}`, `{{ww.item.reported}}`,
3202
+ and `{{ww.item.reference_to_id}}`. `resolved` and `reported` render as `true`
3203
+ or `false`; every other value renders as the empty string while unset (a
3204
+ `reference_to_id` is empty for an item that links to none). The specification's
3205
+ [Item values](specification.md#item-values) is authoritative. The effective current
3206
+ step's `{{ww.choices}}` value is a JSON array of configured choice labels in
3207
+ order, or `[]` when there are none. Use it as guidance in prompts or provided-
3208
+ variable descriptions; ww does not validate a supplied value against labels.
3209
+
3210
+ Two flow-level rules make deduplication a refusal rather than a hope:
3211
+
3212
+ ```yaml
3213
+ items:
3214
+ persistent: true
3215
+ identity: bitbucket_comment_id
3216
+ unique: [bitbucket_comment_id, bitbucket_reply_id]
3217
+ ```
3218
+
3219
+ `identity` names the field every new item must carry. `unique` is one pool
3220
+ of values across the listed fields: a value may appear once over all items,
3221
+ in the run and, when the flow is persistent, in the task's stored items, so a
3222
+ reply posted in round one cannot become an item in round two, and no two
3223
+ items can claim the same comment. `add-item` and `update-item` refuse a
3224
+ duplicate and name the item that holds it. The collection page states both
3225
+ rules and the stored list shows each item's fields, so reconciling is a
3226
+ diff on real IDs.
3227
+
3228
+ During collection and processing, use the item commands to maintain the
3229
+ structured records:
3230
+
3231
+ ```console
3232
+ ww-agentic-workflows add-item TASK-123 --id comment-1 \
3233
+ --text="The error path is not tested."
3234
+ ww-agentic-workflows items TASK-123
3235
+ ww-agentic-workflows item TASK-123 --id comment-1
3236
+ ww-agentic-workflows update-item TASK-123 --id comment-1 \
3237
+ --processed-item="Missing failure-path coverage" \
3238
+ --proposed-solution="Add an integration test"
3239
+ ww-agentic-workflows update-item TASK-123 --id comment-1 \
3240
+ --actual-solution="Added the integration test" --resolved=true --reported=true
3241
+ ```
3242
+
3243
+ `update-item` confirms the saved item and returns the current worker completion
3244
+ command.
3245
+
3246
+ ## Worker-controlled loop control
3247
+
3248
+ A step can wrap an ordered `loop` body. Individual agent-owned body steps may
3249
+ declare natural-language `break` or `continue` conditions, so review and remediation stay
3250
+ visible as separate assignments and more than one worker may be authorized to
3251
+ end the loop. Body steps retain hooks, profiles, artifacts, nesting, and item
3252
+ collection.
3253
+
3254
+ ```yaml
3255
+ workflows:
3256
+ - task: ~
3257
+ steps:
3258
+ - review-and-fix: ~
3259
+ max_rounds: 5
3260
+ loop:
3261
+ - review: Review the implementation and report meaningful findings.
3262
+ break: The review has no meaningful findings.
3263
+ - fix: Fix the reported findings.
3264
+ ```
3265
+
3266
+ After doing a break-enabled step, the worker evaluates its break gate. When the
3267
+ condition holds, it uses the displayed command instead of ordinary completion;
3268
+ the command accepts the same artifact, variable, metadata, and execution fields
3269
+ as `complete`:
3270
+
3271
+ ```console
3272
+ ww-agentic-workflows loop TASK-123 --break --role worker \
3273
+ --artifact="<whole result in Markdown>"
3274
+ ```
3275
+
3276
+ The breaking step's completion hooks still run before ww skips the remaining
3277
+ body. A step may instead declare `continue`; its worker command runs completion
3278
+ hooks and then skips the rest of the current body, restarting from the first
3279
+ body step:
3280
+
3281
+ ```console
3282
+ ww-agentic-workflows loop TASK-123 --continue --role worker \
3283
+ --artifact="<whole result in Markdown>"
3284
+ ```
3285
+
3286
+ If no worker breaks or continues, the body repeats automatically. Each repetition gives
3287
+ automatic actions fresh operation IDs, while retries within one round
3288
+ retain their existing idempotency identity.
3289
+
3290
+ ### One worker per loop round
3291
+
3292
+ In the `auto` runtime, `assignment` decides how the body of one round is
3293
+ split into worker assignments, like `assignment` does for per-item
3294
+ stages:
3295
+
3296
+ - `per_round`, the default, keeps consecutive body steps in one assignment
3297
+ while they resolve to the same agent, model, reasoning, and profile. The
3298
+ worker completes each step with its own command and receives the next step
3299
+ straight away. The repeat boundary always ends the assignment, so the
3300
+ manager still sees every round and still receives the limit escalation.
3301
+ - `per_step` hands every body step back to the manager.
3302
+
3303
+ Body steps keep their own `profile`, `agent`, `model`, and `reasoning`
3304
+ overrides under `per_round`; a step whose settings differ from the
3305
+ worker's simply starts a new assignment. That is deliberate: a `code-reviewer`
3306
+ review followed by a `developer` fix stays two workers, so the reviewer never
3307
+ fixes its own findings, while a fix-until-green loop under one profile runs as
3308
+ one worker per round.
3309
+
3310
+ ```yaml
3311
+ - run-tests: ~
3312
+ assignment: per_round
3313
+ profile: quick-developer
3314
+ loop:
3315
+ - test: Run the test suite.
3316
+ break: No failures found.
3317
+ - fix-tests: Fix the failures.
3318
+ ```
3319
+
3320
+ Every body step's work instruction names the loop and the round. The first
3321
+ round is described as building on the work of the steps before the loop; a
3322
+ later round tells the worker to concentrate on the previous rounds of this
3323
+ loop, not on the whole task, and shows the `artifacts` command that lists the
3324
+ earlier iteration directories. The setting has no effect in the `single`
3325
+ runtime.
3326
+
3327
+ ww limits loops to three rounds by default. Set a different project-wide
3328
+ positive integer as `limits.rounds` in `ww.json`, or
3329
+ override one wrapper with `max_rounds` in `ww.yaml`:
3330
+
3331
+ ```json
3332
+ {"limits": {"rounds": 4}, "extensions": {}}
3333
+ ```
3334
+
3335
+ ```yaml
3336
+ - review-and-fix: ~
3337
+ max_rounds: 7
3338
+ loop:
3339
+ - review: Review the implementation.
3340
+ - fix: Fix the findings.
3341
+ ```
3342
+
3343
+ The effective limit is saved in the compiled plan. When the completed round
3344
+ count reaches it, ww does not begin another round or provide a continuation
3345
+ command. The response reports `awaiting_operator` with `operator_reason:
3346
+ loop_limit` and explicitly tells the manager to escalate the saved results and warning to the user for manual
3347
+ resolution. It also shows the operator's one way past the limit: once the user
3348
+ has resolved or accepted the remaining findings, `next --force --reason`
3349
+ leaves the loop, records the reason on the repeat boundary, and continues with
3350
+ the steps after the loop wrapper. Nothing else starts another round; a
3351
+ further round needs a higher `max_rounds`.
3352
+
3353
+ ## Parent and child tasks
3354
+
3355
+ A step with `children` splits a parent task into child tasks, then runs every
3356
+ child with one workflow; the parent continues after the last child completes.
3357
+ Child tasks live under the parent task directory and are intentionally limited
3358
+ to one level for now.
3359
+
3360
+ ```yaml
3361
+ workflows:
3362
+ - name: feature
3363
+ steps:
3364
+ - name: split-work
3365
+ description: Split the feature into stories.
3366
+ children:
3367
+ description: One child per story. # optional splitting guidance
3368
+ workflow: implementation
3369
+
3370
+ - name: implementation
3371
+ steps:
3372
+ - name: implement
3373
+ description: Implement this child task.
3374
+ ```
3375
+
3376
+ While the step collects, record each child:
3377
+
3378
+ ```console
3379
+ ww-agentic-workflows add-child TASK-123 --text "Implement the API"
3380
+ ```
3381
+
3382
+ Without `--id`, ww uses the configured `task_format`, the child's project's
3383
+ own when `--project` names one that sets it, else the root's, or the usual
3384
+ generated `TASK-<timestamp>` ID when no format is configured. `{{timestamp}}`,
3385
+ `{{digit}}`, and `{{uuid}}` are the supported placeholders. Supply `--id TASK-123.1` when you
3386
+ want a stable, human-chosen child label instead. When the child workflow's first
3387
+ step declares the variable `task_id`, omit `--id` and the child obtains its own ID from that
3388
+ step; see [children that bind their own IDs](#children-that-bind-their-own-ids).
3389
+ `--project <name>` runs the child in a configured project directory.
3390
+
3391
+ Once the step completes, the parent waits at `split-work/children`, the
3392
+ item that runs the children; start a chosen child:
3393
+
3394
+ ```console
3395
+ ww-agentic-workflows start-child TASK-123 TASK-123.1
3396
+ ```
3397
+
3398
+ A child that has not started yet can still change its text or project (and,
3399
+ at any time, its custom `--field` values):
3400
+
3401
+ ```console
3402
+ ww-agentic-workflows update-child TASK-123 TASK-123.1 --text "Implement the API and its client"
3403
+ ```
3404
+
3405
+ `update-child` works while the child is `pending`, during the collecting step
3406
+ and while the parent waits, and refuses a child that has started, naming its
3407
+ status. The child's first step records the text it has when it starts as its
3408
+ requirements.
3409
+
3410
+ The child runs as `TASK-123/TASK-123.1`, with its own hooks, items, and run
3411
+ history. The parent waits while a child is active. Completing the final child
3412
+ automatically resumes and completes the parent's normal lifecycle; the
3413
+ collecting step's completion hooks run after its children, and the parent's
3414
+ later steps follow.
3415
+
3416
+ ### Per-child parent stages
3417
+
3418
+ When the parent has its own work to do around each child, such as adjusting the
3419
+ next slice to what earlier ones landed, reviewing the child's branch, and
3420
+ merging it, give `children` a list of `steps` instead of a `workflow`. The
3421
+ parent then runs those stages once per child, strictly one child at a time.
3422
+ Exactly one stage carries `workflow:`; inside `children` that stage starts the
3423
+ current child with that workflow and waits for it, it does not hand off (a
3424
+ handoff is `handoff_to`, which cannot run inside `children.steps`). The stages
3425
+ are assigned one per step (`children.assignment: per_step`, the only value
3426
+ built; `per_child` is reserved).
3427
+
3428
+ ```yaml
3429
+ workflows:
3430
+ - name: roadmap
3431
+ steps:
3432
+ - read-plan: Add one child per slice of the plan, with the slice's full text.
3433
+ children:
3434
+ steps:
3435
+ - refine: Adjust {{ww.child.text}} to what earlier slices landed.
3436
+ role: manager
3437
+ - implement:
3438
+ workflow: task
3439
+ - review: Review {{ww.child.git.branch}} against the slice.
3440
+ artifact_from: implement
3441
+ role: manager
3442
+ break: The roadmap is done; nothing else is worth building.
3443
+ - land: Merge {{ww.child.git.branch}} into {{ww.git.branch}}.
3444
+ - close-plan: Record what the roadmap delivered.
3445
+
3446
+ - name: task
3447
+ steps:
3448
+ - develop: Implement {{ww.task.id}}.
3449
+ ```
3450
+
3451
+ A stage that only runs a command can be automatic: `land: ~` with
3452
+ `argv: [git, merge, --no-ff, "{{ww.child.git.branch}}"]` and `on_failure: fix`
3453
+ runs in the task workspace, and a conflict hands the agent a repair assignment
3454
+ carrying the command's output (see `on_failure` above), so the agent resolves the
3455
+ merge instead of performing every landing.
3456
+
3457
+ With two children `A` and `B`, the parent runs `refine`, `implement` (child `A`
3458
+ runs its `task` workflow), `review`, and `land` for `A`, then the same four for
3459
+ `B`, then `close-plan`. `ww plan --workflow roadmap` shows the stages under
3460
+ `read-plan/{child}`; once the children are collected they become
3461
+ `read-plan/child-1/refine`, `read-plan/child-2/refine`, and so on.
3462
+
3463
+ - A stage reads its child as `{{ww.child.id}}`, `{{ww.child.text}}`,
3464
+ `{{ww.child.project}}`, `{{ww.child.field.<name>}}`, and the child task's own
3465
+ extension values, such as `{{ww.child.git.branch}}` and
3466
+ `{{ww.child.git.base_branch}}`. Its page also names the current child and,
3467
+ while it has not started, how to change it. Stages before `implement` run
3468
+ before the child task exists, so they may read only its ID, text, project,
3469
+ and fields; reading `{{ww.child.git.branch}}` there is a configuration error.
3470
+ A value that is not available yet, such as a field the child does not carry,
3471
+ stops the task before the stage starts, for the operator to retry or skip;
3472
+ the error names the `update-child` command that sets a missing field.
3473
+ - `refine` runs before the child starts, so it may rewrite it with
3474
+ `update-child TASK-123 A --text "..."`; the child's `init` records that text
3475
+ as its requirements.
3476
+ - Children carry custom fields like items: `add-child ... --field area=parser`,
3477
+ and `update-child ... --field area=lexer` at any time.
3478
+ - Add `start_child` beside `workflow:` to let ww start the child itself:
3479
+ `implement: {workflow: task, start_child: {model: "{{ww.child.field.model}}"}}`.
3480
+ It takes `workflow`, `runtime`, `model`, `reasoning` and `agent`, each a template
3481
+ over the child's record, read when the stage runs; an omitted or empty value
3482
+ inherits as `start-child` does. Record the settings with
3483
+ `update-child ... --field model=...` (or `add-child --field`) in the stages
3484
+ before. The manager's `next` starts the child and shows its page; a failed
3485
+ launch stops the stage for the operator, and `next --retry` starts it again.
3486
+ - Without `start_child`, the `implement` stage shows `start-child TASK-123 A` for its own child only;
3487
+ its artifact is the child's workflow summary, which `review` reads through
3488
+ `artifact_from: implement`.
3489
+ - In `auto`, the parent's manager also manages the child: starting it returns
3490
+ the child's page, the child's steps are ordinary worker assignments the same
3491
+ manager dispatches, and the completed child's page names the parent command
3492
+ to continue with.
3493
+ - A child that fails stops the parent for the operator, as in the simple form.
3494
+ - `break` on a stage ends the loop over the children: every remaining stage is
3495
+ skipped and each child that has not started is marked `skipped`. A `break`
3496
+ inside a `loop` within a stage ends that loop only; a `loop` inside the
3497
+ stages runs its own rounds for each child.
3498
+ - A step with `children.steps` cannot sit inside a `loop`; the simple
3499
+ `children: {workflow: ...}` form can.
3500
+
3501
+ Steps may contain recursive `steps` without a depth limit. The plan remains
3502
+ flat: each leaf action uses a hierarchical ID such as `parent/child`, with its
3503
+ immediate `parent` recorded in JSON and shown in Markdown. Parent steps are
3504
+ stateful grouping boundaries: they become in-progress with their first child and
3505
+ complete when every child and parent completion hook completes.
3506
+
3507
+ A workflow such as `decide-on-workflow` hands off when it ends with a workflow
3508
+ transition that starts a successor and never returns. The transition itself
3509
+ makes it a handoff workflow; there is no flag to set. The transition is a step
3510
+ with `handoff_to` beside its name, usually interpolating a variable an earlier
3511
+ step handed back; the same key as the last `after_complete` hook of the last
3512
+ step is equivalent. `workflow:` on a step is rejected naming `handoff_to`:
3513
+ `workflow` only ever means "run a child with this workflow", under
3514
+ `children`:
3515
+
3516
+ ```yaml
3517
+ - name: decide-on-workflow
3518
+ steps:
3519
+ - classify: Decide which workflow fits this request.
3520
+ artifact: false
3521
+ variables:
3522
+ - workflow: One of {{ww.task.workflows}}, other than decide-on-workflow.
3523
+ - route: ~
3524
+ handoff_to: "{{workflow}}"
3525
+ ```
3526
+
3527
+ Loading the configuration rejects more than one transition and a transition
3528
+ anywhere but last: a transition step that is not the last top-level step, or
3529
+ that a completion hook would follow; a transition hook on another step, in
3530
+ another phase, or followed by another `after_complete` hook; and a transition
3531
+ hook at global or workflow scope. The plan marks the workflow as a handoff. Execution
3532
+ completes the selection workflow's run, records
3533
+ `<original-workflow>=<next-workflow>` in authoritative task state, and starts the
3534
+ successor as the task's next numbered run — so `ww instruction <task>` lists both,
3535
+ each with its own plan, state and artifacts.
3536
+
3537
+ Handoffs are deliberately limited, and the limits are accepted for now:
3538
+
3539
+ - A workflow has exactly one transition, and it is the last thing the workflow
3540
+ does; there is no routing to different workflows from different steps. Choose
3541
+ the target dynamically with `{{workflow}}` instead, or branch earlier with an
3542
+ assessment.
3543
+ - A task hands off once. The successor cannot hand off again; a second
3544
+ transition fails with "already has a handoff marker".
3545
+ - A workflow cannot call another workflow and continue afterwards. Use child
3546
+ tasks to run another workflow per piece of work, or a reusable `handler` step
3547
+ tree to share a phase between workflows.
3548
+
3549
+ General nested workflow definitions remain deferred and are rejected when
3550
+ `ww.yaml` is loaded.
3551
+
3552
+ ## Extensions
3553
+
3554
+ An extension adds handlers, modes, and commands to ww. It is identified as
3555
+ `vendor/name` and is always referenced by its full address, never by a bare
3556
+ name:
3557
+
3558
+ ```yaml
3559
+ workflows:
3560
+ - name: task
3561
+ modes:
3562
+ - ext/ww/git/modes:conventional-commits
3563
+ steps:
3564
+ - name: work
3565
+ kind: prompt
3566
+ hooks:
3567
+ before_start:
3568
+ - name: ext/ww/git/handlers:is-git-clean
3569
+ after_complete:
3570
+ - name: ext/ww/git/handlers:git-commit
3571
+ ```
3572
+
3573
+ Because every reference is qualified, installing an extension can never change
3574
+ what a name already means in your project: nothing it provides takes effect
3575
+ until you name it. Extensions do not provide hooks — a hook decides *when* work
3576
+ runs against a particular workflow and step, which is your configuration's
3577
+ business, not the extension's.
3578
+
3579
+ An extension handler runs inside ww rather than as a shell command, so it can
3580
+ remember what it did. `ww/git`'s `git-commit` commits and then records the
3581
+ commit, and `commits` reads that back. It stages the task workspace first; when
3582
+ nothing is staged, for example after a review round that needed no fix, it
3583
+ succeeds without a commit and without invoking project pre-commit hooks such as
3584
+ Husky or lint-staged:
3585
+
3586
+ ```console
3587
+ ww-agentic-workflows extensions # what is installed, and what it provides
3588
+ ww-agentic-workflows extension ww/git commits # every commit ww made
3589
+ ww-agentic-workflows extension ww/git commits TASK-123 # just this task's
3590
+ ```
3591
+
3592
+ With Git worktrees enabled, branch creation and worktree selection are separate
3593
+ handlers. The default project workflow runs them together, but you may move
3594
+ `create-worktree` to a later hook when you want to use the primary checkout
3595
+ instead:
3596
+
3597
+ ```yaml
3598
+ hooks:
3599
+ before_start_workflow:
3600
+ - name: ext/ww/git/handlers:start-task-branch
3601
+ - name: ext/ww/git/handlers:create-worktree
3602
+ ```
3603
+
3604
+ `start-task-branch` only creates or adopts the branch. `create-worktree` is a
3605
+ no-op when worktrees are disabled. If the primary checkout is already on the
3606
+ exact task branch rendered from the workflow's configured branch name format,
3607
+ either handler selects it as the task workspace rather than creating a separate
3608
+ worktree. No conventional branch names such as a base or development branch
3609
+ participate in that decision.
3610
+
3611
+ Each extension owns `.ww/ext/<vendor>/<name>/`, reached only through the store
3612
+ object it is handed, and every write goes through ww's lock layer. Use
3613
+ `store.update_text(name, callback)` when new content depends on existing content;
3614
+ it holds one lock across the complete read–modify–write sequence.
3615
+
3616
+ ### Configuring one
3617
+
3618
+ Extension settings live in `ww.json`, ww's project config file —
3619
+ separate from `ww.yaml`, which describes what a workflow *does*:
3620
+
3621
+ ```json
3622
+ {
3623
+ "extensions": {
3624
+ "ww/git": {
3625
+ "commit_format": "{{ww.task.id}}: {{commit_message}}",
3626
+ "base_branches": {
3627
+ "default": "main",
3628
+ "bugfix": "develop",
3629
+ "task": {"argv": ["./scripts/base-branch", "{{ww.task.lane}}"]}
3630
+ },
3631
+ "separate_branch": true,
3632
+ "branch_name_formats": {
3633
+ "default": "feature/{{ww.task.id}}",
3634
+ "bugfix": "hotfix/{{ww.task.id}}"
3635
+ },
3636
+ "worktrees": false
3637
+ }
3638
+ }
3639
+ }
3640
+ ```
3641
+
3642
+ `"ww/git"` is the canonical key; a bare `"git"` also works when only one
3643
+ installed extension has that name. An extension receives its own section and
3644
+ nothing else from the file, and validates it itself — ww cannot know a third
3645
+ party's schema. A section naming no installed extension is an error rather than
3646
+ ignored, because a block that silently applies to nothing looks configured and
3647
+ is not.
3648
+
3649
+ The formats read `{{ww.task.id}}`, `{{ww.task.workflow}}`, `{{ww.task.lane}}`,
3650
+ `{{ww.task.run}}`, and, in `commit_format`, `{{commit_message}}`.
3651
+ `{{ww.task.lane}}` is the workflow whose branch handling the task takes: the
3652
+ workflow's `hooks_from` when it has one, else the workflow itself, the name
3653
+ `branch_name_formats` and `base_branches` are looked up by.
3654
+
3655
+ For `ww/git`, `ww-agentic-workflows extension ww/git settings` prints what actually resolved,
3656
+ which is the first thing to run after editing the file; `--project <name>`
3657
+ prints what a task in that configured project receives.
3658
+
3659
+ When `worktrees` is enabled, generated task IDs reserve any existing path
3660
+ rendered by `worktree_dir` and `worktree_name_format`. For example, an existing
3661
+ `worktrees/TASK-1` makes the next `{{digit}}`-formatted task use `TASK-2`, rather
3662
+ than adopting that checkout for a new task. A generated ID also skips one
3663
+ `ww/git` still holds: a branch record for it, or an existing branch its branch
3664
+ name formats render for it, so a cleaned-up `.ww/tasks` does not hand an old
3665
+ task's ID, and with it that task's history, to a new one.
3666
+
3667
+ `base_branches` maps exact workflow names to base branches, and its `default`
3668
+ entry covers every other workflow, the same shape as `branch_name_formats`. A
3669
+ `ww-scriptize-rules` task always uses the required `default` entry, even when
3670
+ an entry names that workflow explicitly. A
3671
+ repository under a configured project with a base branch of its own sets
3672
+ `base_branches` in [its own settings file](#a-projects-own-extension-settings).
3673
+ Each value may be either a literal branch name or an
3674
+ object with a non-empty `argv` array. An argv command runs directly without a shell in
3675
+ the project root; its single non-empty stdout line becomes the base branch.
3676
+ Arguments may interpolate `{{ww.task.id}}`, `{{ww.task.workflow}}`, `{{ww.task.lane}}`, and `{{ww.task.run}}`;
3677
+ a script choosing the base by workflow reads `{{ww.task.lane}}`, so a workflow with `hooks_from` gets its lane's base.
3678
+ The resolved base is recorded with the task branch so retries, worktree creation,
3679
+ and return-to-base use one stable value. The record is trusted only while it
3680
+ names the branch being resolved and that branch exists; a record of another
3681
+ branch, or of a deleted one, is left behind by an earlier task under the same
3682
+ ID, and the configured base is resolved instead. A child task always uses its
3683
+ recorded parent task branch instead. `reset` drops the task's branch and commit
3684
+ records, and its children's.
3685
+
3686
+ `branch_name_formats` names the available branch naming strategies. Without an
3687
+ override, `start-task-branch` first looks for a strategy matching the workflow
3688
+ name and then falls back to `default`. Select another configured strategy for a
3689
+ single run by name:
3690
+
3691
+ ```console
3692
+ ww-agentic-workflows start TASK-123 --workflow task --agent codex \
3693
+ --requirements="Fix the requested bug." --branch-strategy bugfix
3694
+ ```
3695
+
3696
+ The selection is persisted with the run, so later or retried branch and
3697
+ worktree handlers use the same format. An unknown explicit strategy fails
3698
+ instead of silently falling back.
3699
+
3700
+ `on_signing_failure` says what `git-commit` and `merge-branch` do when git
3701
+ cannot sign a commit, for example because the signing agent is locked while the run goes on
3702
+ unattended. `operator`, the default, stops for the operator as for any failed
3703
+ handler. `unsigned` commits once more with `commit.gpgsign=false`, records
3704
+ `signed: false` for the commit, and says so in the handler's result; any
3705
+ other commit error still stops. Set it where the unattended run happens, such
3706
+ as the user or local settings file:
3707
+
3708
+ ```json
3709
+ { "extensions": { "ww/git": { "on_signing_failure": "unsigned" } } }
3710
+ ```
3711
+
3712
+ #### What `ww/git` does with those settings
3713
+
3714
+ | Handler | Settings it acts on |
3715
+ | --- | --- |
3716
+ | `git-commit` | `commit_format`, `on_signing_failure` |
3717
+ | `merge-branch` | `commit_format`, `on_signing_failure` |
3718
+ | `start-task-branch` | `base_branches`, `separate_branch`, `branch_name_formats`, `worktrees`, `worktree_dir`, `worktree_name_format` |
3719
+ | `return-to-base-branch` | `base_branches`, `separate_branch` |
3720
+ | `remove-task-worktree` | `worktrees` |
3721
+ | `is-git-clean` | — |
3722
+
3723
+ A suggested wiring, with `is-git-clean` before `start-task-branch` so a branch is
3724
+ never cut from a dirty tree:
3725
+
3726
+ ```yaml
3727
+ hooks:
3728
+ before_start_workflow:
3729
+ - name: ext/ww/git/handlers:is-git-clean
3730
+ - name: ext/ww/git/handlers:start-task-branch
3731
+ before_complete_workflow:
3732
+ - handlers:
3733
+ - ext/ww/git/handlers:git-commit: ~
3734
+ - ext/ww/git/handlers:return-to-base-branch: ~
3735
+ ```
3736
+
3737
+ `remove-task-worktree` is left out on purpose: a worktree is where the work
3738
+ happened, so deleting it the moment a workflow ends should be your choice, not a
3739
+ default. `ww-agentic-workflows extension ww/git branches [TASK-ID]` shows what was opened, and
3740
+ `commits` what was committed.
3741
+
3742
+ #### Landing a branch with `merge-branch`
3743
+
3744
+ `merge-branch` merges a branch into the task's current branch, in the task
3745
+ workspace, with `git merge --no-ff`, so a "land" stage is ww's work instead of
3746
+ an agent's. It takes two `args`, the branch to merge and the merge message;
3747
+ both may use templates, and the message goes through `commit_format` like a
3748
+ `git-commit` subject:
3749
+
3750
+ ```yaml
3751
+ children:
3752
+ steps:
3753
+ - implement:
3754
+ workflow: task
3755
+ - name: ext/ww/git/handlers:merge-branch
3756
+ args: ["{{ww.child.git.branch}}", "Land slice {{ww.child.id}}"]
3757
+ ```
3758
+
3759
+ It refuses a workspace with uncommitted changes, a branch that does not
3760
+ exist, a detached `HEAD` (the merge would land on no branch), and a workspace
3761
+ where a rebase, `git am`, cherry-pick or revert is in progress. On a conflict it runs `git merge --abort` and fails naming the
3762
+ conflicting files, so the task stops for the operator with the workspace as
3763
+ it was. When git cannot sign the merge commit it follows `on_signing_failure`
3764
+ exactly as `git-commit` does: it stops, or, with `unsigned`, aborts the
3765
+ half-made merge, merges once more without a signature, and records
3766
+ `signed: false`. It reports success only when no merge is left in progress
3767
+ (no `MERGE_HEAD`) and `HEAD` is a merge commit of the branch. The merge commit's
3768
+ sha is its output, `{{merge_commit}}`, and the commit is recorded with the
3769
+ merged branch; `commits` lists it. A branch already contained in the current
3770
+ one merges nothing and succeeds with an empty `merge_commit`.
3771
+
3772
+ Like `git-commit`, it puts ww's operation ID in a `WW-Operation` trailer, so a
3773
+ retry after an interruption finds the merge commit the earlier attempt made
3774
+ instead of merging again. A merge that attempt left half-done (its own
3775
+ trailer in `MERGE_MSG`) is aborted and redone only while it is untouched:
3776
+ every conflicted file still carries its conflict markers, and nothing is
3777
+ staged or changed beyond what git's merge left (the merged branch's version
3778
+ of a file only it changed, or the clean three-way merge of one both sides
3779
+ changed). Once the operator has worked on it, by resolving or staging a file,
3780
+ the handler changes nothing and fails asking them to conclude the merge with
3781
+ `git commit` (a retry then finds that commit by its trailer) or discard it
3782
+ with `git merge --abort`. Any other merge in progress is refused.
3783
+
3784
+ `create-worktree` reuses a worktree that already exists at the configured
3785
+ path. When none does but git reports the task branch checked out in another
3786
+ worktree, left by an earlier round, moved by hand, or created before the
3787
+ settings changed, the handler adopts that worktree and records its location
3788
+ rather than failing on git's one-worktree-per-branch rule.
3789
+
3790
+ When `create-worktree` selects a checkout, ww persists its path for the run.
3791
+ Later shell and extension handlers — including `git-commit` — execute there,
3792
+ and Markdown agent instructions include a `cd` command so manual work uses the
3793
+ same checkout. JSON instructions expose the path as `working_directory`. ww
3794
+ persists the path relative to the project root and prints it absolute for the
3795
+ filesystem it runs in, so a task started on the host continues correctly inside
3796
+ a container that mounts the checkout elsewhere; project-local profile files are
3797
+ recorded and printed the same way.
3798
+ `ww-agentic-workflows extension ww/git branches <TASK-ID>` also reports it.
3799
+
3800
+ #### Template values from `ww/git`
3801
+
3802
+ With `ww/git` in the settings (a section, even an empty one), every template
3803
+ of every workflow may read the task's branch:
3804
+
3805
+ | Value | What it is |
3806
+ | --- | --- |
3807
+ | `{{ww.git.branch}}` | The task's branch. A child task's is `<parent branch>-<child ID>`. |
3808
+ | `{{ww.git.base_branch}}` | The branch it was created from; a child's is its parent's branch. |
3809
+ | `{{ww.git.branch_strategy}}` | The branch format key in use: `start --branch-strategy`, else the workflow's own `branch_name_formats` entry, else `default`. |
3810
+
3811
+ ```yaml
3812
+ - land: Merge {{ww.git.branch}} into {{ww.git.base_branch}} and push.
3813
+ ```
3814
+
3815
+ The branch values come from what `start-task-branch` or `create-worktree`
3816
+ recorded for the task, never from a live `git rev-parse`: the primary
3817
+ checkout and a task's worktree can be on different branches. Before the task
3818
+ has a branch, an agent step that reads one does not start: the task stops
3819
+ for the operator with `operator_reason: value_unavailable` and an error naming
3820
+ the variable and its extension; `next --retry` checks again once the branch
3821
+ exists, and `next --force` skips the step. An automatic handler that reads one
3822
+ fails as any handler does (`handler_failed`). Wire `start-task-branch` before
3823
+ the first step that uses them. An unknown `ww.`
3824
+ name, or `{{ww.git.*}}` without `ww/git` in the settings, is an error when
3825
+ the workflow is loaded.
3826
+
3827
+ ### Writing one
3828
+
3829
+ Create `<project>/ext/<vendor>/<name>/extension.py` exposing `EXTENSION`, or
3830
+ publish a package advertising an `ww.extensions` entry point:
3831
+
3832
+ ```python
3833
+ from ww.extensions.api import Extension, ExtensionHandler, ExtensionResult
3834
+
3835
+
3836
+ def _greet(context):
3837
+ return ExtensionResult(
3838
+ True,
3839
+ f"hello from {context.root}",
3840
+ values={"greeting": "hello"},
3841
+ )
3842
+
3843
+
3844
+ EXTENSION = Extension(
3845
+ vendor="acme",
3846
+ name="hello",
3847
+ version="1.0.0",
3848
+ description="A minimal example.",
3849
+ handlers=(ExtensionHandler("greet", _greet, "Say hello.", outputs=("greeting",)),),
3850
+ )
3851
+ ```
3852
+
3853
+ For a packaged extension, name the `ww.extensions` entry point `acme.hello`;
3854
+ the dot maps to the `acme/hello` identifier without importing the package.
3855
+ Discovery is lazy, so unrelated workflows and saved-state commands do not load
3856
+ the extension. An extension is trusted in-process Python once referenced:
3857
+ qualified references isolate names, not side effects or process access.
3858
+
3859
+ The context identifies the current plan item, work item, attempt, and stable
3860
+ operation. Human-readable `output` is kept on the execution record; structured
3861
+ `values` must exactly match the `outputs` the handler declares (in YAML, a
3862
+ handler returning values lists them as bare `variables` entries) and become
3863
+ available to later workflow actions as `{{greeting}}`. Invalid return types,
3864
+ undeclared values, and missing declared values fail the handler consistently.
3865
+
3866
+ A handler that needs settings per use declares `arguments`, the names of its
3867
+ positional arguments in order. A reference passes them as `args`, a list of
3868
+ strings in which templates are allowed; ww checks the count and the template
3869
+ names when it compiles the workflow, renders the templates when the handler
3870
+ runs, and hands the result over as `context.arguments`. A reference to a
3871
+ handler that declares none may not pass `args`.
3872
+
3873
+ ```python
3874
+ ExtensionHandler("merge-branch", _merge, arguments=("branch", "message"))
3875
+ ```
3876
+
3877
+ A handler that declares `provide` (its agent-supplied inputs, the Python
3878
+ counterpart of `variables`) may also declare `validate`, a callable that
3879
+ receives the handler's own declared values as a mapping and returns an error
3880
+ message to refuse them or `None` to accept. ww calls it when the agent
3881
+ supplies the values, before the completion is saved, so a refused value comes
3882
+ back to the agent as a failed `complete` with that message instead of a
3883
+ handler failure the operator has to resolve. It runs with no store, no
3884
+ workspace, and no effects, and it does not replace the check the handler makes
3885
+ when it runs: `ww/git` declares one for `commit_message` and still checks the
3886
+ same rule in `git-commit`.
3887
+
3888
+ ```python
3889
+ def _subject_error(values):
3890
+ if "\n" in values.get("commit_message", ""):
3891
+ return "commit_message must be a single line"
3892
+ return None
3893
+
3894
+
3895
+ ExtensionHandler(
3896
+ "git-commit",
3897
+ _commit,
3898
+ provide=(ProvidedVariable("commit_message"),),
3899
+ validate=_subject_error,
3900
+ )
3901
+ ```
3902
+
3903
+ An extension that keeps records per task, as `ww/git` keeps branch and commit
3904
+ records, may declare two optional hooks so a reused task ID inherits nothing.
3905
+ `claims_task` receives a context with `task_id` (and `workflow` and the
3906
+ project's `config`) and returns `True` while the extension still holds
3907
+ anything for that ID; a generated task ID skips such an ID, as it skips one
3908
+ whose `reserved_paths` exist. `forget_task` receives the same context and drops
3909
+ the records of the task and its children; `reset` calls it. ww asks the
3910
+ extensions the root or the task's project lists, even with an empty section,
3911
+ and any that has a store.
3912
+
3913
+ ```python
3914
+ def _claims(context):
3915
+ return context.store.read_text(f"{context.task_id}.json") is not None
3916
+
3917
+
3918
+ EXTENSION = Extension(
3919
+ vendor="acme",
3920
+ name="tickets",
3921
+ claims_task=_claims,
3922
+ forget_task=_forget,
3923
+ )
3924
+ ```
3925
+
3926
+ The compiled plan also records the extension API/version, provider source,
3927
+ source fingerprint, and resolved settings. A resumed run uses those saved
3928
+ settings and refuses to dispatch if the extension's version, API version, or
3929
+ provider source has changed, preventing an upgrade from silently changing an
3930
+ in-flight run. Fixing an extension in place under the same version is allowed,
3931
+ as it is for ww itself; the fingerprint is recorded for audit only.
3932
+
3933
+ An extension may declare `ExtensionVariable` entries to override variables
3934
+ owned by ww core. It cannot introduce arbitrary global variables or replace
3935
+ values declared by workflow steps. Only extensions already referenced by the
3936
+ saved plan participate, preserving lazy discovery. Conflicting overrides are
3937
+ configuration errors. The Git extension uses this contract to resolve
3938
+ `{{ww.task.workspace_dir}}` from the primary checkout or its recorded worktree.
3939
+
3940
+ New values go in the extension's one `namespace`, an `ExtensionNamespace`
3941
+ whose `ExtensionVariable` entries templates read as
3942
+ `{{ww.<namespace>.<name>}}`. A namespace is available whenever the root
3943
+ settings list the extension, even with an empty section, and not only when
3944
+ one of its handlers is referenced. Each value is resolved for the task each
3945
+ time ww renders the task's templates; a resolver returning `None` means "not
3946
+ available yet": an agent step that reads it stops the task for the operator
3947
+ (`value_unavailable`) before it starts, and an automatic handler fails. The
3948
+ namespace `ww` and the names ww keeps for its own values (`task`, `project`,
3949
+ `documents`, `metadata`, `project_metadata`, `item`, `child`) cannot be
3950
+ claimed, and two listed extensions claiming one namespace are an error.
3951
+ `ww/git` declares `git`:
3952
+
3953
+ ```python
3954
+ namespace = (
3955
+ ExtensionNamespace(
3956
+ "git",
3957
+ (
3958
+ ExtensionVariable("branch", _branch_variable),
3959
+ ExtensionVariable("base_branch", _base_branch_variable),
3960
+ ),
3961
+ ),
3962
+ )
3963
+ ```
3964
+
3965
+ `ww/git` is bundled with the installed `ww-agentic-workflows` package, so it is
3966
+ available in every project, including a `pipx --editable` installation whose
3967
+ source checkout lives elsewhere. A third-party extension remains project-local.
3968
+ A project cannot provide a second `ww/git`; duplicate extension IDs are an
3969
+ error. A handler is one unit of work: a retry re-runs the whole thing, so write
3970
+ handlers that tolerate that.
3971
+
3972
+ ## Execute a workflow
3973
+
3974
+ ```console
3975
+ ww-agentic-workflows start TASK-123 --workflow task --agent codex --runtime single \
3976
+ --requirements="Implement the requested change." \
3977
+ --model gpt-5 --reasoning high --role manager
3978
+ ww-agentic-workflows next TASK-123 --model gpt-5 --reasoning high --role manager
3979
+ # perform the displayed prompt, skill, or slash command
3980
+ ww-agentic-workflows complete TASK-123 --role worker \
3981
+ --artifact "<whole result in Markdown>" \
3982
+ --summary "<one or two sentences for the next step>"
3983
+ ww-agentic-workflows instruction TASK-123 --role worker
3984
+ ww-agentic-workflows metadata TASK-123
3985
+ ww-agentic-workflows metadata --project
3986
+ ```
3987
+
3988
+ A task has at most one open run. Starting a workflow on a task whose last
3989
+ run is unfinished, failed included, is refused until that run finishes or
3990
+ the task is reset, unless the workflow is declared `restartable`: then the
3991
+ new start abandons the unfinished run of the same workflow and opens a new
3992
+ one, and the abandoned run stays readable in the task's history with its
3993
+ items, artifacts, and interactions. This is the natural setting for a
3994
+ workflow that is run round after round, such as manual testing over shared
3995
+ items. An unfinished run of a different workflow is never abandoned this
3996
+ way.
3997
+
3998
+ In the `single` runtime one session does every step, so a completion opens
3999
+ the next agent step itself and prints that step's page: the `next` it would
4000
+ have run is run for it, preparation hooks included. `next` on a step that is
4001
+ already open then simply shows it again. When opening the next step needs
4002
+ something only the agent can give, such as the outcome of an assessment,
4003
+ the completion prints the pending page that says so. The `auto` runtime
4004
+ keeps the manager's `next`, because that is where a worker is chosen.
4005
+
4006
+ When an outside-of-ww issue has been resolved by an operator, a failed item
4007
+ can be skipped with `next --force --reason "<reason>"`. This is an exceptional operator command:
4008
+ ww asks for an interactive confirmation and explains that agents must obtain
4009
+ permission before using it. Answer `no` (or provide no answer) to leave the
4010
+ failed item in place; answer `yes` only after the operator has approved the
4011
+ forceful transition.
4012
+
4013
+ ```console
4014
+ ww-agentic-workflows next TASK-123 --force --reason "Resolved manually" --role manager
4015
+ # confirmation: Proceed with force? [y/N]
4016
+ ```
4017
+
4018
+ Runtime and execution metadata are retained in task instructions. Under
4019
+ `auto`, compiled requests and manager-selected agent/model/reasoning are
4020
+ shown and persisted separately; ww itself does not launch agents. Under `single`,
4021
+ configured workflow and built-in hints are ignored in favor of the current
4022
+ session. Completion flags can report a bounded delegate for one item without
4023
+ changing the rest of the assignment.
4024
+
4025
+ Human-facing instructions identify themselves as generated by `ww` and name the
4026
+ reader's current role. In `auto`, the manager receives only a worker
4027
+ bootstrap command and passes it to the selected worker without task details or
4028
+ commentary. The worker runs `ww instruction` with `--role worker` to retrieve its
4029
+ complete, role-specific assignment, then receives instructions for when and
4030
+ what to hand back. `single` identifies the session as both manager and worker and
4031
+ states which role to perform without spawning. A short explanation of how `ww`
4032
+ manages the saved workflow appears only after `start` and an explicit `instruction`;
4033
+ normal `next` and `complete` responses stay focused on the immediate action.
4034
+
4035
+ Successful commands return exit code `0`. Handled `ww` errors and rendered
4036
+ failed or interrupted workflow states return `1`. Invalid command-line syntax
4037
+ is reported by `argparse` with exit code `2`. Abbreviated flags are not
4038
+ accepted: every flag is spelled in full.
4039
+
4040
+ The task ID may be omitted from `start`. `task_format` in
4041
+ `ww.json` then controls generation with `{{timestamp}}`,
4042
+ `{{digit}}`, and/or `{{uuid}}`; without it, ww uses `TASK-{{timestamp}}`. It is a
4043
+ setting of the checkout and of the tracker a repository uses, not of what a
4044
+ workflow does, so it lives in the JSON settings, at any of their
4045
+ [levels](#user-repo-and-local-configuration), and a configured project may
4046
+ carry [its own](#a-projects-own-extension-settings). A `task_format` key in
4047
+ any YAML file is an error that names the file and points here.
4048
+
4049
+ ```json
4050
+ {"task_format": "TASK-{{digit}}"}
4051
+ ```
4052
+
4053
+ Prefer an explicit ID whenever the request names an external ticket, so the
4054
+ task matches the issue it works on; `discover` and the embedded agent
4055
+ instructions say so. Avoid a generated format that imitates your tracker's keys,
4056
+ such as `FOOBAR-{{digit}}` next to Jira's `FOOBAR-10859`. To rule generated IDs out,
4057
+ set `"task_format": "explicit"`: `start` and `add-child` then require an ID, and the
4058
+ only exception is a workflow that obtains its own ID in its first step.
4059
+
4060
+ When a task has more than one run, `instruction TASK-123` shows every run and its
4061
+ summary. Use
4062
+ `ww-agentic-workflows instruction TASK-123 --run 02-code-review --role manager` for
4063
+ the detailed instruction and status of one run.
4064
+
4065
+ After a run completes, start another workflow with the same task ID to append a
4066
+ sequential run. Each run retains its own plan, state, artifacts, execution
4067
+ settings, and summary.
4068
+
4069
+ Every non-terminal Markdown instruction shows one role-specific continuation
4070
+ command. A completion screen may request values for upcoming automatic CLI
4071
+ handlers in the same assignment; pass each with `--variable name=value`. Before
4072
+ anything is saved, ww hands each value to the handler that will consume it:
4073
+ a handler that declares a validator, such as `ww/git`'s `git-commit` for
4074
+ `commit_message`, refuses a value it would fail on, and the completion fails
4075
+ with the handler's own message and records nothing, so the agent corrects the
4076
+ value and completes again. `ww` then
4077
+ executes those handlers itself before it activates the next worker item or
4078
+ returns control to the manager. If an automatic command fails, the worker stops
4079
+ and reports the failure to the manager. The response reports
4080
+ `awaiting_operator` with `operator_reason: handler_failed`, so the manager
4081
+ reports it to the ww operator for manual intervention; its instruction lists
4082
+ the two operator
4083
+ options, `next --retry` to run the handler again once the cause is fixed and
4084
+ `next --force --reason` to skip it, so the agent can run the one the
4085
+ operator chooses without guessing. A retried handler that takes provided
4086
+ values does not replay the values it failed with: it asks for them again
4087
+ through the ordinary input request, which shows what it was given last time,
4088
+ so a wrong value is corrected and a right one repeated. `next --force` checks the task state before
4089
+ it asks for confirmation, and its prompt states what the force will do; a task
4090
+ that is neither failed, interrupted, nor stopped at a loop limit is refused
4091
+ without a prompt.
4092
+
4093
+ `status TASK-123` is a quick current-state check: it reports only the task ID,
4094
+ workflow, current step and step state, runtime, and agent/model/reasoning.
4095
+ Use `instruction` when an agent needs the detailed role-specific guidance.
4096
+
4097
+ Markdown and `--json` output are rendered directly from the normalized
4098
+ instruction record. Project-local `.ww/templates` files are not a supported
4099
+ customization mechanism.
4100
+
4101
+ ### Catalogs, output, and project selection
4102
+
4103
+ Catalog commands expose configured and discovered capabilities as JSON; for a
4104
+ single agent-facing overview use `discover`:
4105
+
4106
+ ```console
4107
+ ww-agentic-workflows workflows
4108
+ ww-agentic-workflows modes
4109
+ ww-agentic-workflows runtimes
4110
+ ww-agentic-workflows agents
4111
+ ww-agentic-workflows projects
4112
+ ww-agentic-workflows extensions
4113
+ ww-agentic-workflows artifacts TASK-123
4114
+ ww-agentic-workflows interrupted
4115
+ ```
4116
+
4117
+ `artifacts` returns JSON references for completed step and hook artifacts. Hook
4118
+ records include their parent step, hook name, and hook phase. Each entry's
4119
+ `artifact` (or `command_output`) is the stable project-relative reference, and
4120
+ `path` is its absolute location, which a worker running in a linked worktree
4121
+ needs because `.ww` lives under the primary checkout.
4122
+
4123
+ Lifecycle commands support `--json` when machine-readable output is needed.
4124
+ By default, `ww` detects the primary Git checkout so linked worktrees share task
4125
+ state. Pass global `--root /path/to/project` to select a project explicitly.
4126
+
4127
+ ### Interrupted automatic handlers
4128
+
4129
+ If ww is interrupted after it records an automatic command or extension as
4130
+ started, the operation is shown as `interrupted` because its external outcome
4131
+ is unknown. `next` only reports that recovery boundary; it never replays the
4132
+ operation implicitly. Two cases are settled without asking. A command that
4133
+ had already exited non-zero when ww died is a known failure, not an unknown
4134
+ outcome: every finished command is recorded the moment it exits, so `next`
4135
+ reports it as `failed` with the exit code and what it printed, and the
4136
+ ordinary `next --retry` applies. A command handler declared
4137
+ `idempotent: true` is replayed by `next` itself, because its author has said
4138
+ a second run cannot do damage. For everything else, inspect the current state
4139
+ with:
4140
+
4141
+ ```console
4142
+ ww-agentic-workflows status TASK-123 --role manager
4143
+ ```
4144
+
4145
+ After checking the external system, use
4146
+ `ww-agentic-workflows next TASK-123 --role manager --retry` to replay the
4147
+ unfinished operation. It requires operator confirmation because the external
4148
+ effect may have already occurred. To advance without replaying it, use `next
4149
+ --force` with a specific `--reason`; this also requires confirmation and
4150
+ retains the reason with the item record. Agents must ask an operator before
4151
+ using either exceptional option. Completed command segments remain recorded and
4152
+ are not replayed.
4153
+
4154
+ ## Concurrent ww processes
4155
+
4156
+ Several `ww` invocations can run against one project at the same time. Each
4157
+ mutating command — `start`, `next`, `complete`, `reset` — holds an
4158
+ exclusive lock on its task for its whole duration, so a second process waits and
4159
+ then acts on the first one's committed state instead of overwriting it. Waiting
4160
+ is automatic: the blocked process parks until the holder releases, printing one
4161
+ notice to stderr if the wait lasts longer than a moment.
4162
+
4163
+ Reads are not locked. `instruction` and compact `status` answer immediately even while another process is
4164
+ mid-command, and writes are atomic, so it never sees a partial file.
4165
+
4166
+ The order in which waiting processes are served is **not** guaranteed — the
4167
+ operating system may grant the lock to any waiter. Waiting is bounded by
4168
+ `WW_LOCK_TIMEOUT` (seconds, default `30`); set it to `0` to wait indefinitely.
4169
+ Lock files live in `.ww/locks` and the kernel releases them when a process
4170
+ exits, so a killed run never leaves one behind. Locks are advisory between `ww`
4171
+ processes; editing `.ww/tasks/<id>/state.json` by hand is still unsupported.
4172
+
4173
+ For a real side-effect smoke test with placeholder agent output, use:
4174
+
4175
+ ```console
4176
+ .venv/bin/python scripts/run_workflow_dummy.py TASK-123 --workflow task
4177
+ ```
4178
+
4179
+ The runner executes every ww-owned CLI handler for real, including commits. Run
4180
+ it on a disposable branch or a test repository.
4181
+
4182
+ ## Initialize and maintain a project
4183
+
4184
+ `init` creates a normalized default configuration and project-local agent
4185
+ instructions. `cleanup` removes inactive lock sidecar files. `reset` deletes one
4186
+ task's saved state and artifacts, and the records extensions keep for it, such
4187
+ as `ww/git`'s branch and commit records, and therefore requires explicit
4188
+ confirmation.
4189
+
4190
+ ```console
4191
+ ww-agentic-workflows init
4192
+ ww-agentic-workflows cleanup
4193
+ ww-agentic-workflows reset TASK-123 --yes
4194
+ ```
4195
+
4196
+ ## When an automatic handler fails
4197
+
4198
+ By default, ww stops the task and hands the decision to the operator. An
4199
+ automatic shell/argv handler can instead declare `on_failure: fix` to request
4200
+ an agent repair before ww retries it:
4201
+
4202
+ ```yaml
4203
+ - build: ~
4204
+ shell: npm run build
4205
+ on_failure: fix
4206
+ on_failure_instruction: Fix the build errors reported by the command.
4207
+ ```
4208
+
4209
+ ww runs the handler until it fails, then gives an agent a repair assignment
4210
+ containing the command, diagnostics, full output references, and optional
4211
+ failure instruction. The agent fixes the cause and submits `complete` with an
4212
+ artifact; ww retries the handler and advances only on success. Completed
4213
+ preceding handlers stay completed. The repair belongs to the failed execution
4214
+ and creates no workflow step or hooks.
4215
+
4216
+ In `auto`, the manager dispatches the repair and repeated failures stay with
4217
+ that worker; in `single`, the session receives it directly. Repair artifacts
4218
+ survive reloads and are available through `artifacts`. Repeated failures reach
4219
+ the existing `limits.fixes` operator stop (default 3). An operator retry renews
4220
+ the budget, and an operator force skips the handler. Known failure retries
4221
+ need no `idempotent: true`; unknown outcomes after interruption still use the
4222
+ existing recovery rules.
4223
+
4224
+ `limits.auto_retries` in `ww.json` (default 0, never negative) makes ww retry a
4225
+ failed automatic step that many times itself before any of this applies: an
4226
+ interrupted step (unknown outcome) and a step that needs agent-supplied values
4227
+ are never retried this way. Each failed attempt is kept on the step's record, and a
4228
+ page that stops for the operator, or hands a repair to the agent, lists them
4229
+ (`ww retried this step N time(s) itself`). An operator retry starts the count over.
4230
+
4231
+ Optional `on_failure_instruction` also adds guidance to hook failures.
4232
+ `before_complete` hooks with `on_failure: fix` keep the step's existing check
4233
+ loop with its worker; see [The fix loop](#the-fix-loop).
4234
+
4235
+ For the default `on_failure: operator` policy, the failure page hands the
4236
+ decision to the operator as follows.
4237
+
4238
+ The page the agent receives names the command and shows what it printed:
4239
+
4240
+ ```markdown
4241
+ ### Error
4242
+
4243
+ automatic handler failed (1) running: python -m pytest -q
4244
+
4245
+ 2 failed, 1 passed
4246
+ ```
4247
+
4248
+ Either stream is reported — stderr when it has something, otherwise stdout,
4249
+ which is where pytest, ruff, and mypy actually write. Output longer than forty
4250
+ lines is tailed, and the complete text stays available through
4251
+ `ww artifacts <task-id>`.
4252
+
4253
+ Under "Operator recovery" the agent is told to hand over: report what failed
4254
+ and quote the output, say that completed work is saved and that nothing after
4255
+ the step has run, ask for a decision without making it, and state what happens
4256
+ next either way. Then stop and wait.
4257
+
4258
+ Two routes lead out, and the agent runs whichever the operator picks:
4259
+
4260
+ ```console
4261
+ ./ww next <task-id> --retry --role manager
4262
+ ./ww next <task-id> --force --reason "<reason>" --role manager
4263
+ ```
4264
+
4265
+ `--retry` runs the same handler again, for when the cause has been fixed.
4266
+ `--force` skips it and records the operator's reason in the task, so a skipped
4267
+ check is visible afterwards rather than forgotten. A loop that hits its
4268
+ round limit escalates the same way, and the force there leaves the loop.
4269
+
4270
+ ## Installing the ww skills during init
4271
+
4272
+ `init` offers its bundled skills to every agent integration it knows about:
4273
+ `ww`, `noww`, `ww-rule`, and `ww-setup` with the skills it guides through
4274
+ (`ww-learn-project`, `ww-suggest`, `ww-refresh`, `ww-solve`,
4275
+ `ww-rules-from-artifacts`, `ww-feedback-rules`, `ww-deduce-feedback`,
4276
+ `ww-automate`, `ww-scriptize`, `ww-wizard`; see
4277
+ [Setting ww up](#setting-ww-up-learning-and-suggestions)). In a terminal it
4278
+ can redraw, that is one checklist rather than one question per agent:
4279
+
4280
+ ```text
4281
+ Install the ww skills (ww, noww, ww-rule, ww-setup, ww-learn-project, …) into which agent directories?
4282
+ ↑↓ move · space toggles · a all · enter confirms
4283
+
4284
+ > [ ] .agents
4285
+ [ ] .codex
4286
+ [x] .claude already present
4287
+ [ ] .gemini
4288
+ ```
4289
+
4290
+ Directories that already exist start ticked, because having one is good
4291
+ evidence you use that agent. Nothing is written until you press enter, and
4292
+ the answers are remembered in `.ww/init-choices.json`, so a later `init` only
4293
+ asks about agents you have not decided on; `init --force` asks about every
4294
+ agent whose `ww` skill is not installed yet.
4295
+
4296
+ Where the terminal cannot be driven that way — a pipe, `TERM=dumb`, a captured
4297
+ stdin in a test — ww falls back to plain questions: one for each directory that
4298
+ already exists, then a single comma-separated question for the agents without
4299
+ one. `--skills` and `--no-skills` skip the interaction entirely, and
4300
+ `--no-input` takes the defaults.
4301
+
4302
+ `init-choices.json` also remembers which bundled skills you accepted. When a
4303
+ later ww version bundles a new one, the next `init` asks about that skill
4304
+ alone, into the directories you already chose, without the agent questions:
4305
+
4306
+ ```text
4307
+ ww now ships the `ww-rule` skill. Install into .claude? [Y/n]:
4308
+ ```
4309
+
4310
+ Either answer is remembered, so it is asked once; a skill you declined is not
4311
+ installed later on its own. Without a recorded answer, a skill already
4312
+ present in a chosen directory counts as accepted.
4313
+
4314
+ The rest of the summary adapts to repeat runs too. The box saying what to allow
4315
+ in your agents' permissions is shown the first time only (and again under
4316
+ `--force`), and the steps for getting started only while
4317
+ `ww.yaml` defines no workflow. The documentation links and
4318
+ the closing next step, the `ww-setup` skill, are always shown.
4319
+
4320
+ ## Agent hooks
4321
+
4322
+ Agent hooks are the agent's own hooks (session-start, stop, interrupt),
4323
+ installed with `ww hook` and separate from the workflow hooks above. They
4324
+ carry ww's task state into a session — which task is unfinished, whether a
4325
+ step was left mid-way — without blocking the agent. `agent_hooks` in
4326
+ `ww.json` sets how many days back `session-start` looks for unfinished
4327
+ tasks (`recent_days`, 3) or switches that scan off (`check_unfinished:
4328
+ false`). See
4329
+ [documentation/agent-hooks.md](agent-hooks.md) for the events, the
4330
+ per-agent table, install/uninstall/show, failure behaviour, and interrupted
4331
+ tasks.
4332
+
4333
+ ## Choosing a runtime
4334
+
4335
+ A parent and its children can use different runtimes and session models. For
4336
+ example, a Sol manager can coordinate an `auto` roadmap while each Luna session
4337
+ handles a whole child in `single`:
4338
+
4339
+ ```console
4340
+ ww-agentic-workflows start-child TASK-123 TASK-123.1 \
4341
+ --workflow express --runtime single --model gpt-6-luna --reasoning high
4342
+ ```
4343
+
4344
+ Launch the child session with those actual host settings and give it the child's
4345
+ manager instruction command; ww does not switch a running session's model.
4346
+ The parent retains its own runtime/model/reasoning and resumes its review stages
4347
+ after the child completes. Without flags, children inherit parent settings.
4348
+ Changing only the model resets reasoning to `auto`; specify both for an exact
4349
+ request. `--agent` starts the child for another agent and defaults to the parent's. Launch settings are fixed once starting begins and survive retries,
4350
+ including external-ID bootstrap. This command cannot change an already-started
4351
+ child's runtime or model. `--workflow` also overrides the child workflow named
4352
+ by the parent coordinator, without changing the parent plan or earlier children.
4353
+ The target must exist, cannot contain `children`, and must provide its own
4354
+ first-step `task_id` variable when starting an external-ID request. The chosen
4355
+ workflow survives interrupted starts and identity binding; it cannot change
4356
+ after launch begins. Omit the flag to use the configured target.
4357
+
4358
+ `single` is the default, so an agent told little more than that would omit
4359
+ `--runtime` and get `single` every time, including for workflows written to
4360
+ delegate. `discover` therefore makes the choice explicit. Any workflow declaring an `agent`,
4361
+ `model`, `reasoning`, or `profile` is listed with the steps that declare one
4362
+ and a note to start it under `auto`:
4363
+
4364
+ ```markdown
4365
+ - `reviewed` — Cheap triage, strong review. Requests a specific worker on:
4366
+ `triage`, `review` — start it with `--runtime auto` so those requests apply.
4367
+ ```
4368
+
4369
+ The search covers the whole workflow, not just its top level: nested steps,
4370
+ loop bodies, per-item stages, and assessment branches all count, as does a
4371
+ setting on the workflow itself. A workflow that requests nothing is listed
4372
+ without a note, so the marker means something.
4373
+
4374
+ `--json` reports the same thing as `delegation_requests`, the list of step
4375
+ names carrying a request, empty when there are none.
4376
+
4377
+ This is advice, not enforcement. `single` remains right when nothing is
4378
+ requested, when delegation is unavailable or not permitted, or when the
4379
+ operator asked the session to do the work itself — and a workflow that always
4380
+ wants delegation should declare `runtime: auto` rather than rely on the reader.
4381
+
4382
+ ## Choosing the ww binary
4383
+
4384
+ A project names the ww it runs in `ww.json`:
4385
+
4386
+ ```json
4387
+ {"executable": "ww-agentic-workflows-dev"}
4388
+ ```
4389
+
4390
+ The value is a command on `PATH` or a path. Every command ww prints for that
4391
+ project starts with it — `ww-agentic-workflows-dev next TASK-1 --role
4392
+ manager` — and the `./ww` launcher runs it, reading the key each time, so a
4393
+ project switches installs by editing that one line. Like every setting, the key
4394
+ may also come from the user or local settings file, the local one winning,
4395
+ so one checkout can use a development install without changing the shared
4396
+ file. Without the key, printed
4397
+ commands use `./ww` and the launcher runs `ww-agentic-workflows`. `init` writes
4398
+ `"executable": "ww-agentic-workflows"` when the key is missing. The launcher
4399
+ itself is ww-owned: `init` rewrites a `./ww` that differs from the current one
4400
+ and reports it as updated, because a launcher an older ww wrote can read old
4401
+ configuration file names and run the wrong binary, and `lint` warns about such
4402
+ a launcher, naming `init` as the fix. Choose the binary with `executable`, not
4403
+ by editing `./ww`.
4404
+
4405
+ This is what lets two installs live side by side, for example a source
4406
+ checkout for developing ww itself, switched between branches often, and the
4407
+ PyPI development snapshots for use in other projects. pipx gives the second a
4408
+ different global name:
4409
+
4410
+ ```console
4411
+ pipx install --editable ~/tools/agentic-workflows
4412
+ pipx install --suffix=-dev --pip-args=--pre ww-agentic-workflows
4413
+ ```
4414
+
4415
+ Two checkouts work the same way, with
4416
+ `pipx install --editable --suffix=-dev ~/tools/agentic-workflows-dev`. A
4417
+ project that should use the second install then sets
4418
+ `"executable": "ww-agentic-workflows-dev"`. The update notice, `--version`,
4419
+ and the audit log keep naming the package, `ww-agentic-workflows`.
4420
+
4421
+ Either install also runs inside the other checkout, for example the
4422
+ development install used for all work in the `dev` checkout. ww recognises a
4423
+ checkout of its own source by `src/ww/extensions/registry.py` and then uses the
4424
+ running install's bundled `ww/git`, ignoring the checkout's own `ext/ww/*`
4425
+ copy. In any other project, an `ext/ww/<name>` of its own is refused as
4426
+ a duplicate of the bundled extension.
4427
+
4428
+ ## Update notices and upgrading ww
4429
+
4430
+ Before normal commands, ww checks for an update at most once a day and shows
4431
+ an available update once. Editable Git installs compare their checkout with
4432
+ its tracking branch and summarise changelog entries or commit subjects.
4433
+ Package installs query PyPI for newer compatible, non-yanked versions. Stable
4434
+ installs select stable releases; dev, beta and RC installs also allow
4435
+ prereleases. A final release supersedes its earlier prereleases.
4436
+
4437
+ A package notice names both versions and the upgrade command, using the
4438
+ project's configured executable, for example:
4439
+
4440
+ ```text
4441
+ ## A newer ww is available
4442
+
4443
+ 1.0.0.dev42 → 1.0.0.dev47
4444
+ Run: `ww-agentic-workflows upgrade`
4445
+ ```
4446
+
4447
+ Checks have short network timeouts and remain silent when offline. Notices go
4448
+ to stderr for JSON and other machine-readable commands. They do not prevent
4449
+ the requested command from running. PyPI checks send only an ordinary package
4450
+ metadata request, with no project or task information.
4451
+
4452
+ ```console
4453
+ ww-agentic-workflows updates # repeat the cached notice
4454
+ ww-agentic-workflows updates --now # force a fresh check
4455
+ ww-agentic-workflows updates --json # machine-readable version information
4456
+ ww-agentic-workflows upgrade # preserve the installed release preference
4457
+ ww-agentic-workflows upgrade --pre # allow prereleases from a stable installation
4458
+ ```
4459
+
4460
+ `upgrade` uses pip in the running Python environment or pipx for the owning
4461
+ pipx environment, including suffixed installs and a custom `PIPX_HOME`. A pipx
4462
+ installation requires pipx on PATH. An installation injected into another
4463
+ pipx environment must be upgraded through pipx directly. Installer errors are
4464
+ reported without overriding environment protections.
4465
+
4466
+ For editable Git installs, `upgrade` performs `git pull --ff-only` on the
4467
+ checkout's actual tracking branch. It refuses local changes, detached HEAD,
4468
+ missing upstream and divergent history; local work is not stashed or reset.
4469
+ An editable installation without a Git checkout cannot use this command.
4470
+
4471
+ `upgrade` does not check for open tasks. A release that changes the task state
4472
+ format can leave tasks an older build started unreadable, in this project and in
4473
+ every other project that uses the same installation, so read the changelog and
4474
+ finish such tasks first when it says so.
4475
+
4476
+ The per-user cache is under `~/.config/ww`, or `$XDG_CONFIG_HOME/ww`; package
4477
+ checks have separate cache files for each Python environment and installed
4478
+ version. `WW_STATE_HOME` overrides the cache directory. `update_check: false`
4479
+ in `ww.json` disables notices for a project; `WW_UPDATE_CHECK=0` disables them
4480
+ globally. `WW_UPDATE_CHECK_INTERVAL` sets the seconds between checks.
4481
+
4482
+ ## A newer ww is available
4483
+
4484
+ This checkout is 23 commits behind `origin/main`.
4485
+
4486
+ What changed:
4487
+
4488
+ - `interact --pause` records that the operator is done for now.
4489
+ - Items carry custom string fields, set with `--field NAME=VALUE`.
4490
+
4491
+ **Tell the person you are working for about this before you continue**, and let them decide whether to update. To update:
4492
+
4493
+ ```console
4494
+ git -C ~/tools/agentic-workflows pull
4495
+ ```
4496
+
4497
+ This notice is shown once. `ww updates` prints it again.
4498
+ ````
4499
+
4500
+ The notice is announced, never enforced: it is written above the command's
4501
+ own output, which then runs exactly as it would have. An agent relaying that
4502
+ output shows the update to the operator first, and the decision to pull is
4503
+ theirs. Nothing is reported anywhere — the only network call is a `git fetch`
4504
+ against the remote the user cloned from, made at most once a day, and every
4505
+ failure in it, including no network at all, leaves the command untouched.
4506
+
4507
+ What the notice lists comes from the bullets added to `CHANGELOG.md` between
4508
+ the two commits, falling back to commit subjects when the changelog did not
4509
+ change. The branch compared against is whatever the checkout tracks, so
4510
+ someone following `dev` is told about `dev`.
4511
+
4512
+ Each notice is shown once. The record of what was already announced is per
4513
+ user, in `~/.config/ww/updates.json` (under `$XDG_CONFIG_HOME` when that is
4514
+ set), because the
4515
+ installation is shared by every project on the machine — acknowledging an
4516
+ update in one project does not raise it again in the next.
4517
+
4518
+ ```console
4519
+ ww-agentic-workflows updates # print the last notice again
4520
+ ww-agentic-workflows updates --now # look now, before the next check is due
4521
+ ```
4522
+
4523
+ For a command whose output is consumed by a program — the JSON catalogs,
4524
+ `artifacts`, `items`, anything with `--json` — the notice goes to standard
4525
+ error instead, so standard output stays parseable.
4526
+
4527
+ To switch the check off for a project, set `"update_check": false` in
4528
+ `ww.json`. `WW_UPDATE_CHECK=0` switches it off everywhere,
4529
+ and `WW_UPDATE_CHECK_INTERVAL` sets the seconds between checks.
4530
+
4531
+ ## Learning from operator feedback
4532
+
4533
+ Feedback deduction is optional follow-up work after a workflow completes. It
4534
+ adds no assignments, gates, handlers or steps to the workflow. Explicitly mark
4535
+ artifact-producing steps that can contain useful negative feedback:
4536
+
4537
+ ```yaml
4538
+ workflows:
4539
+ - name: task
4540
+ steps:
4541
+ - review: Review the changes and record any corrections.
4542
+ learnable: true
4543
+ - confirm: Confirm acceptance with the operator.
4544
+ interactive: true
4545
+ learnable: true
4546
+ ```
4547
+
4548
+ `learnable` is a boolean, default `false`, independent of `interactive`.
4549
+ Noninteractive reviews can be learnable; ordinary conversations are not
4550
+ learnable unless explicitly marked. It requires `artifact: true`. The saved
4551
+ plan retains this source metadata without inserting learning work. When an
4552
+ eligible artifact exists and `feedback_learning` in `ww.json` is enabled
4553
+ (default `true`), the completed-workflow page suggests the `ww-deduce-feedback`
4554
+ skill. It does not run deduction automatically or postpone completion.
4555
+
4556
+ The skill reads negative feedback from eligible completed-step artifacts,
4557
+ reasons about possible recurrence and matches existing generalizations by
4558
+ meaning. It records whether enforcement could be scripted or needs reasoning,
4559
+ including a concrete approach and its limits. A candidate is an observation,
4560
+ not an obligation or an installed rule. A single encounter can be useful;
4561
+ frequency is evidence rather than a required threshold or prediction.
4562
+
4563
+ The internal commands expose sources and stable point IDs:
4564
+
4565
+ ```console
4566
+ ./ww feedback sources TASK-42 --run 01-task --json
4567
+ ./ww feedback --json
4568
+ ./ww feedback get feedback-a1b2c3d4e5f6 --json
4569
+ ```
4570
+
4571
+ `sources` returns artifact source IDs, completion timestamps and content through
4572
+ ww's storage adapter. Only completed runs and explicitly learnable artifacts
4573
+ are eligible, including retained loop-round results. `show` is an alias for
4574
+ `sources`. Do not use arbitrary files or interactive transcripts as deduction
4575
+ sources. Generalize feedback in the artifacts, not artifact headings or
4576
+ instructions. The agent decides meaning; ww validates supporting quotes.
4577
+
4578
+ Write an analysis array such as this, substituting a source ID ww returned:
4579
+
4580
+ ```json
4581
+ [
4582
+ {
4583
+ "summary": "Use English variable names.",
4584
+ "reason": "Unspecified naming language can recur in new code.",
4585
+ "enforcement": "reasoning",
4586
+ "approach": "Review identifiers; dictionaries have false positives.",
4587
+ "evidence": [
4588
+ {"source": "artifact-a1b2c3d4e5f60000", "quote": "Use English names."}
4589
+ ]
4590
+ }
4591
+ ]
4592
+ ```
4593
+
4594
+ Then record the deductions after completion:
4595
+
4596
+ ```console
4597
+ ./ww feedback record TASK-42 --run 01-task --analysis analysis.json --role manager
4598
+ ```
4599
+
4600
+ New points omit `id`. For another encounter of an existing point, supply its
4601
+ exact `id` from `list` or `get`; ww rejects a same-wording update with new
4602
+ evidence if the ID is omitted. Semantic matching of paraphrases belongs to the
4603
+ agent. Repeating the same point and artifact quote does not add an occurrence,
4604
+ including retries of new-point creation. New supporting quotes increment the
4605
+ count; several quotes in one task still count as one distinct encountered task.
4606
+ Record `[]` when no negative feedback generalizes. Recording deductions does
4607
+ not change the completed run's state, plan, progress or assignment.
4608
+
4609
+ The locked, atomically written `.ww/feedback.json` store retains provenance,
4610
+ occurrences, distinct encountered tasks, and `last_encountered_at`: the latest
4611
+ supporting artifact completion time, not deduction time. This timestamp is
4612
+ stored for later use; it does not affect pruning. `task_ratio` measures the
4613
+ fraction of tracked tasks with encounters; `occurrence_ratio` divides supporting
4614
+ quote encounters by tracked tasks and can exceed one. `completed_task_ratio`
4615
+ uses completed tasks on both sides. Tracking counts each completed task once
4616
+ and also includes explicitly analysed historical tasks; it never automatically
4617
+ backfills old tasks. Earlier transcript-based points remain readable with their
4618
+ IDs and counts; their timestamp is derived from the recorded interaction time.
4619
+
4620
+ Completion and deduction never delete points. Run `/ww-feedback-rules` for a
4621
+ separate review of every candidate and a batch of concrete rule proposals.
4622
+ The skill asks for explicit approval before writing rules through validated
4623
+ `ww rules` commands. It also maintains the store using a separate command:
4624
+
4625
+ ```console
4626
+ ./ww feedback prune --dry-run --json
4627
+ ./ww feedback prune --keep feedback-a1b2c3d4e5f6 --json
4628
+ ```
4629
+
4630
+ Pruning deletes candidates absent for five subsequently completed tasks. The
4631
+ review skill examines all candidates first and retains stale points still
4632
+ useful for proposals or deferred decisions with repeatable `--keep` IDs. A
4633
+ pruning preview does not write anything. Original artifacts are never deleted.
4634
+ No elapsed-time policy is implied by `last_encountered_at`.
4635
+
4636
+ Set `"feedback_learning": false` in `ww.json` to disable completion suggestions,
4637
+ deduction recording and task-exposure tracking. Existing candidates and
4638
+ artifacts remain readable. Pruning remains an explicit maintenance operation,
4639
+ independent of that suggestion setting.