orchestrate-batch-interactive
Skill1 starsChanged 7 days agoMITView on GitHub
Drive a multi-task batch through the engine scheduler on the interactive×Codex lane. Thin supervisor — the DAG/retry/cascade/capacity logic is all in the `orchestrator` engine; this skill only sequences the fan-out.
In this repository17 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- batch-planSkill
- brainstormSkill
- new-projectSkill
- orchestrate-batch-headlessSkill
- orchestrate-task-interactiveSkill
- spec-intakeSkill
- triage-followupsSkill
- batch-planSkill
- brainstormSkill
- new-projectSkill
- orchestrate-batch-headlessSkill
- orchestrate-batch-interactiveSkill
- orchestrate-task-interactiveSkill
- spec-intakeSkill
- triage-followupsSkill
The file
We split this skill into the rules it gives an agent
5 rules. About 0 are common, 2 are distinctive, and 3 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 16
Per-task dispatch, not per-round barrier (#97): Do NOT fan a whole round out as one Workflow batch and wait for the slowest member — that …
- Distinctive: line 52
every: follow-on dispatch (not once per round): a task returning frees one slot, and the concurrency cap has to bind across all …
- Very specific: line 56
If dispatchable is empty but tasks remain non-terminal and in_flight_count == 0, you're capacity-stalled (limit == 0) — wait for the usage …
- Very specific: line 78
If it returns null, check status first: run_state=parked means stop and surface supervisor_parked.reason plus resume_command, not "task …
- Very specific: line 110
All state is persisted. If the session dies mid-batch, just start this skill again on the same ROOT/RUN: dispatchable re-derives what's …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Batch supervisor — interactive×Codex lane
You are the batch supervisor. The scheduler logic (which tasks are ready, the
capacity-derived dispatch limit, retry-with-learnings, transitive cascade-blocking,
run finalization) lives in the orchestrator engine. Your job is the loop:
ask which tasks are dispatchable → launch ONE Workflow invocation PER task
(in the background) → record each result the instant its invocation returns →
immediately dispatch that task's next stage until the run is terminal. You never
call a model directly and never run Codex -p.
Per-task dispatch, not per-round barrier (#97). Do NOT fan a whole round out as
one Workflow batch and wait for the slowest member — that idles every fast task until
the round's slowest stage finishes (the slowest-member tax). Instead run one Workflow
invocation per task with run_in_background, and advance each task independently the
moment its own invocation returns. A fast task's next stage dispatches while a slow
sibling is still mid-stage.
Constants
ROOT= the shared runs-root (the top-levelruns/dir). The engine auto-nests each run's store underruns/<run-id>/so runs never comingle their files flat.RUN= run id.PROJECT=<your-project-adapter>(e.g.adapters.project.selfhost).- Engine call shape:
uv run orchestrator --root "$ROOT" --shared-root --run "$RUN" --project "$PROJECT" <cmd> ...- Always pass
--shared-rootwhenROOTis the top-levelruns/dir (#102): it forces the per-run nest even on a freshruns/the auto-detect heuristic can't yet recognize (no KB / sibling stores exist on day one). It's a no-op once nesting is established, so it's safe to pass on every call. Omit it only if you pointROOTdirectly at a pre-existing per-run dir (runs/<run-id>).
- Always pass
One-time setup
uv run orchestrator --root "$ROOT" --shared-root --run "$RUN" --project "$PROJECT" init-run --lane full.… --shared-root … add-task --task "#NNN"for each task in the batch (the task source supplies each task'sdepends_on; the engine builds the DAG).
Capacity: bind across concurrent invocations
dispatchable reports the DAG-ready set AND the in-flight lease count, so you can size
remaining headroom yourself:
D=$(uv run orchestrator --root "$ROOT" --shared-root --run "$RUN" --project "$PROJECT" dispatchable --util auto --max-concurrent 3)D.dispatchable— DAG-ready, unleased tasks (EXCLUDES anything already in flight).D.limit— the engine's capacity-derived dispatch cap (binding — never exceed it).D.in_flight/D.in_flight_count— tasks with a live dispatch lease right now (one background Workflow invocation out per task).- Remaining headroom =
limit - in_flight_count. Launch at most that many NEW invocations. Because there is no per-round barrier, you MUST re-check this before every follow-on dispatch (not once per round): a task returning frees one slot, and the concurrency cap has to bind across all concurrently-live invocations. This is also correct after a resume — a crashed invocation leaves its lease held, soin_flightre-counts it and you don't over-dispatch. - If
dispatchableis empty but tasks remain non-terminal andin_flight_count == 0, you're capacity-stalled (limit == 0) — wait for the usage window, then retry.
The loop (repeat until status.run_state is terminal)
Maintain a set of in-flight background dispatches (task id → background invocation +
its timeout_s + start time). Each pass:
Require the Codex status-line sensor throughout the loop: configure
orchestrator statusline as statusLine and verify orchestrator supervisor-context
returns a fresh snapshot. Every next below uses the engine guard, which evaluates the
exact rendered prompt before returning it or taking a lease. If guarded next returns
drain_required, stop launching new work, reap and record every existing background
dispatch, then retry guarded next; only the lease-free retry may emit
supervisor_parked. Never mark a run parked while a sibling invocation is live.
- Fill headroom. Compute
slots = limit - in_flight_countfrom a freshdispatchable. For up toslotstasks fromD.dispatchable:WORK=$(… --shared-root … next --task "$T" --guard-supervisor-context --supervisor-resume-command "start a fresh Codex session and invoke /orchestrate-batch-interactive for $RUN")→ one WorkItem (the engine drains any leading deterministic stage in-process and returns the first model WorkItem;nullmeans that task is done — skip it). If it returnsnull, check status first:run_state=parkedmeans stop and surfacesupervisor_parked.reasonplusresume_command, not "task done". A fresh session runs… resume-supervisoronce before restarting this loop.- Launch ONE Workflow invocation for that task with
run_in_background: invokerun_targets/workflow_shim.jswith{ workItems: [WORK], dispatchLimit: <engine limit>, now: <ISO>, schemas: {...} }. PassWORKthrough VERBATIM (#311): copy the whole JSON objectnextprinted — never retype or abbreviate a field.content_hashis a 64-char digest whose only job is tying the returned result back to this dispatch; with several tasks in flight, a truncated log preview or a hash copied from a sibling item is exactly the livebatch-next5bfailure.recordrefuses such a result, and the shim aborts before spending anything when the shape is wrong. The shim runs the stage in-session and returns its StageResult (it cannot persist). RecordT, the background handle,WORK.timeout_s, and the start time.
- Reap returns. As each background invocation returns, immediately:
- record its StageResult: write to a temp file →
… --shared-root … record --result <file>. The engine advances that task, retries a failed stage with learnings, and cascade-blocks dependents of any task that fails — you don't manage that. A non-zero exit with{"ok": false, "recorded": false, …}means the result did not answer that task's outstanding dispatch (also logged asresult_rejected). Do NOT patch the result'scontent_hashto make it pass — re-dispatch that stage with… next --resumeand record what actually comes back. - re-check
dispatchableand, if that task is now dispatchable and there's headroom, immediately launch its next stage (step 1). Do not wait for siblings.
- record its StageResult: write to a temp file →
- Own per-item timeouts individually. The shim CANNOT enforce
timeout_s(no clock in the Workflow sandbox). Track each in-flight dispatch's own deadline: if one visibly exceeds ITStimeout_s, stop waiting on that one only, hand-craft itsStageResultwithstatus: "timeout"and a one-lineerror, and record it. Never leave a hung dispatch un-recorded, and never let one slow task block reaping others. - Loop. Stop when
… --shared-root … statusshowsrun_state=completedorfailed.
Resumability
All state is persisted. If the session dies mid-batch, just start this skill again on
the same ROOT/RUN: dispatchable re-derives what's left, in_flight re-counts any
still-leased tasks, and the engine re-emits any un-recorded stage (a crash-marked
RUNNING stage re-dispatches at the same attempt — no double-execution). Resume
granularity is per task, not per round — only the individual in-flight task's stage
is re-run, never a whole round. Resume only on a genuine crash — always capture next
into WORK in the single call above, never next then next --resume for the same
live stage. A resume that supersedes a still-held lease is self-describing in the
timeline (#142): the re-dispatch's stage_dispatched carries resume: true /
supersedes: <old work_item_id> and the retired lease gets a lease_superseded event,
so a consumer counting stage_dispatched can discount the superseded one.
Audit (every gate)
… --shared-root … status → lane_audit.clean == true: every recorded call
interactive:Codex, zero unattributed. The durable timeline is events.jsonl;
per-stage records are under stages/<task>/NN-<stage>.json.
Post-run follow-up triage (opt-in: --triage-followups)
A completed run's evidence-out seam files the review stages' non_blocking findings and
improvement ideas as GitHub issues automatically, with no human gate (the run must
never block on a human). That grows the backlog with issues the human never chose to track
and often can't parse. If the invocation args include --triage-followups (or the
human asks to triage the run's filed issues), then after the run reaches a terminal
run_state and the audit gate above is clean, invoke the triage-followups skill on
this RUN:
- It enumerates only the issues THIS run filed (matched by each issue's
Filed automatically from the <task_id> reviewprovenance footer, open issues only) and walks them one at a time, explaining each from its source review finding (stages/<task>/NN-review.json) and the code it points at, then takes the human's keep / close / promote / edit decision per issue. - It is a pure human-judgment gate — read-only on the run, acting only on GitHub. It is
re-runnable (open-only enumeration), so the human can also defer triage and run
triage-followupson this run later instead of inline. Without the flag, behavior is exactly as before: the run finalizes and its auto-filed issues stay untriaged.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

