omp-conductor 0.14.0 → 0.15.1

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/src/board.ts CHANGED
@@ -7,6 +7,7 @@ import {
7
7
  codeGraphFromHealthz,
8
8
  fleetLayers,
9
9
  probeTelegramHealth,
10
+ workerPhasesFromHealthz,
10
11
  type FleetLayers,
11
12
  type TelegramHealth,
12
13
  } from "./fleet.ts";
@@ -922,36 +923,6 @@ export function renderBoard(
922
923
  ].join("\n");
923
924
  }
924
925
 
925
- export function workerPhasesFromHealthz(
926
- body: string | undefined,
927
- project: string,
928
- ): ReadonlyMap<number, WorkerPausePhase> {
929
- const phases = new Map<number, WorkerPausePhase>();
930
- if (body === undefined) return phases;
931
- try {
932
- const payload = JSON.parse(body) as unknown;
933
- if (payload === null || typeof payload !== "object") return phases;
934
- if (Reflect.get(payload, "project") !== project) return phases;
935
- const workers = Reflect.get(payload, "workers");
936
- if (!Array.isArray(workers)) return phases;
937
- for (const worker of workers) {
938
- if (worker === null || typeof worker !== "object") continue;
939
- const issue = Reflect.get(worker, "issue");
940
- const phase = Reflect.get(worker, "phase");
941
- if (
942
- Number.isSafeInteger(issue) &&
943
- (issue as number) > 0 &&
944
- (phase === "pausing" || phase === "paused")
945
- ) {
946
- phases.set(issue as number, phase);
947
- }
948
- }
949
- } catch {
950
- // An unreadable health body means no trustworthy pause phase.
951
- }
952
- return phases;
953
- }
954
-
955
926
  async function probeBoardHealth(project: ProjectConfig): Promise<BoardHealthProbe> {
956
927
  const layers = fleetLayers(project.name);
957
928
  const record = livingDaemon();
@@ -966,8 +937,24 @@ async function probeBoardHealth(project: ProjectConfig): Promise<BoardHealthProb
966
937
  else if (health?.ok !== true) daemon = "unreachable";
967
938
  else {
968
939
  try {
969
- const payload = JSON.parse(health.body ?? "null") as { project?: unknown };
970
- daemon = payload.project === project.name ? "ok" : "other-project";
940
+ const payload = JSON.parse(health.body ?? "null") as unknown;
941
+ if (payload === null || typeof payload !== "object") {
942
+ daemon = "unreachable";
943
+ } else if (Reflect.get(payload, "project") === project.name) {
944
+ daemon = "ok";
945
+ } else {
946
+ const projects = Reflect.get(payload, "projects");
947
+ daemon =
948
+ Array.isArray(projects) &&
949
+ projects.some(
950
+ (entry) =>
951
+ entry !== null &&
952
+ typeof entry === "object" &&
953
+ Reflect.get(entry, "project") === project.name,
954
+ )
955
+ ? "ok"
956
+ : "other-project";
957
+ }
971
958
  } catch {
972
959
  daemon = "unreachable";
973
960
  }
@@ -575,7 +575,7 @@ export function formatBriefReport(path: string, layout: BriefLayout, missing: re
575
575
  return [
576
576
  `brief ${path}`,
577
577
  "",
578
- "No brief here yet. Run /conductor setup and say yes to writing ORCHESTRATOR.md;",
578
+ "No brief here yet. Run `omp-conductor setup brief` and say yes to writing ORCHESTRATOR.md;",
579
579
  "it writes POLICY.md beside it, which is the half you then own.",
580
580
  ].join("\n");
581
581
  }
@@ -16,8 +16,10 @@ Point the heartbeat at the workspace that holds `ORCHESTRATOR.md` /
16
16
  `POLICY.md` — a `.conductor-tick.json` whose default message re-reads both.
17
17
 
18
18
  This floor ships conservative so an unedited `POLICY.md` is still a safe fleet.
19
- To tailor Releases and Project context, ask an omp session to read
20
- `skill://conductor-onboarding` and onboard you.
19
+ To tailor Releases and Project context, run `omp-conductor setup brief`: it asks
20
+ the judgment questions no repo reading can answer, then reads your repos to draft
21
+ the rest and shows each draft for confirmation. Editing `POLICY.md` by hand does
22
+ the same job.
21
23
 
22
24
  ---
23
25
 
@@ -421,9 +423,11 @@ Four controls stop different work:
421
423
  spend a failure or continuation budget. Use it when the operator explicitly
422
424
  ends obsolete or already-delivered work. A salvage failure keeps the tree and
423
425
  names the path; recover that copy before any forced unblock.
424
- - **Fleet dispatch:** `omp-conductor pause` stops new claims and work-starting
425
- mutations. Work admitted before the pause may still complete, and completion
426
- verbs and releases remain available.
426
+ - **Fleet dispatch:** `omp-conductor hold` stops new claims and work-starting
427
+ mutations. Work admitted before it may still complete, and completion verbs and
428
+ releases remain available. Note it also disarms ticks, so it silences *you*:
429
+ stopping the fleet is the operator's call, and the right move is to report that
430
+ it needs stopping rather than to run this yourself.
427
431
  - **Orchestrator ticks:** `omp-conductor disarm` removes the operator-owned
428
432
  `ARMED` marker so ticks skip. It does not pause workers or stop processes.
429
433
 
@@ -52,10 +52,10 @@ propose the corrected steps.
52
52
 
53
53
  ## Project context (filled during onboarding)
54
54
 
55
- Empty until an onboarding session fills it in: the product in a paragraph, a map
56
- of which repo owns what, and the grooming guidance Duty 2 needs to judge priority
57
- and spot issues that would collide. Ask an omp session to read
58
- `skill://conductor-onboarding` to have it written.
55
+ Empty until setup fills it in: the product in a paragraph, a map of which repo
56
+ owns what, the grooming guidance Duty 2 needs to judge priority and spot issues
57
+ that would collide, and where the roadmap lives. `omp-conductor setup` asks for
58
+ the last of those and proposes the rest.
59
59
 
60
60
  ## Reporting
61
61
 
@@ -0,0 +1,51 @@
1
+ You are reading one repository to answer a single question for an operator who is
2
+ configuring an automated dispatcher. You have been given
3
+ reading tools only: there is no shell, no editor and no verb here, so reading and
4
+ answering is the whole of what you can do.
5
+
6
+ ## The question
7
+
8
+ What are the **pre-push gates** for `{{REPO}}` (branch `{{BRANCH}}`)? A pre-push
9
+ gate is a command a change must pass locally *before* it is pushed, and the answer
10
+ is only useful if it matches what CI actually runs.
11
+
12
+ ## Where to look
13
+
14
+ In this order, stopping when you have enough:
15
+
16
+ 1. CI workflow definitions — `.github/workflows/*.yml`, or the equivalent for
17
+ whatever CI this repo uses. This is the authority: it is what will fail a PR.
18
+ 2. `package.json` scripts, `Makefile`, `justfile`, `Taskfile.yml`, `tox.ini`,
19
+ `pyproject.toml`, `Cargo.toml`.
20
+ 3. Any `CONTRIBUTING.md` / `AGENTS.md` / `CLAUDE.md` that names a pre-push
21
+ routine.
22
+
23
+ ## Three traps, each of which produces a wrong answer
24
+
25
+ - **Whole tree, not source directory.** If CI lints the repository and a script
26
+ lints only `src/`, the gate is the repository-wide command. A gate narrower than
27
+ CI is how a lint error reaches the runners with nobody watching.
28
+ - **Cheap only.** Gates run on a shared host, many at once. Include type checks,
29
+ lint and unit tests. **Exclude** docker builds, image builds, production builds,
30
+ browser/e2e suites, and anything that needs a service or a credential — CI owns
31
+ those.
32
+ - **An honest "no gates" is a real answer.** If this repo genuinely has no cheap
33
+ local check, say so with an empty list. Inventing a plausible `npm test` for a
34
+ repo that has no test script produces a gate that fails on every push.
35
+
36
+ Each gate needs the **`cwd` it runs from**, relative to the repository root, as a
37
+ monorepo's checks usually do not run from the top. Use `"."` for the root.
38
+
39
+ ## Answer
40
+
41
+ One fenced JSON block, nothing else after it:
42
+
43
+ ```json
44
+ {
45
+ "gates": [{ "cmd": "bun run check", "cwd": "." }],
46
+ "evidence": "one line naming the files you read that establish these"
47
+ }
48
+ ```
49
+
50
+ `evidence` is what lets the operator judge your answer without repeating your
51
+ reading. Name files, not impressions.
@@ -0,0 +1,59 @@
1
+ You are reading one repository to draft a section of an operator's standing brief.
2
+ You have been given reading tools only: there is no shell,
3
+ no editor and no verb here, so reading and answering is the whole of what you can
4
+ do.
5
+
6
+ ## What you are writing
7
+
8
+ The `## Project context` section of `POLICY.md`, which a supervising orchestrator
9
+ session re-reads on **every** tick. Keep it **under 40 lines**: a brief nobody
10
+ finishes reading is a brief that gets skimmed.
11
+
12
+ It needs exactly four things, in this order.
13
+
14
+ 1. **The product in one paragraph.** What it does, for whom. Not a feature list.
15
+ 2. **A repo map** — one line per routing key below, naming what that repo owns in
16
+ the operator's vocabulary. This is what turns a routing label into a judgement.
17
+ 3. **Grooming guidance.** Which repos ship together, so a change in one is known
18
+ to need a matching PR in the other. And which *kinds* of issue touch the same
19
+ files: those must not be queued concurrently, because two agents editing one
20
+ file produce two pull requests that cannot both merge.
21
+ 4. **Where the roadmap lives, and how to judge priority against it** — in one
22
+ line.
23
+
24
+ ## Where you are
25
+
26
+ Your working directory holds **one directory per routing repo**, each a shallow
27
+ clone, listed below. Read across all of them — that is what makes items 2 and 3
28
+ answerable, and a draft written from one repo has to guess the rest.
29
+
30
+ In each, read the `README` (what it is for, and who uses it), whatever top-level
31
+ architecture doc exists (`docs/`, `ARCHITECTURE.md`, an ADR directory) for which
32
+ repo owns which concern, and `AGENTS.md` / `CONTRIBUTING.md` for the repo's own
33
+ rules — those outrank the brief.
34
+
35
+ ## Stated inputs — these are given, not yours to decide
36
+
37
+ The routing keys this project dispatches to, and the directory each was cloned
38
+ into. Refer to repos by their **routing key**, never by the directory name — the
39
+ directory is scratch, the key is what an issue carries:
40
+
41
+ {{REPOS}}
42
+
43
+ The operator's own answer about the roadmap and the current priority:
44
+
45
+ > {{ROADMAP}}
46
+
47
+ **Item 4 must quote that answer.** You are reading a repository, which shows what
48
+ is open and never what matters; the operator supplied the ranking and it is not
49
+ yours to improve. If the quote above is empty, write item 4 as a single line
50
+ saying the operator has not named a roadmap yet, and nothing more.
51
+
52
+ ## Answer
53
+
54
+ One fenced markdown block containing the section and nothing else — start it at
55
+ the `## Project context` heading. No preamble, no commentary after it.
56
+
57
+ Write what the repository supports. Where you are guessing, say so in the text
58
+ itself in a few words: the operator edits this file, and a marked guess is one
59
+ they can correct, while a confident invention is one they will not notice.
@@ -0,0 +1,81 @@
1
+ You are reading one repository to turn an operator's stated release *intent* into
2
+ that repository's own machinery. You have been given reading tools only: there is no shell,
3
+ no editor and no verb here, so reading and answering is the whole of what you can
4
+ do.
5
+
6
+ ## The one thing you must not do
7
+
8
+ **You are not deciding the release policy.** The operator has already decided it,
9
+ below. Your job is to find how this repository actually ships and express their
10
+ intent in its terms. Do not widen the boundary, do not add a step they did not
11
+ ask for, and do not write the procedure from the intent alone without reading the
12
+ repository — an invented procedure reads exactly like a real one and fails the
13
+ first time it is followed.
14
+
15
+ ## Stated intent — given, not yours to revise
16
+
17
+ - **Where the orchestrator's leg ends:** {{BOUNDARY}}
18
+ - **What may be released, and from which branch:** {{WHAT}}
19
+ - **When — batched how, after which named checks:** {{WHEN}}
20
+ - **Proof that must be held first:** {{PROOF}}
21
+ - **What must still be asked, every time:** {{ASK}}
22
+ - **Permanently forbidden:** {{FORBIDDEN}}
23
+ - **A release worth cutting:** {{WORTH_CUTTING}}
24
+ - **Rollback owner:** {{ROLLBACK_OWNER}}
25
+
26
+ ## Where you are, and what to read
27
+
28
+ Your working directory holds **one directory per routing repo**, each a shallow
29
+ clone. Release machinery does not always live in the repo you would expect, so look
30
+ across all of them before writing: the repo that ships may not be the first one.
31
+
32
+ Each routing key and the directory it was cloned into:
33
+
34
+ {{REPOS}}
35
+
36
+ **Name repos by their routing key, never by the directory.** The directory is
37
+ scratch and will not exist when anyone reads your answer; the key is what an issue
38
+ carries and what an orchestrator routes on.
39
+
40
+ In each, read the release workflows (`.github/workflows/*release*`, `*publish*`,
41
+ `*tag*`), the package manifest's version and publish configuration, any
42
+ `RELEASING.md` / `CONTRIBUTING.md` release section, and how a version is bumped.
43
+
44
+ For every workflow that publishes anything — a release, a tag, an image, a package,
45
+ a deployment — **the trigger is the fact that matters**:
46
+
47
+ - `workflow_dispatch` → the release is *dispatched*. That workflow is the authority,
48
+ and the instruction is "dispatch it with the planned version", never "do what it
49
+ does".
50
+ - `on: push: tags:` → a pushed tag is the trigger, so **tagging is releasing**.
51
+ - `on: release: published` → the GitHub Release is the trigger.
52
+
53
+ Also record **what the workflow enforces** — many reject a tag unless several
54
+ version files agree — because that is what turns a release attempt into a failure
55
+ an operator has to unpick.
56
+
57
+ Name the repo each step belongs to. A procedure that does not say where it runs is
58
+ one an orchestrator applies in the wrong checkout.
59
+
60
+ ## What to write
61
+
62
+ - **The named authority, and how it is invoked.** If shipping is a protected or
63
+ dispatchable workflow, the instruction is to *dispatch it and verify the run* —
64
+ never to reproduce what it does by hand, even when every step is visible. A
65
+ hand-rolled release skips the checks the workflow exists to enforce.
66
+ - **The steps on the agent's side, each with the check that proves it.** A step
67
+ with no verifiable outcome is a step that silently did not happen.
68
+ - **The forbidden list, with a file citation** — cite the file that says so
69
+ (`AGENTS.md`, a runbook) so the rule survives a future session that thinks it has
70
+ found a shortcut. Force-push, secrets and production data are forbidden
71
+ everywhere, always, whether or not this repository restates them.
72
+ - **Where the leg ends**, restated as a concrete artefact or commit, matching the
73
+ boundary above.
74
+
75
+ If the repository has no release machinery at all, say that in one line rather
76
+ than inventing a plausible one. That is a finding the operator needs.
77
+
78
+ ## Answer
79
+
80
+ One fenced markdown block containing the procedure and nothing else. No preamble,
81
+ no commentary after it.