orchestrator-workflow 0.24.0 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,335 @@ All notable changes to `orchestrator-workflow` are documented here.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [Unreleased]
9
+
10
+ ## [0.26.0] - 2026-08-30
11
+
12
+ ### Added
13
+
14
+ - The orchestrator now writes a per-worktree run pointer, `.ai/run`: a plain
15
+ text file whose first non-empty line is the absolute path of the run
16
+ directory, one written in every repository or worktree a run touches
17
+ (`SKILL.md` Run state, step 1, and all three Harness notes bullets;
18
+ `agents-md-section.md` Run state gained the matching bullet). For a run
19
+ spanning more than one repository, `00-goal.md` now also carries one keyed
20
+ `run-base[<repo-basename>]` marker per repository alongside the existing
21
+ unkeyed one, exact form `<!-- solution-acceptance: run-base[<repo-basename>]
22
+ = <sha> -->`; the shipped template line uses the placeholder key
23
+ `<repo-basename>` and value `<sha>` as a documentation example. Both are
24
+ written for a new consumer: the `.ai/run` pointer and the keyed marker are
25
+ read by grounding-mcp's `ow-run-completeness` reader, released as
26
+ `@lannguyensi/grounding-mcp` 0.9.0 (agent-grounding task
27
+ `design/ow-run-pointer-binding`, agent-tasks 43a7ef58, PR #198). The
28
+ reader resolves a run through the pointer first and falls back to scanning
29
+ the repository's own `.ai/runs/` (newest by name) only when no pointer file
30
+ exists, so kits and repos without the pointer keep working exactly as
31
+ before; the run-base marker's own date-heuristic fallback for a `TODO`
32
+ value is a separate mechanism and is unchanged. `README.md` ("What gets
33
+ installed") and `INSTALL-AGENT.md`
34
+ ("Write surface" and the manual scaffold list) now note that `.ai/run`
35
+ should be added to the repository's `.gitignore` (the installer does not
36
+ edit `.gitignore` itself). Pinned by new tests in
37
+ `test/template-markers.test.ts` (the keyed placeholder line's exact text,
38
+ its whole-line-comment shape, its position directly below the unkeyed
39
+ marker, and that the existing unkeyed `run-base` regex still matches
40
+ exactly once) and a new `test/docs-consistency.test.ts` describe block
41
+ (the pointer contract's phrases in SKILL.md Run state, the exact keyed
42
+ example string, step 1, each of the three Harness notes bullets
43
+ individually, the agents-md-section bullet, and the README/INSTALL-AGENT
44
+ gitignore notes). Anchors in `docs/okf/*.md` that cite line ranges in
45
+ `SKILL.md`, `test/docs-consistency.test.ts`, and
46
+ `test/template-markers.test.ts` drifted out of range because of the line
47
+ shifts this change introduces; those anchors were re-pointed in the same
48
+ PR, and `run-state-lifecycle-and-markers.md` gained a section documenting
49
+ the pointer and the keyed marker.
50
+ - Two review rounds on the run-pointer change above corrected inaccurate
51
+ claims and hardened the pinning tests. `SKILL.md` Run state now states the
52
+ pointer contract as a short lead sentence plus three bullets (what the
53
+ pointer's content is, when to write, overwrite, and remove it, and to
54
+ make sure it is ignored before writing it), followed by a separate
55
+ paragraph on how the run-completeness reader uses it: pointer first,
56
+ falling back to that repository's own `.ai/runs/` (the run there that
57
+ sorts newest by directory name) only when no pointer file exists, with a broken pointer rejected outright
58
+ rather than falling back; the exact accept/reject rules are left to the
59
+ consuming gate's (grounding-mcp) own documentation, not restated here.
60
+ The keyed-marker grammar sentence is now a single generalised rule: write
61
+ the marker exactly in its documented form, on its own line; a deviating
62
+ line is either rejected, which blocks the run, or not recognised at all
63
+ (for example inside a list bullet), which leaves the binding for that
64
+ repository silently missing. The consumer detail that a real key left
65
+ with the placeholder value `<sha>` is read as-is and blocked by the
66
+ verdict layer lives in `docs/okf/run-state-lifecycle-and-markers.md`,
67
+ not in the skill text. `test/docs-consistency.test.ts`'s pointer-doc
68
+ describe block now routes six of its eight checks through one shared
69
+ `expectPointerMention` helper that asserts the exact phrase `` `.ai/run`
70
+ pointer `` (a bare `.ai/runs/` mention alone cannot satisfy it); the
71
+ SKILL.md Run state contract check and the exact-keyed-example check keep
72
+ their own specific phrases instead, and a further check pins the
73
+ grammar rule's wording ("on its own line", both deviation outcomes).
74
+ `test/template-markers.test.ts`'s property test now carries
75
+ grounding-mcp's `KEYED_RUN_BASE_STRICT` and `PLACEHOLDER_KEY` regexes
76
+ verbatim, kept in sync by hand, instead of a locally tightened mirror,
77
+ and still asserts that two constructed near-miss variants (uppercase,
78
+ space before the colon) do not match. `agents-md-section.md`'s
79
+ run-directory bullet still notes the run directory can live "in the
80
+ workspace or a touched repository". `docs/okf/run-state-lifecycle-and-markers.md`
81
+ carries the corrected claims plus the consumer's own test-measured
82
+ evidence for the scan fallback and the malformed/not-seen split, and
83
+ every `docs/okf/*.md` anchor that cited a line range shifted by either
84
+ round's edits was re-pointed in the same PR.
85
+ - An operator-level install layer: a new `operator-manifest.ts` module and
86
+ an operator home directory (default `~/.orchestrator-workflow/`,
87
+ overridable via the `ORCHESTRATOR_WORKFLOW_HOME` environment variable)
88
+ hold one manifest per operator (`{ kit, schemaVersion: 1, defaults: {
89
+ harnesses, profile, tiers, models }, targets: [{ path,
90
+ lastAppliedVersion, lastAppliedAt }], createdAt, updatedAt }`), separate
91
+ from each repository's own `.ai/workflow/manifest.json`. Four new
92
+ subcommands sit alongside the existing per-repository `init`/`uninstall`,
93
+ which stay fully supported and unchanged: `setup` writes or updates the
94
+ operator defaults without touching any repository; `apply --target
95
+ <repo>` projects those defaults, and the target's own previously
96
+ recorded settings, onto one repository through the same
97
+ option-resolution logic `init` uses (`resolveInitInputs`, extracted for
98
+ reuse), and registers the target, by its resolved real path, in the
99
+ operator manifest, with `--sync` inverting precedence so the operator's
100
+ defaults win over the target's recorded profile/tiers/models, and
101
+ `--pin`/`--unpin`/`--force-pin` controlling the new per-repo kit-version
102
+ pin (below); `doctor [--json] [--prune]` walks the registry and reports
103
+ each target's status (`clean`, `divergent`, `version-lag`, `drift`,
104
+ `missing`, `no-manifest`, `unverifiable`), exiting `2` when the operator
105
+ manifest is missing or unreadable (or, with `--prune`, when the manifest
106
+ lock cannot be acquired or the rewrite fails), `1` when any target is
107
+ `drift`/`missing`/`no-manifest`/`unverifiable`, else `0`, and `--prune`
108
+ removes `missing`/`no-manifest` targets (never `unverifiable`) and
109
+ rewrites the manifest in normalized form; `adopt [dir] [--json]` registers an
110
+ already-installed repository verbatim, touching nothing in it,
111
+ bootstrapping the operator manifest from the repository's own recorded
112
+ settings when none exists, recording the repository's own version as
113
+ `lastAppliedVersion`, and printing that target's `doctor` report (exit
114
+ `1` only on drift, exit `2` for a precondition failure). Design
115
+ decisions: no new binary, all four subcommands live on the existing
116
+ `orchestrator-workflow` CLI; the registry is implicit, `apply`/`adopt`
117
+ register as a side effect of a real run and `doctor --prune` is the only
118
+ way to remove an entry; a multi-repo workspace root is an ordinary
119
+ target, nothing special. `README.md` gained a new "Operator-level
120
+ install" section and `INSTALL-AGENT.md` gained the operator path (an
121
+ installing agent runs `apply` instead of `init` when an operator
122
+ manifest already exists, and `adopt` for an already-installed
123
+ repository) plus the new operator-home and `pin` entries in its Write
124
+ surface list. Consumer-side evidence: agent-tasks `b457ee55`, PRs
125
+ #142-#147.
126
+ - The repo manifest (`.ai/workflow/manifest.json`) gained one optional
127
+ field, `pin`: a kit-version string. `apply --pin <version>` sets or
128
+ replaces it (trimmed; empty, whitespace-only, or containing internal
129
+ whitespace rejected as a usage error, exit `2`, writing nothing),
130
+ `--unpin` clears it, and `--force-pin` advances an existing pin to the
131
+ running version (a no-op on an unpinned target); read by `apply`'s pin
132
+ gate and by `doctor`, which on a pinned target compares the pin against
133
+ the installed version instead of the installed version against the
134
+ running kit. Purely additive: a
135
+ caller that never sets it sees a byte-identical manifest to before.
136
+ - `init --harness none` (the literal word `none`, alone): a templates-only
137
+ mode that writes only `.ai/workflow/**` and `.ai/runs/.gitkeep`, records
138
+ `harnesses: []` in the manifest, and touches no `AGENTS.md`, `CLAUDE.md`,
139
+ or per-harness directory. `none` combined with a real harness name
140
+ (`none,claude`, either order) is a usage error rather than an implicit
141
+ precedence rule. A plain re-run (no `--harness` flag) after a recorded
142
+ `harnesses: []` install stays templates-only instead of falling back to
143
+ filesystem detection; a later `init --harness <list>` on the same target
144
+ adds harness files and manifest entries additively, without touching the
145
+ already-installed templates. `apply` shares the same option parsing (an
146
+ explicit `--harness none` on an `apply` call resolves to templates-only
147
+ too) but not the re-run stickiness: `apply`'s own harness fallback chain
148
+ (target's recorded harnesses, else the operator defaults, else detection)
149
+ is unchanged, so a target `apply`-installed as templates-only is not
150
+ guaranteed to stay that way on a flagless `apply` re-run, a gap left open
151
+ by this change rather than closed. The closing summary line prints
152
+ `templates only` instead of `installed for: ` followed by nothing.
153
+ Motivated by friction filed 2026-08-28 while refreshing an agent-tasks
154
+ install that had ended up in the templates-only manifest shape (`harnesses:
155
+ []`, produced by a 0.14.0-era install with no harness configured) with no
156
+ supported way to reproduce or re-render that state: `--harness none`
157
+ rejected the literal value, and `--harness ""` fell back to detection,
158
+ which under `--yes` installed `claude` unasked. Documented in `README.md`
159
+ ("Non-interactive") and `docs/okf/install-fence-mechanics.md` (new
160
+ "`--harness none` (templates-only mode)" section). Agent-tasks 613316c9.
161
+
162
+ ### Changed
163
+
164
+ - `setup`, `apply`'s registration step, `doctor --prune`, and `adopt` all
165
+ write the operator manifest through the same locked write API,
166
+ `updateOperatorManifest`/`withOperatorManifestLock`, backed by one
167
+ advisory lock (`.manifest.lock` in the operator home, stale after 30s)
168
+ so concurrent `orchestrator-workflow` invocations on one machine cannot
169
+ race each other's writes.
170
+
171
+ ## [0.25.0] - 2026-08-27
172
+
173
+ ### Added
174
+
175
+ - A "Review-round escalation budget" (`SKILL.md`, new section right after
176
+ the existing Round-2 halt rule): by the second round-2 halt signal on a
177
+ task, or its third `fix_required` review round, whichever comes first,
178
+ the orchestrator now picks one of three escalations, tier/model
179
+ escalation, an advisor spawn, or an operator merge-hold, instead of
180
+ running another round unaided, and records the choice in
181
+ `03-decisions.md`'s new Review-round escalation section (the
182
+ `review-round-escalation` marker: `n/a | tier_escalation | advisor |
183
+ merge_hold`, `n/a` a deliberately fail-open default since most runs
184
+ never trigger the budget at all, unlike the `TODO` fail-closed sentinel
185
+ the `solution-acceptance:` marker family uses). Which of the three is
186
+ picked stays a judgment call; only that one is picked and recorded is
187
+ now mandatory, and escalating never substitutes for a review round.
188
+ `agents-md-section.md` carries the same rule in short form. The
189
+ reviewer output contract (`SKILL.md` and `reviewer.md`) gained a
190
+ `recurrence: new | repeated` field per finding, and step 7 now has the
191
+ orchestrator name the review round number in the briefing when it is
192
+ not the task's first, so the reviewer can classify each finding against
193
+ the rounds it was told about instead of the orchestrator re-deriving
194
+ recurrence by hand. `03-decisions.md`'s new marker is a documented
195
+ convention only: nothing in this package's own code reads it today
196
+ (unlike the `solution-acceptance:` markers, which grounding-mcp's
197
+ run-completeness reader does parse); wiring it into that reader, if
198
+ wanted, is a follow-up in the consuming project, not part of this
199
+ change.
200
+
201
+ Evidence: agent-tasks d03af8f6 (pandora run
202
+ `.ai/runs/2026-08-26-open-pool-batch30`, a harness risk-gate deletion
203
+ arm) ran five implementer rounds on the same effort tier (rounds 1-5, the
204
+ default-tier implementer, Sonnet) before this rule existed; each reviewer
205
+ round found one new HIGH on the permissive side of the same detection layer
206
+ (first-segment matching, wrapper flags, xargs flags, a find-root premise
207
+ twice, xargs `-i`/append), and the Round-2 halt rule's split-or-redesign
208
+ response was applied three times (D-014, D-019, D-022/D-023) without ever
209
+ escalating tier, model, or to the advisor, and without a merge-hold. Only
210
+ after round 5 did the operator suggest a stronger model (D-024); round 6, on
211
+ Fable with the `-xhigh` variant, found and closed twelve further fail-open
212
+ classes in one round by its own 248-probe audit, and the following review
213
+ found only one remaining, a documentation-only medium. A same-run comparison
214
+ task, agent-tasks da823721, needed three rounds with one round-2 halt and
215
+ was accepted after it, well inside this budget. This is the first data
216
+ point relating implementer model strength to round count on a
217
+ permissive-security-parser class of task; the 2026-08-24 tier A/B (see
218
+ `[0.23.0]` below) measured only
219
+ `implementer-low` against the default tier on a different task shape,
220
+ not model strength, so whether a stronger model generally shortens
221
+ these rounds remains open.
222
+ - A new `okf-anchor-guard` job in `.github/workflows/ci.yml` (this repo)
223
+ runs okf-kit's anchor check against `docs/okf` and fails the build (no
224
+ branch-protection change; master has no required checks today) when an
225
+ edit to `SKILL.md`, an agent template under `assets/agents/`,
226
+ `src/models.ts`, a `test/*.test.ts` file, any other `src/*.ts` module,
227
+ a run template under `assets/templates/`, or `assets/agents-md-section.md`
228
+ shifts a cited range out of the section or text an anchored bundle
229
+ citation names, instead of only the existing warn-only `okf-staleness.yml`
230
+ drift watch (which never blocks by design and stays untouched). Every
231
+ in-scope bundle citation into those source categories now carries a
232
+ string-form anchor (up from a first-round draft that review round 2
233
+ found had missed 44 bare, non-backtick-delimited citations in two of the
234
+ five docs/okf siblings; the citation parser was corrected to match
235
+ okf-kit's own backtick-optional shape; scope later widened from the
236
+ original four categories to every `src/*.ts` module and every
237
+ `assets/templates/*.md` plus `assets/agents-md-section.md`, agent-tasks
238
+ ca9d5048); the `CHANGELOG.md` citations still carry heading anchors from
239
+ the prior round (that mechanism is untouched, but every CHANGELOG entry
240
+ added above them, this one included, re-points all of them -- see
241
+ `docs/okf/log.md` for the live count and the re-point history, not
242
+ hand-copied here since it drifts with every CHANGELOG edit).
243
+ - Every anchor now satisfies two mechanically-checked properties review
244
+ round 2 added (a first-round anchor sitting on a wide range's first line,
245
+ as 107 of 121 did, survives an insertion shorter than the range itself --
246
+ measured: round 1 had 46 SKILL.md-targeting anchors, and a 1-line
247
+ insertion near the top of SKILL.md left 24 of them silently green): (a)
248
+ the anchor text occurs on the LAST line of its cited range (ranges were
249
+ narrowed where needed to end on real content rather than a
250
+ blank/closing-brace line), and (b) it occurs at most 3 times in the
251
+ whole target file (23 first-round anchors used a too-common token, e.g.
252
+ `describe(`, and were
253
+ replaced). Two anchors were additionally re-pointed because the text
254
+ they carried did not match the claim their citing sentence made, not
255
+ just its mechanical position; see `docs/okf/log.md` for both. Pinned by
256
+ three new tests in `test/docs-consistency.test.ts` (version-pin
257
+ coverage extended to every `.github/workflows/*.yml` file, not just
258
+ `okf-staleness.yml`; the last-line/occurrence-cap rule, verified red
259
+ against the first-round anchors and green against this round's; and an
260
+ erosion brake asserting zero unanchored in-scope citations going
261
+ forward). `ci.yml`'s anchor-finding jq filter now matches any
262
+ `anchor-*`-tagged finding by pattern instead of four hardcoded rule
263
+ ids, guarded by a new self-test step that builds a throwaway fixture
264
+ bundle with one deliberately drifted anchored citation and requires the
265
+ filter to catch it before the real check runs.
266
+ `okf-kit check` reports the same 0 errors / 13 warnings / 22 notices
267
+ before and after this round's full anchor rewrite (0 anchor findings
268
+ either way; the 13 pre-existing warnings are unrelated
269
+ `install-fence-mechanics.md` short-form findings against `init.test.ts`
270
+ and `init.ts`). Differential mutation probe, replacing the first
271
+ round's single 27-finding number: inserting `k` dummy lines near the
272
+ top of SKILL.md, 52/52 (100%) of its unique cited ranges now produce a
273
+ finding at `k=1`; 51/52 (98%) at `k=2`, one named exception (a
274
+ same-block token collision, see `docs/okf/log.md`). A `package.json`
275
+ patch-version bump still leaves the anchor-finding count at 0,
276
+ confirming no false positive. Residual gaps named in `docs/okf/log.md`:
277
+ a content change inside a cited range that neither shifts its line
278
+ count nor disturbs the anchor text stays invisible to this check
279
+ (mechanical, never semantic, the same limit okf-kit's own README
280
+ documents), plus the one named same-block token collision above
281
+ (agent-tasks task 578f5bfd, review round 2; following the
282
+ anchored-citations feature itself, task 5c8013c0, and its release, task
283
+ c0effc67).
284
+
285
+ ### Changed
286
+
287
+ - `docs/okf/subagent-contracts-superset.md`: rewrote its 22 sibling short-
288
+ form citations (21 initially, plus one missed and fixed this round) from
289
+ the parenthesized form (`(N-M)`) to the colon form (`, :N-M`) so
290
+ `citations-resolve` checks them again. Neither form was ever machine-
291
+ checked in a released `okf-kit`: the colon-form gate and the drop of
292
+ paren-form collection landed in the same `[Unreleased]` entry, so
293
+ "dropped" overstates it. Inserting this entry shifts every later line
294
+ number in this file, so any absolute-line `CHANGELOG.md` citation below
295
+ it breaks until re-pointed; this round re-points all sixteen such
296
+ citations across the three touched docs/okf siblings
297
+ (`subagent-contracts-superset.md`, `review-gate-and-waivers.md`,
298
+ `run-state-lifecycle-and-markers.md`), each checked against the
299
+ `## [x.y.z]` section its own sentence names, not against a byte-diff of a
300
+ moving base. `okf-kit check` against a repo build (not the published
301
+ package) reports 0 errors / 13 warnings / 22 notices; all 13 are
302
+ pre-existing `install-fence-mechanics.md` short-form findings unrelated
303
+ to this change, so the three touched docs carry no citations-resolve or
304
+ sources-fresh finding of their own (log.md records the fuller
305
+ sources-fresh investigation, since that count depends on this round's
306
+ commit shape, not on the citations themselves). Coverage holds only
307
+ against a repo build: CI's `okf-staleness.yml` still pins the published
308
+ `okf-kit@0.5.0`, which predates short-form colon resolution, so it
309
+ reports 0 short-form findings until that release ships (agent-tasks task
310
+ 2e3e5f4b).
311
+ - All sixteen `CHANGELOG.md` citations across the three `docs/okf` siblings
312
+ above now also carry a heading anchor (`` `CHANGELOG.md:N-M#x.y.z` ``, a
313
+ new `citations-resolve` form -- see okf-kit's own CHANGELOG for the
314
+ design), pinning each one to the release section its own sentence names
315
+ instead of only to a line range that a future top-of-file insertion can
316
+ silently shift into the wrong section. `okf-kit check` against a repo
317
+ build still reports the same 0 errors / 13 warnings / 22 notices as
318
+ above (all pre-existing, unrelated to this change); a mutation probe that
319
+ moved one migrated citation's range into its neighbouring release
320
+ section, and a second probe that inserted a dummy entry at the top of
321
+ this file (shifting every citation below it), were both caught by the
322
+ new anchor check and reverted (agent-tasks task 5c8013c0).
323
+
324
+ ### Corrections
325
+
326
+ - Correction to the "Known limit of the pack" note in the 0.24.0 entry
327
+ below: this is not an `orchestrator-workflow` behavior change, it
328
+ documents a `slop-detector` fix. The 0.24.0 note described a known limit
329
+ of `placement-slop`, that an `allow` match suppressed every placement
330
+ rule on the line it matched, not just the marker span it was meant to
331
+ excuse. `slop-detector` has since fixed this (`placement.allow` is now
332
+ span-scoped, not line-wide). Consumer-visible effect: a config that
333
+ reported clean before can now report a `block`-severity finding (e.g.
334
+ `placement-slop/home-path`) when a home path, a date, or a tally phrase
335
+ shares a line with an allowed marker.
336
+
8
337
  ## [0.24.0] - 2026-08-24
