gm-orchestrate
gm-orchestrate
Pool and publish rules. Shared rules (autonomy, git identity, CI read, collisions, exit): gm. Recovery: docs/recovery.md. Incidents: docs/incidents.md.
ceiling = the harness's live concurrent-subagent limit, read from its refusal message (You can run N subagents at once) or from the harness, never written into this skill. It is the only bound on concurrency: free = ceiling - live. live = ListAgents count. floor = min(2, ceiling). shortfall = live < floor with independent work open.
Standing pair (every run)
Every /gm run executes the drain procedure below in its first turn, before any other fan-out, through gm verbs and the harness's own parallel workers (subagents or background tasks). No workflow file or harness-specific runner is needed. Where the harness has no parallel workers, the groups run in sequence through the same loop.
- Plan once. List pending rows in pages of at most 50:
prd-list {"status":"pending","limit":50,"offset":N}for N = 0, 50, 100, ... until a page returns fewer than 50 rows. Never request the whole list in one call: a full pending list exceeds the tool-result cap and the drain never starts. Group rows by the[repo:] [group:]prefix of their description; a row without a prefix forms its own group. Record the plan (units, row ids) with one append line per unit to.gm/pool/plan-<run>.txt. Units are split as the Launch loop states. - Drain, in parallel. Each unit works its rows in order. Launch at most
freeunits in one block (Launch loop, rules 2 and 3). Queue the rest and launch each queued unit in the same turn a slot frees. A refusal ("Concurrent subagent limit reached") means wait for a slot: re-launch that item when a completion frees one, never retry in a loop, never drop it. Agents may edit the same file in parallel: each re-reads the file immediately before its edit and applies its change to the current state, never to a remembered copy. A dirty or diverged checkout is consolidated by the lane that owns it before the row's commit, never worked around. A bundle owns the rows it is given: ownership is never a blocker. Each row runs the gm-prd stages (orient through publish, thenprd-resolvewith a live witness). A row attempted in a run is not retried in that run. There is no blocked state: a row whose attempt ends without a witness keeps its work open, and the next launch does the missing step (edit, build, push, CI, or a live witness from another session). A row whose premise a live read refutes (the named symbol, file, job or sha is absent or already fixed) closes withprd-resolve {"id":..., "resolution":"stale"}. Its witness must come from a session other than the resolver's: file the refuting dispatch ids withprd_witness_request, then a verifier session runsgm-prdwithmode=witnessand resolves. A self-witness is refused (prd-resolve-self-witness): witness dispatches use a SESSION_ID distinct from the resolve call's (resolverdrain-<bundle>, witnessverify-<row>), and the witness dispatch id must appear in.gm/exec-spool/.dispatch-ledger.jsonbeforeprd-resolveis called. A row is never parked: every round re-lists the open rows and every open row is attempted. A row whose fix lives in a submodule first moves that submodule to its remotemaintip; a dirty or diverged submodule blocks the row with that fact named. Call shapes:prd-blocktakesnote,prd-resolvetakesresolution(nonote); one row is read in full withprd-list {"id":"<row id>","full":true}. - Validate per batch. When a group's commits land, read
ci-status {sha}for each pushed sha; a group closes its rows only after those reads. Do not wait for the whole drain. A red job goes back to the row that owns the failing file (prd-addfix row, taken by that row's lane). Validation never runs on uncommitted work. - Close.
prd-resolvewith the commit sha as witness. Then remove.gm/prd/<id>.ymland.gm/receipts/<id>/if they remain. The commit body carriesRow: <id>on its own line, so the git log records each finished row. A commit stages only its own explicit paths and refuses when other paths are already staged, so it never sweeps in another lane's work. A commit that needs amending is amended once; if the amend does not return, re-read the commit (git_show) and never retry it in a loop. - Re-plan. After each round, repeat from step 1 with a fresh paged listing. Stop when a round closes no row, or when the pending backlog is empty.
- Rollout. Traversal (gm-hop over
skills/dream-rsi/gm-graph.json) and new-row finding run in free slots only while fewer than 20 rows are open. At 20 or more open rows they wait, and the drain has the slots.