omp-conductor 0.2.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/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "omp-conductor",
3
+ "version": "0.2.0",
4
+ "type": "module",
5
+ "license": "MIT",
6
+ "description": "A 24/7 dispatcher that takes ready GitHub issues to green, mergeable PRs using omp coding sessions, with tiered escalation first to an orchestrator session and then to a human.",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/TerrifiedBug/conductor.git",
10
+ "directory": "omp"
11
+ },
12
+ "main": "./src/plugin.ts",
13
+ "omp": {
14
+ "extensions": [
15
+ "./src/plugin.ts",
16
+ "./src/orchestrator-tick.ts"
17
+ ]
18
+ },
19
+ "bin": {
20
+ "omp-conductor": "./src/cli.ts"
21
+ },
22
+ "files": [
23
+ "src",
24
+ "!src/**/*.test.ts",
25
+ "skills",
26
+ "README.md",
27
+ "LICENSE"
28
+ ],
29
+ "scripts": {
30
+ "check": "tsc --noEmit",
31
+ "test": "bun test"
32
+ },
33
+ "peerDependencies": {
34
+ "@oh-my-pi/pi-coding-agent": ">=17.1.4"
35
+ },
36
+ "devDependencies": {
37
+ "@types/bun": "^1.2.0",
38
+ "typescript": "^5.7.0"
39
+ }
40
+ }
@@ -0,0 +1,626 @@
1
+ ---
2
+ name: conductor-onboarding
3
+ description: Interview-driven onboarding for omp-conductor. Use when the user wants to set up conductor, onboard a new fleet or project, configure the fleet, asks for conductor setup help, asks what belongs in ORCHESTRATOR.md, or wants an agent's release and merge authority scoped and written down. Interviews the operator on release policy, escalation taste and reporting scope, reads each routing repo's CI to propose the real pre-push gates, learns the product and roadmap the fleet will groom, scaffolds the release procedure from the repo's own release workflows rather than from the operator's memory, tailors ORCHESTRATOR.md from the shipped template, verifies the worker brief's assumptions against the actual repos, then finishes through the deterministic /conductor setup wizard.
4
+ ---
5
+
6
+ # Onboarding a conductor fleet
7
+
8
+ Onboarding has two layers, and they are not the same job.
9
+
10
+ - **`/conductor setup` is the mechanical layer.** It is deterministic, tested, and
11
+ the **only** thing that writes `config.json`. It asks closed questions, plans
12
+ labels, prints a dry run, and mutates nothing until the operator confirms.
13
+ - **You are the judgement layer.** The wizard cannot ask "where should this fleet
14
+ stop?" and get a useful answer from a text prompt, and it cannot read a repo to
15
+ find out what CI actually runs. That is the part that decides whether an
16
+ unattended fleet is safe, and it is yours.
17
+
18
+ So: **you interview and investigate; the wizard writes.** Never hand-edit
19
+ `config.json`, never construct it and ask for a blessing, never skip the wizard's
20
+ dry run. Its consent gate is the safety property; going around it removes the one
21
+ step where the operator sees what is about to change.
22
+
23
+ Two more ground rules before you start.
24
+
25
+ **Do not recite this file.** Nothing here is a script to read aloud. Every
26
+ question below exists to extract one decision; ask it in your own words, in the
27
+ operator's vocabulary, and skip the ones the repo already answers. An interview
28
+ where you ask and they answer is worth more than a checklist you both step
29
+ through.
30
+
31
+ **Investigate before you ask.** Anything discoverable — default branches, CI
32
+ jobs, gate commands, whether a repo has a `Makefile` — you read, then propose.
33
+ Asking an operator to recite their own CI config is how gates end up wrong: they
34
+ tell you what they *think* runs, and the fleet pushes on it at 03:00.
35
+
36
+ ---
37
+
38
+ ## Step 0 — orient
39
+
40
+ Before the first question, find out where you are:
41
+
42
+ ```bash
43
+ gh auth status # repo + project scopes, and who the token is
44
+ cat ~/.omp/conductor/config.json # honours $OMP_CONDUCTOR_HOME
45
+ ```
46
+
47
+ - **Config already there?** This is a re-run or a second project. The wizard
48
+ pre-fills from the existing project and replaces it in place, keeping its
49
+ neighbours — so the interview is now about *what changed*, not everything.
50
+ Read the existing project out loud and ask what is wrong with it.
51
+ - **`gh` missing `repo` or `project`?** Say so now. The wizard warns at the
52
+ confirm, but a token that cannot label issues means every claim fails, and it
53
+ is cheaper to fix before the interview than after.
54
+ - **An `ORCHESTRATOR.md` already exists** at `<workspaceRoot>/ORCHESTRATOR.md`
55
+ (default `~/.omp/conductor/worktrees/ORCHESTRATOR.md`)? Read it. It is the
56
+ operator's accumulated policy, and it outranks the shipped template. Your job
57
+ becomes amending it, and you must warn that a wizard re-run offers to overwrite
58
+ it.
59
+
60
+ ---
61
+
62
+ ## Step 1 — the interview
63
+
64
+ Ask for decisions, not for values you could look up. Each question below carries
65
+ the reason it matters; when you ask it, lead with that reason. An operator who
66
+ understands why a question is being asked gives a usable answer.
67
+
68
+ ### Project and tracker
69
+
70
+ **"What is this fleet called, and which one repo holds the queue?"**
71
+
72
+ *Why:* the project name is the handle for everything afterwards
73
+ (`/conductor status <name>`, `--project <name>`), and the tracker is the **one**
74
+ `owner/repo` whose open-issue list *is* the queue. Nothing else is ever read.
75
+
76
+ Say the part that surprises people: **the tracker repo does not have to contain
77
+ any code.** A planning repo whose only content is issues is the normal shape, and
78
+ it is often the better one — the queue then has its own label namespace and its
79
+ own permissions, separate from the code it dispatches into.
80
+
81
+ Then: **"What label means a human has signed this off?"** Default
82
+ `ready-for-agent`. *Why:* this label is the entire consent mechanism for
83
+ unattended work. The conductor never adds it. Everything the fleet ever does
84
+ starts with a human putting that label on an issue, so it should read like a
85
+ decision, not like a status.
86
+
87
+ The three state labels (`agent:in-progress`, `agent:blocked`, `agent:failed`) are
88
+ written *by* the conductor so the tracker alone shows live state. Only ask about
89
+ renaming them if the repo already has a colliding label convention — the
90
+ namespaced defaults are right almost always, and the wizard asks with one confirm.
91
+
92
+ ### Routing — what lands where
93
+
94
+ **"Which code repos does this queue dispatch into, and how would you tell them
95
+ apart on an issue?"**
96
+
97
+ *Why:* an issue must carry **exactly one** `repo:<name>` label naming a repo in
98
+ `routing.repos`. Zero or two is reported unroutable and skipped — never guessed.
99
+ Routing is the fan-out: one tracker, any number of code repos.
100
+
101
+ For each repo you need the clone URL and the default branch, but **look those up**
102
+ rather than asking (Step 2). What you actually need from the operator is the
103
+ routing *key* — the word that goes after the prefix — and it should be the word
104
+ they already use in conversation about that repo, because they are the one who
105
+ will be typing it onto issues at 2am.
106
+
107
+ Prefer an SSH clone URL, or an https URL backed by a credential helper. A URL
108
+ with a credential in it gets persisted into the mirror's git config exactly as it
109
+ would for a hand-run clone; say that out loud if you see one.
110
+
111
+ ### Release policy — the question that actually matters
112
+
113
+ This is the decision the shipped brief exists to protect, so give it room.
114
+
115
+ First, settle who is even a candidate, because operators assume it is the workers
116
+ and it never is. A worker is scoped to one issue: it cannot judge whether a release
117
+ is worth cutting, and it stops at a green PR permanently. **The only two candidates
118
+ are the orchestrator and a human.** The orchestrator is the right agent for it if
119
+ any agent is: it is long-lived, it can see everything that merged since the last
120
+ release, and batching is exactly the judgement a per-issue session cannot make.
121
+
122
+ So frame it as **three** options, in this order, and name the default:
123
+
124
+ 1. **Humans release.** *(default, and what the package ships)* Work ends at a
125
+ green PR. Merging is a separate human action; releasing is a separate human
126
+ action after that. Neither a worker nor the orchestrator ever tags, pins,
127
+ publishes, or deploys. "This needs releasing" becomes something the
128
+ orchestrator *reports*.
129
+ 2. **The orchestrator releases up to a named boundary.** Delegating part of the
130
+ release to the supervising session, with the stopping line written down.
131
+ 3. **The orchestrator releases fully.**
132
+
133
+ Then ask the question that makes option 2 real:
134
+
135
+ > **"Where does the orchestrator's leg END?"**
136
+
137
+ Not "can it release" — *where does its leg stop*. A boundary you cannot state in
138
+ one sentence is not a boundary, and an orchestrator with a vague release mandate
139
+ is one that eventually publishes something at 03:00.
140
+
141
+ Give them a worked answer so they can calibrate. The Veltro deployment's answer:
142
+ **the agent's leg ends at the merged suite pin.** It may open and land the PR that
143
+ bumps the module image tags, because that artefact is reviewable, reversible by a
144
+ revert, and its correctness is checkable by a named CI check. Deploying that pin
145
+ to prod is **operator territory** — it needs a person who can watch it, and who
146
+ owns the rollback. That is a leg with an end: a merge commit.
147
+
148
+ If they choose option 2, capture all five of these, because the brief needs them
149
+ and a missing one is a hole:
150
+
151
+ - **what** may be released — which packages or images, from which branch;
152
+ - **when** — batched how, after which *named* checks are green;
153
+ - **what proof** must be held first — check results actually read, not an
154
+ impression;
155
+ - **what must still be asked, every time**;
156
+ - **what stays permanently forbidden** — force-push, secrets, production data.
157
+
158
+ If they choose option 3, do not just write it down. Warn, concretely:
159
+
160
+ - **Credentials.** Full release means the session holds publish tokens, registry
161
+ credentials, or deploy keys. Those live in the session's environment, exposed to
162
+ every turn, including a turn that went wrong. Ask whether they are willing to
163
+ put that credential in a process that runs unattended for weeks.
164
+ - **Rollback ownership.** An agent that can release owns the 03:00 rollback too,
165
+ and a rollback is a judgement call under time pressure with partial
166
+ information — the exact thing agents are worst at. If the answer to "who rolls
167
+ this back" is a person, then that person is already the release owner, and
168
+ option 2 with a named boundary is the honest configuration.
169
+
170
+ Push back once if the answer is option 3 and the reasoning is "it'll be fine".
171
+ Then record what they decide. It is their fleet.
172
+
173
+ **Then stop, and do not write the section yet.** What you have is the operator's
174
+ *intent*: how much they want to delegate, and where they want the line. The
175
+ *steps* on their side of that line come from the repo's own release machinery, not
176
+ from this conversation. Step 4 reads that machinery and turns the intent into a
177
+ procedure. Writing release steps from an interview answer is how a brief ends up
178
+ prescribing a hand-rolled release the repo's own policy forbids.
179
+
180
+ ### Escalation taste
181
+
182
+ **"What should wake you up, and what can wait for the digest?"**
183
+
184
+ *Why:* there are two tiers, and the split is not adjustable — tier 1 is a worker
185
+ that stopped and asked a question (the orchestrator answers it), tier 2 is
186
+ "nobody can proceed without a human". What *is* adjustable is how tier 2 reaches
187
+ them and how much else comes along with it. An operator who gets paged for
188
+ everything stops reading the pages, which is functionally the same as having no
189
+ escalation channel at all.
190
+
191
+ Concretely, decide:
192
+
193
+ - **Channel.** If `omp-telegram` is installed and paired, the wizard offers that
194
+ chat. If not, tier 2 degrades to an issue comment — a documented fallback, not
195
+ an error, but say plainly that a comment on an issue nobody is watching is a
196
+ page that lands nowhere.
197
+ - **Belt and braces.** Also comment on the issue when a run escalates?
198
+ Recommended yes: a chat message you miss is a run nobody sees, and the comment
199
+ is the durable copy.
200
+ - **Attempts before escalating** (`maxAttemptsPerIssue`, default 3). *Why:* an
201
+ issue that failed three times is not a retry candidate — it is a diagnosis
202
+ task. Setting this high converts a bad issue into a spend line.
203
+
204
+ ### Reporting scope
205
+
206
+ **"Do you want to hear about progress, or only about problems?"**
207
+
208
+ *Why:* this is the one half of the brief that the *config* also knows about,
209
+ because every orchestrator tick appends the matching constraint line to its
210
+ prompt, re-read from the config each tick. It maps onto exactly two values:
211
+
212
+ | Answer | `reporting.scope` | What that means |
213
+ | --- | --- | --- |
214
+ | "Tell me when things happen." | `material` *(default)* | Escalations, plus every material event as it happens: a run reaching a green PR (with link), a run that failed twice, an issue pulled off the queue, a cap that stopped the fleet. |
215
+ | "Only bother me when I'm needed." | `escalations` | Every tier-2 escalation immediately, plus one daily digest. Every other tick silent. |
216
+
217
+ Two honesty notes to pass on:
218
+
219
+ - **Neither scope is an outbound filter.** Nothing inspects the orchestrator's
220
+ messages and drops the ones the scope did not ask for. It is a constraint handed
221
+ to the model each turn, not a gate it is held to.
222
+ - **Changing the scope later does not rewrite an existing `ORCHESTRATOR.md`.** The
223
+ tick line changes; the brief does not. Whoever changes it must edit the brief's
224
+ Reporting section too, or the session is carrying two versions of the policy.
225
+
226
+ ---
227
+
228
+ ## Step 2 — read the repos, then propose the gates
229
+
230
+ **Do this before you ask anything about gates.** The wizard's gate prompt is a
231
+ free-text field; whatever goes in it is what an unattended worker runs before
232
+ every push. It has to match what CI actually runs, and the operator is not the
233
+ best source for that. Their CI config is.
234
+
235
+ For each routing repo, mirror it read-only if you do not have it locally, then
236
+ read:
237
+
238
+ ```bash
239
+ gh api repos/<owner>/<repo> --jq '.default_branch'
240
+ gh api repos/<owner>/<repo>/contents/.github/workflows --jq '.[].name'
241
+ ```
242
+
243
+ and then, in the checkout:
244
+
245
+ - `.github/workflows/*.yml` — the PR-triggered jobs and their exact `run:` lines,
246
+ including their `working-directory`;
247
+ - `package.json` — the `scripts` block (`lint`, `check`, `typecheck`, `test`);
248
+ - `Makefile` / `justfile` / `Taskfile.yml` — many repos put the real gate here and
249
+ have CI call `make check`;
250
+ - `pyproject.toml`, `Cargo.toml`, `go.mod` — for the same reason, in other
251
+ ecosystems;
252
+ - any `CONTRIBUTING.md` / `AGENTS.md` line that names the pre-push command.
253
+
254
+ Then **propose**, do not ask. Show your reading and the exact commands, with the
255
+ `cwd` each runs from, in the format the wizard takes (`cmd`, or `cmd @ cwd`,
256
+ comma-separated; `cwd` defaults to `.`):
257
+
258
+ ```text
259
+ repo:api — from .github/workflows/ci.yml (on: pull_request), jobs lint + test:
260
+ bun run lint @ . # CI: `bun run lint` at repo root, whole tree
261
+ bun run check @ . # CI: tsc --noEmit
262
+ bun test @ . # CI: bun test
263
+
264
+ Is that the set, and is anything missing that CI would catch?
265
+ ```
266
+
267
+ Three warnings to carry, every time:
268
+
269
+ 1. **Whole tree, not the subdirectory.** CI lints everything. A gate that lints
270
+ only `src/` is how an error in a migration, a config file, a script or a test
271
+ fixture reaches the runners. If CI runs `bun run lint` at the root, the gate is
272
+ `bun run lint` at the root — not `bun run lint src`.
273
+ 2. **Cheap gates only.** Do not put docker builds, image builds, production
274
+ builds, browser/e2e suites, or a full integration suite in here. The host is
275
+ shared; CI owns the heavy gates. If a repo's only meaningful check is heavy,
276
+ say so — that repo's workers will lean on CI, and that is a known cost, not
277
+ something to paper over with a fake gate.
278
+ 3. **No gates at all is a real answer, and a loud one.** The wizard warns. Repeat
279
+ the warning in plain terms: a repo with no gates means every unattended push
280
+ is an experiment run on the shared runners.
281
+
282
+ ---
283
+
284
+ ## Step 3 — learn the product
285
+
286
+ The duties assume an orchestrator that understands what it is grooming. Duty 2
287
+ asks it to judge whether acceptance criteria are readable and whether an issue is
288
+ worth claiming at all; neither is answerable by a session that knows only the repo
289
+ names. So learn the product now, and write what you learn into the brief.
290
+
291
+ Read, per routing repo:
292
+
293
+ - the `README` — what the thing is for, and who uses it;
294
+ - whatever top-level architecture doc exists (`docs/`, `ARCHITECTURE.md`, an ADR
295
+ directory), enough to say which repo owns which concern;
296
+ - `AGENTS.md` / `CONTRIBUTING.md` for the repo's own rules, which outrank the
297
+ brief.
298
+
299
+ Then read the tracker as a roadmap rather than as a queue:
300
+
301
+ ```bash
302
+ gh issue list --repo <tracker> --state open --limit 100 --json number,title,labels,milestone
303
+ gh api repos/<tracker>/milestones --jq '.[] | "\(.title) — \(.open_issues) open"'
304
+ gh label list --repo <tracker>
305
+ ```
306
+
307
+ Milestones and the label taxonomy are what separate a theme from a one-off. Epics
308
+ usually surface as one or the other.
309
+
310
+ Then ask the operator exactly one question, because it is the one thing none of
311
+ that reading answers:
312
+
313
+ > **"Where does the roadmap live, and what is the current priority?"**
314
+
315
+ *Why:* a tracker shows what is open, never what matters. An orchestrator that
316
+ cannot rank work grooms by recency, and that is how a stale issue outranks the
317
+ thing the operator is actually shipping this month.
318
+
319
+ **Write the findings into the brief** as a `## Project context` section, in the
320
+ editable half beside Releases — the template ships a stub for it. Keep it under 40
321
+ lines: it is read on every tick, and a brief nobody finishes reading is a brief
322
+ that gets skimmed. It needs four things.
323
+
324
+ 1. **The product in one paragraph.** What it does, for whom. Not a feature list.
325
+ 2. **A repo map** — one line per routing key, naming what that repo owns in the
326
+ operator's vocabulary. This is what turns a routing label into a judgement.
327
+ 3. **Grooming guidance for Duty 2.** Which repos ship together, so a change in one
328
+ is known to need a matching PR in the other. And which kinds of issue touch the
329
+ same files: those must not be queued concurrently, because two workers editing
330
+ one file produce two PRs that cannot both merge.
331
+ 4. **Where the roadmap lives, and how to judge priority against it** — the pointer
332
+ the operator just gave you, in one line.
333
+
334
+ Same order of operations as Step 5: draft it now, and apply it to the brief after
335
+ the wizard has written the file.
336
+
337
+ ---
338
+
339
+ ## Step 4 — scaffold the release process from the repo, not from memory
340
+
341
+ The interview gave you a boundary. This step turns it into steps the operator's
342
+ repos will actually accept, for the same reason Step 2 reads CI instead of asking
343
+ about gates: an operator describes the release they *remember*, and a release is
344
+ the one procedure where being approximately right is worst.
345
+
346
+ Skip this step only for option 1 (humans release). There is nothing to scaffold:
347
+ the shipped paragraph is already correct and the brief keeps it verbatim.
348
+
349
+ ### Find the release authority
350
+
351
+ Per repo that can be released, read:
352
+
353
+ ```bash
354
+ gh api repos/<owner>/<repo>/contents/.github/workflows --jq '.[].name'
355
+ gh release list --repo <owner>/<repo> --limit 10
356
+ git tag --list --sort=-v:refname | head
357
+ ```
358
+
359
+ and then, in the checkout:
360
+
361
+ - **every workflow that publishes anything** — a release, a tag, an image, a
362
+ package, a deployment. For each, the **trigger** is the fact that matters:
363
+ - `workflow_dispatch` → the release is *dispatched*. That workflow is the
364
+ authority, and the correct instruction is "dispatch it with the planned
365
+ version", never "do what it does".
366
+ - `on: push: tags:` → a pushed tag is the trigger, so tagging *is* releasing.
367
+ - `on: release: published` → the GitHub Release is the trigger.
368
+ - **what the workflow enforces.** Many reject a tag unless several version files
369
+ agree. That constraint belongs in the brief, quoted, because it is the failure
370
+ the agent will otherwise hit at 03:00.
371
+ - **`AGENTS.md`, `CONTRIBUTING.md`, and any release runbook.** An explicit policy
372
+ outranks anything you infer from a workflow, and it is usually where the
373
+ *forbidden* paths are named.
374
+ - **whether a release needs a human by construction.** An `npm publish` behind
375
+ interactive 2FA cannot be delegated to an unattended session at all, whatever the
376
+ operator would like. Say so rather than writing a step that cannot run.
377
+
378
+ ### Then write three things, and one of them is the forbidden list
379
+
380
+ Present this back as a proposal, in the repo's own commands, before it goes in the
381
+ brief:
382
+
383
+ 1. **The authority, named.** One sentence: which workflow or command ships this
384
+ repo, and how it is invoked. If it is a protected workflow, the brief says
385
+ *dispatch it and verify the run* and stops there.
386
+ 2. **The steps on the agent's side of the boundary**, as commands, in order, each
387
+ with the check that proves it worked. A step whose success cannot be read from
388
+ a named check is not a step the agent can own.
389
+ 3. **What is forbidden, and why, with the citation.** This is the part that decays
390
+ silently, so it is the part to write down hardest. Cite the file and the line:
391
+ `never mutate the deployment directly or reimplement the release by hand
392
+ (repos/<repo>/AGENTS.md)`. A forbidden path with a source attached survives a
393
+ future session's improvisation; "be careful with releases" does not.
394
+
395
+ ### Ask two things the repo cannot tell you
396
+
397
+ - **"What is a release worth cutting?"** The batching unit, in the repo's own
398
+ vocabulary: a sprint, an epic's children all closed, N merged issues waiting, N
399
+ days elapsed, or urgency. Without this the orchestrator either releases per merge
400
+ (a stream of meaningless versions burning shared runners) or never releases at
401
+ all.
402
+ - **"Who owns the rollback?"** If the answer is a person, that person owns the
403
+ release, and the boundary belongs before the irreversible step regardless of
404
+ what option 2 sounded like in the interview.
405
+
406
+ ### And make it self-correcting
407
+
408
+ A release process is the section most likely to go stale: workflows get replaced,
409
+ and a brief describing the old one still reads plausible. So tell the operator
410
+ plainly, and make sure the brief's own **Learning loop** covers it: when the
411
+ release workflow changes, the brief contradicts repo reality, which is exactly an
412
+ amendment trigger. The session proposes the corrected steps and they approve with
413
+ a yes.
414
+
415
+ ---
416
+
417
+ ## Step 5 — tailor the brief, and show the diff first
418
+
419
+ `src/briefs/orchestrator.md` in this package is the **floor**, not the deliverable.
420
+ It ships deliberately conservative so that an operator who never edits it still
421
+ has a safe fleet. Your job is to raise it to *this* fleet.
422
+
423
+ The file has a hard line in it — an HTML comment banner reading
424
+ `YOURS TO EDIT`. Respect it in both directions:
425
+
426
+ **Above the banner — leave it alone.** Duties (drain, groom, report), the
427
+ escalation-tier table, and the hard boundaries describe how the package already
428
+ behaves. Rewriting them makes the brief disagree with the code, and the code wins.
429
+ The evidence rule in particular is not negotiable: *every claim cites evidence — a
430
+ PR URL, an issue number, or a named check actually read.* "Should be fine",
431
+ "looks green" and "probably passing" are not evidence.
432
+
433
+ Know what is *not* up there, though, because operators expect it to be: the
434
+ orchestrator's own merge and release authority is **not** a hard boundary. It is
435
+ policy, it lives in Releases, and it defaults to none. What is fixed above the
436
+ banner is that a *worker* never merges or releases, and that PRs land one at a time
437
+ with a freshness re-check. Delegating a release to the orchestrator does not touch
438
+ either of those, so it needs no negotiation with the shipped half.
439
+
440
+ **Below the banner — rewrite from the interview.**
441
+
442
+ - **Releases.** Replace the section with the procedure you scaffolded in Step 4. If
443
+ humans-release, say so in one short paragraph and stop; do not leave the "replace
444
+ this paragraph if you are delegating" instructions in a finished brief, because
445
+ a standing prompt full of alternatives it did not choose is a standing prompt
446
+ the session has to guess its way through. If they chose a boundary, write the
447
+ boundary as a sentence with an end — *"your leg ends at the merged pin PR; you
448
+ never deploy it"* — then the scaffolded steps, then the forbidden list with its
449
+ citations. State the merge authority explicitly either way: a brief that
450
+ prescribes landing a release PR without ever saying the orchestrator may merge is
451
+ a brief the session has to infer permission from, and it will infer wrong in one
452
+ direction or the other.
453
+ - **Reporting.** Rewrite it as the one scope they chose, in the second person,
454
+ concretely. Delete the description of the scope they did not choose: it is
455
+ useful in a template and noise in a live prompt. Keep the closing constraint
456
+ verbatim in substance — no narration, no progress updates, no restating the
457
+ brief back. Evidence, or silence.
458
+
459
+ **Then add what the template cannot know: this fleet's own hard boundaries.** Ask
460
+ for them directly:
461
+
462
+ > **"Is there anywhere in these repos an agent must never go, even when an issue
463
+ > says to?"**
464
+
465
+ Typical answers, worth prompting for by name: infrastructure directories
466
+ (`terraform/`, `puppet/`, `ansible/`, `charts/`, `.github/workflows/`), anything
467
+ holding secrets or environment files, migration directories, a vendored or
468
+ generated tree, and **whole repos** that are in the org but off-limits. Write each
469
+ one as a path or repo name, not as a category — "no infra changes" is advice, and
470
+ `never edit terraform/ or .github/workflows/; escalate instead` is a boundary.
471
+
472
+ **Show the diff before writing anything.** Present the tailored sections against
473
+ the shipped template — the sections you rewrote, the boundaries you added, and an
474
+ explicit statement that everything above the banner is untouched. Get an
475
+ acknowledgement. This file becomes the standing prompt for a session that runs
476
+ unattended for weeks; the operator reading it once, now, is the cheapest review it
477
+ will ever get.
478
+
479
+ **Order of operations matters here.** The wizard writes the *template* (with
480
+ coordinates substituted) at the path it owns. So: draft and agree the tailored
481
+ sections now, let the wizard write the rendered floor in Step 7, and apply the
482
+ agreed edits to that file immediately afterwards. Do not pre-write the file to a
483
+ path you guessed, and do not skip the wizard's brief-writing step — you would
484
+ lose the substituted coordinates and the overwrite confirmation.
485
+
486
+ ---
487
+
488
+ ## Step 6 — check the worker brief's assumptions against reality
489
+
490
+ The worker brief makes concrete claims to a session that has no other context. If
491
+ a claim is wrong, the worker cannot tell — it just fails in a confusing way. Check
492
+ each one against the actual repos, and report what you found.
493
+
494
+ 1. **Default branches.** The brief says the worktree is cut from the repo's
495
+ default branch and the PR targets it. Confirm per repo with
496
+ `gh api repos/<owner>/<repo> --jq .default_branch`. A repo on `master`, `develop`
497
+ or `trunk` configured as `main` produces a run that fails at worktree creation.
498
+ 2. **Branch naming.** The conductor cuts `<type>/<slug>`, where type is `fix` when
499
+ an issue label's last segment is `bug` and `feat` otherwise. Check that against
500
+ the repo's convention and its branch protection: a ruleset that only permits
501
+ `feature/*`, or requires a ticket prefix, will reject every push the fleet
502
+ makes. `gh api repos/<owner>/<repo>/rulesets` and the branch-protection settings
503
+ are the place to look.
504
+ 3. **The gates actually run, and exit 0 on a clean checkout.** This is the one
505
+ worth spending real time on. In a clean mirror or worktree, run each proposed
506
+ gate read-only and record the exit code:
507
+ - Safe to run: lint, typecheck, unit tests, formatter `--check` modes.
508
+ - Do **not** run: anything that writes to the working tree (a formatter without
509
+ `--check`), anything that hits the network beyond a package install, docker
510
+ builds, deploys, or a suite that needs live services. If a gate cannot be
511
+ verified safely, say which one and why, rather than asserting it works.
512
+ - A gate that fails on a *clean* checkout is a fleet that can never push. That
513
+ is a finding to report before arming, not after — the operator either fixes
514
+ the repo or drops the gate, and both are their call.
515
+ 4. **Does `pull_request` actually fire?** The whole loop ends with a worker
516
+ watching `gh pr checks --watch` to a verdict. A workflow triggered only on
517
+ `push` to a branch pattern, or gated behind `if: github.actor != ...`, or one
518
+ that requires approval for a first-time contributor, gives a PR with **no
519
+ checks** — and a worker that waits forever on a verdict that never comes. Read
520
+ the `on:` block of each workflow and confirm `pull_request` is there and not
521
+ path-filtered away from the paths this fleet will touch.
522
+
523
+ Report these as findings with evidence, not as reassurance. "I read
524
+ `.github/workflows/ci.yml`; `on: pull_request` is present with no path filter" is a
525
+ finding. "CI should trigger" is not.
526
+
527
+ ---
528
+
529
+ ## Step 7 — finish through the wizard
530
+
531
+ Now hand the collected answers to the deterministic path:
532
+
533
+ ```text
534
+ /conductor setup
535
+ ```
536
+
537
+ You have the answers ready, so this is fast — and it stays the wizard's decision
538
+ to write, not yours. It asks, in this order: project name; tracker repo; queue
539
+ label; whether to rename the state labels; routing label prefix; then per repo the
540
+ routing key, clone URL, default branch and **pre-push gates** (your Step 2
541
+ proposal, in `cmd @ cwd` form); whether to add another repo; caps; the Telegram
542
+ chat id for tier 2; the escalation fallback; the report scope; and finally whether
543
+ to write `ORCHESTRATOR.md`.
544
+
545
+ Two things about the end of it that you must not smooth over:
546
+
547
+ - **The dry run is the point.** Before the confirm, it reads the tracker through
548
+ the same routing code the loop uses and prints exactly what the next tick would
549
+ pick up, which repo each issue routes to, the branch it would cut, and every
550
+ issue it cannot route. Walk the operator through that output. Unroutable issues
551
+ here are the single most useful signal in the whole onboarding: they mean the
552
+ labels and the routing config disagree, and it is far cheaper to see it now.
553
+ - **Nothing is mutated until they answer.** No label created, no config written,
554
+ no state database, no arm. If they decline, the machine is untouched. Never
555
+ answer that confirm on their behalf.
556
+
557
+ Say yes to writing `ORCHESTRATOR.md`, then **immediately apply the edits you
558
+ drafted in Steps 3, 4 and 5** to the file it wrote, and tell them the path. Note
559
+ the trap for later: a future `/conductor setup` re-run offers to overwrite that
560
+ file, and accepting loses every tailored word. Their brief is now a file worth
561
+ keeping a copy of.
562
+
563
+ ### Then walk arm, pause, and disarm — they are three different things
564
+
565
+ Operators conflate these, and the failure modes are not the same.
566
+
567
+ - **Arm** is what that final confirm did, and it is exactly two things: create the
568
+ state database, and clear the pause flag. It does **not** start the daemon —
569
+ `omp-conductor start` does, and it does not report success until the daemon
570
+ answers `GET /healthz`. For a first run, take one tick in the foreground and
571
+ watch it: `omp-conductor daemon --once`.
572
+ - **Pause is maintenance.** `/conductor pause` (or `omp-conductor pause`) writes a
573
+ sentinel in the state directory. The dispatch loop checks it first, so no new
574
+ work is claimed from the next tick; runs already in flight finish rather than
575
+ being killed. The orchestrator heartbeat reads the *same* flag, so pausing the
576
+ fleet also silences its heartbeat — one flag, not two. This is the switch for
577
+ touching a repo, rotating a credential, a release window, or a holiday.
578
+ `resume` undoes it. Nothing is torn down, nothing is forgotten.
579
+ - **Disarm is channel teardown, and it is not a subcommand.** It is removing the
580
+ `armedFile` that `.conductor-tick.json` names — the heartbeat then sends nothing
581
+ and the supervising session simply stops being prompted. Be precise about the
582
+ asymmetry: **disarming stops the heartbeat, not the dispatch loop.** A disarmed
583
+ fleet whose daemon is still up keeps claiming issues with nobody supervising, so
584
+ "stop the fleet" is `pause` (or `omp-conductor stop`) — disarm is "stop waking
585
+ the orchestrator".
586
+ - **And the gate that disarms itself.** If `.conductor-tick.json` names an
587
+ `accessFile`, every tick re-reads the Telegram bridge's `access.json` and
588
+ requires `enabled: true` with exactly **one** paired owner. It fails closed on
589
+ everything else: missing, unreadable, not JSON, disabled, nobody paired, or
590
+ several paired (it refuses to guess which human is on the hook). Unattended
591
+ dispatch is only defensible while a tier-2 escalation can reach a person, so a
592
+ channel that goes away disarms the heartbeat whether or not anyone intended it.
593
+ **A fleet deploy always sets `accessFile`.** Leaving it unset passes the gate —
594
+ that is for ordinary dev sessions, not an off switch.
595
+
596
+ ---
597
+
598
+ ## Step 8 — hand over the learning loop
599
+
600
+ Finish by telling the operator the truth about what they just wrote:
601
+
602
+ **A brief converges from operation, not from an interview.** What you produced
603
+ today is a good first draft, and it is wrong in ways neither of you can see yet.
604
+ Real deployments diverge from the template exactly where the operator learns
605
+ something: a reporting scope that turned out too loud, a release boundary drawn in
606
+ the wrong place, an escalation that should have been a digest line, a hard
607
+ boundary nobody thought to name until an agent walked into it.
608
+
609
+ The brief closes that gap itself now. Point them at its **Learning loop** section
610
+ and say what it means in practice:
611
+
612
+ - **Their corrections are the trigger.** When they tell the orchestrator to work
613
+ differently — mid-flight, in a reply to an escalation, anywhere — it drafts the
614
+ matching edit to its own brief instead of just complying once.
615
+ - **Approval is a Telegram yes/no.** The proposal arrives as one question carrying
616
+ the exact diff: the current lines, then the replacement. Yes applies it. No, or
617
+ no answer at all, drops it, and it does not raise that amendment again.
618
+ - **Two things it will never do:** propose relaxing **Hard boundaries** (that
619
+ section changes only when they hand-edit it), or interrupt a tick's duties to
620
+ ask.
621
+ - **Every applied amendment is logged** as one line under **Amendments** at the
622
+ bottom of the brief — date, trigger, summary. That list is the honest record of
623
+ where this interview was wrong, and it accumulates without anyone scheduling it.
624
+
625
+ That is the whole handover. Convergence is now the loop's job rather than a habit
626
+ the operator has to keep.