9
338
 
10
339
  ### Changed
package/INSTALL-AGENT.md CHANGED
@@ -31,10 +31,23 @@ which is mutable. For a stable audit, pin the URL to a commit SHA instead
31
31
  3. **Run the non-interactive installer** with your answers:
32
32
  `npx orchestrator-workflow init --yes --harness ... --profile ... --models ... [--tiers]`.
33
33
  If the installer reports conflicts with locally edited files, the agent
34
- shows them to you and asks before any `--force` re-run.
34
+ shows them to you and asks before any `--force` re-run. **The operator
35
+ path**: when an operator has already run `orchestrator-workflow setup`
36
+ on this machine (an operator manifest exists at
37
+ `<operator home>/manifest.json`, where the operator home is
38
+ `~/.orchestrator-workflow/` unless `ORCHESTRATOR_WORKFLOW_HOME` names a
39
+ different directory), the agent runs
40
+ `orchestrator-workflow apply --target <repo>` instead of `init`, which
41
+ sources its defaults from that operator install and registers the
42
+ repository under it. A repository that already has the kit installed
43
+ and only needs bringing under that management, with nothing in it
44
+ changed, is registered with `orchestrator-workflow adopt <repo>`
45
+ instead of either command.
35
46
  4. **Manual fallback only when npx or the registry is unavailable**: create
36
47
  the same files by hand from this repository's `assets/` directory,
37
- following the byte-precise rules in step 4 below.
48
+ following the byte-precise rules in step 4 below. This manual path
49
+ covers `init` only; there is no manual equivalent for `apply` or
50
+ `adopt`, both of which require the installed CLI.
38
51
  5. **Report back**: which harnesses were installed, which profile and model
39
52
  each role uses, whether effort-tier variants were rendered, and any
40
53
  conflicts left in place.
@@ -44,7 +57,18 @@ which is mutable. For a stable audit, pin the URL to a commit SHA instead
44
57
  The install creates or touches only these paths:
45
58
 
46
59
  - `.ai/workflow/templates/00-goal.md` through `06-handoff.md`,
47
- `.ai/workflow/manifest.json`, `.ai/runs/.gitkeep` (new files)
60
+ `.ai/workflow/manifest.json`, `.ai/runs/.gitkeep` (new files). The
61
+ orchestrator later writes a per-worktree `.ai/run` pointer at run time (a
62
+ machine-local absolute path, not written by the installer); add it to the
63
+ repository's `.gitignore`. This repository's own `.ai/workflow/manifest.json`
64
+ can additionally carry one optional field, `pin`: a kit version recorded
65
+ by `apply --pin`/`--unpin`/`--force-pin`, absent when no pin was ever set.
66
+ - **Operator path only** (`apply`/`adopt`, not `init`): the operator's own
67
+ home's manifest, `<operator home>/manifest.json`, where the operator home
68
+ is `~/.orchestrator-workflow/` unless `ORCHESTRATOR_WORKFLOW_HOME` names a
69
+ different directory, gains or updates its record of this repository,
70
+ guarded by a transient `.manifest.lock` directory held only for the
71
+ duration of that write. Neither path lives inside the target repository.
48
72
  - `AGENTS.md`: the marker-fenced workflow section is appended (file created
49
73
  when missing); content outside the
50
74
  `<!-- orchestrator-workflow:begin -->` / `<!-- orchestrator-workflow:end -->`
@@ -126,6 +150,19 @@ steps in the repository you were asked to install into.
126
150
  on a re-run. If the command reports conflicts, show them to the operator
127
151
  and ask before re-running with --force.
128
152
 
153
+ **Operator path**: before running `init`, check whether an operator
154
+ manifest already exists on this machine, at
155
+ `<operator home>/manifest.json` (the operator home is
156
+ `~/.orchestrator-workflow/` unless `ORCHESTRATOR_WORKFLOW_HOME` names a
157
+ different directory). If it does, run
158
+ `orchestrator-workflow apply --target <repo>` with the same flags in
159
+ place of `init --yes` instead: it sources its defaults from the operator
160
+ install and the target's own prior settings, and registers the
161
+ repository. If the repository already has the kit installed and the
162
+ operator only wants it brought under that management without any file
163
+ changes, run `orchestrator-workflow adopt <repo>` instead and skip the
164
+ rest of this step.
165
+
129
166
  4. Only if npx or the registry is unavailable, scaffold manually from
130
167
  https://github.com/LanNguyenSi/agent-dx/tree/master/packages/orchestrator-workflow/assets.
131
168
  This manual path does not cover `--tiers`: it never renders
@@ -135,7 +172,10 @@ steps in the repository you were asked to install into.
135
172
 
136
173
  - `.ai/workflow/templates/00-goal.md` through `06-handoff.md` from
137
174
  `assets/templates/`, unchanged.
138
- - `.ai/runs/.gitkeep`, empty.
175
+ - `.ai/runs/.gitkeep`, empty. The orchestrator later writes a
176
+ per-worktree `.ai/run` pointer at run time (a machine-local absolute
177
+ path, not written by the installer); add it to the repository's
178
+ `.gitignore`.
139
179
  - Append the content of `assets/agents-md-section.md` to `AGENTS.md`
140
180
  (create the file when missing; the installer starts a fresh file with a
141
181
  `# Agent instructions` heading). Never change anything outside the
package/README.md CHANGED
@@ -73,6 +73,26 @@ npx orchestrator-workflow init --harness claude,codex,opencode --models "impleme
73
73
  npx orchestrator-workflow init --profile minimal --yes
74
74
  ```
75
75
 
76
+ **Templates-only mode.** `--harness none` (the literal word `none`, on its
77
+ own) installs only `.ai/workflow/**` and `.ai/runs/.gitkeep`: no
78
+ `AGENTS.md`, no `CLAUDE.md`, no harness-specific directory, and a manifest
79
+ recording `harnesses: []`. Use it for a repo that wants the run-state
80
+ templates and the workflow itself, but no per-harness subagent files yet
81
+ (e.g. no harness has been chosen, or the files were dropped by hand).
82
+ `none` combined with a real harness name (`--harness none,claude`) is
83
+ rejected as ambiguous rather than silently picking one. A plain
84
+ **non-interactive** re-run (no `--harness` flag) after a templates-only
85
+ install stays templates-only; add a harness back with an explicit
86
+ `--harness <list>` on a later run, the same explicit-flag-wins rule
87
+ `--profile`/`--models`/`--tiers` use, applied to the no-harness case. An
88
+ **interactive** re-run is different: it still prompts, with nothing forced
89
+ pre-selected, instead of silently skipping straight back to templates-only
90
+ without asking; deselect every checkbox to stay templates-only.
91
+
92
+ ```bash
93
+ npx orchestrator-workflow init --harness none --yes
94
+ ```
95
+
76
96
  To let a coding agent do the install, give it this single line:
77
97
 
78
98
  ```text
@@ -97,6 +117,10 @@ to a commit SHA for a stable audit.
97
117
  AGENTS.md marker-fenced "Agentic Coding Workflow" policy section
98
118
  ```
99
119
 
120
+ The orchestrator writes a `.ai/run` pointer file in every worktree a run
121
+ touches (a machine-local absolute path, not written by the installer); add
122
+ it to the repository's `.gitignore`.
123
+
100
124
  Per selected harness:
101
125
 
102
126
  | Harness | Files | Notes |
@@ -329,14 +353,107 @@ effort actually taking effect.
329
353
  The pin is also emitted unconditionally regardless of which model the role
330
354
  resolves to via `--models`, including a model with no effort support at all
331
355
  (e.g. `--models reviewer=haiku` still renders `model: haiku` followed by
332
- `effort: high`). A wire probe on 2026-08-19 (not re-measured for this doc)
333
- showed the Claude Code CLI silently drops the `effort:` parameter for Haiku
334
- 4.5 rather than rejecting it: the value is ignored, not an install-time or
335
- run-time error.
356
+ `effort: high`). On Haiku 4.5, which does not support the `effort`
357
+ parameter, the harness ignores the pinned value rather than rejecting it
358
+ (anchored by a measurement, see CHANGELOG 0.23.0).
359
+
360
+ ## Operator-level install
361
+
362
+ Alongside `init`, which installs the kit into one repository from that
363
+ repository's own working directory, an operator who maintains many
364
+ repositories can set defaults once and project them onto each target
365
+ instead of re-answering the same prompts per repo. This layer adds no new
366
+ binary: `setup`, `apply`, `doctor`, and `adopt` below are subcommands of the
367
+ same `orchestrator-workflow` CLI `init` and `uninstall` already ship as, and
368
+ `init`/`uninstall` remain fully supported and unchanged for a
369
+ single-repository install.
370
+
371
+ ```bash
372
+ orchestrator-workflow setup --yes
373
+ orchestrator-workflow apply --target /path/to/repo
374
+ ```
375
+
376
+ **`setup`** writes or updates this operator's default install options
377
+ (harnesses, profile, models, tiers) as the baseline for future installs; it
378
+ touches no repository. A flag always wins; a flag-less re-run keeps the
379
+ previously stored values; a first-ever `setup` falls back to `claude` /
380
+ `full` / the kit's default models / tiers off. `setup` takes the same
381
+ option flags as `init` (`--harness`, `--profile`, `--models`, `--tiers` /
382
+ `--no-tiers`, `--opencode-provider`, `--yes`). The defaults live in
383
+ `<operator home>/manifest.json`, where the operator home is
384
+ `~/.orchestrator-workflow/` unless the `ORCHESTRATOR_WORKFLOW_HOME`
385
+ environment variable names a different directory.
386
+
387
+ **`apply --target <repo>`** projects the operator's install onto a target
388
+ repository and registers that target, by its real resolved path, in the
389
+ operator manifest. It requires a prior `orchestrator-workflow setup`;
390
+ without one it exits `1` with "No operator setup found". Option resolution
391
+ follows one precedence order: an
392
+ explicit flag wins, then the target's own previously recorded settings,
393
+ then the operator's defaults (harnesses fall back one step further, to
394
+ what `init` would have auto-detected). Pass `--sync` to invert that for
395
+ profile, tiers, and models: the operator's defaults then win over whatever
396
+ the target already had recorded. A target pinned to a kit version other
397
+ than the one being applied is skipped rather than touched (see the pin
398
+ rule below). `apply` also takes the same install options as `init` (`--harness`,
399
+ `--profile`, `--models`, `--tiers` / `--no-tiers`, `--opencode-provider`,
400
+ `--force`, `--yes`), which feed the precedence rule above.
401
+
402
+ **`doctor [--json] [--prune]`** reports every operator-registered target's
403
+ status: `clean`, `divergent` (from the operator defaults), `version-lag`,
404
+ `drift` (installed files edited, deleted, or unreadable since install),
405
+ `missing`, `no-manifest`, or `unverifiable`. It exits `2` when the operator
406
+ manifest is missing or unreadable, or, with `--prune`, when the operator
407
+ manifest lock cannot be acquired or the rewrite fails; `1` when any target
408
+ is `drift`, `missing`, `no-manifest`, or `unverifiable`; and `0` otherwise.
409
+ `--json` prints one JSON object instead
410
+ of human output, with one entry per target plus the operator home and
411
+ version. `--prune` removes `missing` and `no-manifest` targets from the
412
+ registry before reporting (never an `unverifiable` one, since that status
413
+ means the check itself was inconclusive, not that the target is confirmed
414
+ gone) and rewrites the manifest file in its normalized form.
415
+
416
+ **`adopt [dir] [--json]`** brings a repository that already has the kit installed,
417
+ by hand or by an earlier `init`, under the operator's management without
418
+ changing anything in that repository: it registers the repository
419
+ verbatim, using the repository's own recorded settings to bootstrap the
420
+ operator manifest when none exists yet, records the repository's own
421
+ installed version as its baseline, and prints that one target's `doctor`
422
+ report. It exits `1` only when the freshly adopted target itself reports
423
+ drift, and `2` for a precondition failure (no repo manifest, an unreadable
424
+ or foreign manifest, or a lock or write failure).
425
+
426
+ **The kit-version pin.** A repository's own manifest can additionally
427
+ carry an optional `pin`: a kit version that `apply` must match before it
428
+ will touch that repository again. `apply` skips (exit `0`) a target pinned
429
+ to a different version than the one being applied. `--pin <version>` sets
430
+ or replaces the pin and applies regardless of any existing one; `--unpin`
431
+ clears it and applies; `--force-pin` advances an existing pin that
432
+ differs, but has no effect on a target with no pin recorded (it stays
433
+ unpinned). `doctor` reports `version-lag` when the installed version
434
+ differs from the running kit version; on a pinned target the pin is
435
+ compared against the installed version instead, so a pin equal to the
436
+ installed version is `clean` and a pin that no longer matches it is
437
+ `version-lag`.
438
+
439
+ **The registry is implicit**, not a separate command: `apply` and `adopt`
440
+ register a target as a side effect of a real run, and `doctor --prune` is
441
+ how a registry entry is removed again; there is no bare register or
442
+ unregister command. The workspace root of a multi-repo checkout is treated
443
+ as an ordinary target, nothing special.
444
+
445
+ All writes to the operator manifest, by `setup`, `apply`, `doctor --prune`,
446
+ and `adopt` alike, go through one advisory lock in the operator home, so
447
+ concurrent orchestrator-workflow commands on the same machine cannot
448
+ corrupt each other's state.
336
449
 
337
450
  ## Ownership and re-runs
338
451
 
339
- `init` is idempotent: a second run changes nothing. The rules:
452
+ `init` is idempotent: a second run changes nothing. `apply` installs
453
+ through that same `runInit` path and is subject to the same
454
+ conflict/`--force`/ownership rules; on the repository side it changes
455
+ nothing either, but it refreshes this target's entry in the operator
456
+ manifest on every run. The rules:
340
457
 
341
458
  - `AGENTS.md` and `CLAUDE.md` belong to you. The installer only appends its
342
459
  fenced section or the import line, and on re-run replaces only the content
@@ -347,9 +464,9 @@ run-time error.
347
464
  updates files you never touched and reports files you edited as conflicts
348
465
  instead of overwriting them; `--force` overwrites those too.
349
466
  - `.ai/workflow/manifest.json` is the kit's state file. It records the applied
350
- version, harnesses, role profile, models, the `--tiers` flag, and file
351
- hashes, and is rewritten whenever that state changes; do not edit it by
352
- hand.
467
+ version, harnesses, role profile, models, the `--tiers` flag, the optional
468
+ kit-version pin, and file hashes, and is rewritten whenever that state
469
+ changes; do not edit it by hand.
353
470
 
354
471
  ## Uninstall
355
472
 
@@ -26,6 +26,11 @@ Check, at minimum:
26
26
  reusable instruction file (a skill, an agent prompt, an AGENTS.md section, a
27
27
  template)? Report it; the fix is to move the evidence to the changelog, the
28
28
  run files, or the consuming workspace and leave a one-line pointer.
29
+ - Recurrence: when the briefing tells you this is not the task's first
30
+ review round, classify each finding as `new` or `repeated` against the
31
+ earlier rounds you were told about; on a first round every finding is
32
+ `new` by definition. The orchestrator uses this to detect the
33
+ review-round escalation budget's trigger.
29
34
 
30
35
  Rules:
31
36
 
@@ -73,6 +78,7 @@ findings:
73
78
  category: correctness | architecture | security | tests | maintainability | performance | docs
74
79
  description: ""
75
80
  suggested_fix: ""
81
+ recurrence: new | repeated
76
82
  acceptance_recommendation: accept | accept_with_notes | fix_required | reject
77
83
  missing_tests:
78
84
  - ""
@@ -103,6 +103,21 @@ trivial change.
103
103
  the Accepted Waivers section of `06-handoff.md`.
104
104
  - Medium and low findings are addressed or consciously accepted at the
105
105
  orchestrator's judgment.
106
+ - Review-round escalation budget: by the second round-2 halt signal on a
107
+ task, or its third `fix_required` review round, whichever comes first,
108
+ the orchestrator picks one of tier/model escalation (raise the
109
+ implementer to at least `-xhigh` where installed, or to the strongest
110
+ model available, until that is exhausted), an advisor spawn (where the
111
+ advisor is installed, `full` profile only; under a `minimal` profile
112
+ the exhausted tier path falls straight to the merge-hold), or an
113
+ operator merge-hold, and adds a row (task, choice, reason) to
114
+ `03-decisions.md`'s Review-round escalation table, then sets the
115
+ `review-round-escalation` marker to the most recent choice. A counted
116
+ round is a completed reviewer return recommending `fix_required` or
117
+ `reject`; a misfired review is not a round. Which of the three is
118
+ picked is judgment; that one is picked and recorded is not. Escalating
119
+ never substitutes for a review round and comes in addition to the halt
120
+ rule's split-or-redesign response, not instead of it.
106
121
 
107
122
  ### Instruction trust boundary
108
123
 
@@ -135,11 +150,15 @@ Workflow state lives under `.ai/`:
135
150
 
136
151
  - `.ai/workflow/templates/` holds the canonical file templates
137
152
  (`00-goal.md` through `06-handoff.md`).
138
- - Each unit of work gets a run directory `.ai/runs/YYYY-MM-DD-<slug>/`,
139
- created by copying the templates. The newest run directory is the active
140
- one; older ones are the auditable history.
153
+ - Each unit of work gets a run directory `.ai/runs/YYYY-MM-DD-<slug>/` (in
154
+ the workspace or a touched repository), created by copying the templates.
155
+ The newest run directory is the active one; older ones are the auditable
156
+ history.
141
157
  - `.ai/workflow/manifest.json` records the installed kit version, the chosen
142
158
  harnesses, and the per-role model preferences.
159
+ - Every worktree a run touches carries a `.ai/run` pointer (absolute path of
160
+ the run directory, gitignored) and `00-goal.md` carries one
161
+ `run-base[<repo-basename>]` marker per repository for multi-repo runs.
143
162
 
144
163
  ### Models
145
164