Dispatch tasks to codex agents running under herdr
The raw request is the text passed to this skill — its arguments, or, when it was invoked with none, the task text in the user's own message.
You are an orchestrator. You do not implement the tasks yourself. You split the request into
lanes, give each lane its own herdr workspace and its own codex agent, and then keep those agents
alive and moving until every lane genuinely finishes. You do the planning; codex does the
pursuing: each lane gets a plan and acceptance criteria you author and the user confirms (§3),
and runs as a codex goal (/goal, §5c) — a thread-scoped objective codex auto-continues
toward across turns until it is met. A lane is not finished when its agent stops — it is finished
when its work is verified, its branch is pushed, and its pull request is open (§6f).
How to read this skill
The procedure is split across four files, and the section numbers (§0–§8) are continuous across all of them, so a cross-reference means the same thing wherever you are:
| Sections | File | Read it |
|---|---|---|
| §0 invariants, §1 gate and parse | this file | always, and §0 again at the start of every sweep |
| §2–§4, §5b | references/plan.md |
on a fresh dispatch, before creating anything |
| §5a, §5c, §6a, §6c, §6d, §6g, §6h | references/driver.md |
everything codex-specific: launch, probe, classify, steer |
| §6b, §6e, §6f, §6i, §6j, §7, §8 | references/supervise.md |
before the first supervision sweep |
references/plan.md and references/supervise.md are symlinks into the plugin's skills/_shared/:
the shared halves stay single-sourced while still resolving when this skill's directory is copied on
its own, which is how the skills.sh installer places it. Both are read by path,
not invoked.
§0 Invariants — reread every sweep, never work from memory
- The state file is the only truth.
~/.claude/dispatch-codex/<run-id>/state.json. Begin every sweep by reading it; your conversation memory may have been compacted away. Rewrite it atomically (write.tmp, thenmv) at the end of every sweep. - Judge a lane from disk, not from the screen. Codex writes a rollout JSONL holding exact token usage, turn boundaries and compaction records. Terminal output is the fallback, never the primary signal.
agent_statusalone never means "finished", and it can lie outright. A background lane reportsdone(notidle) when unseen work ends — but it reads the same when the prompt was swallowed, when codex froze, and when herdr misclassified a modal. Always corroborate (§6). The same goes for a lane's notify-back or help ring (§5b): it is a doorbell that starts a sweep sooner, never evidence that skips §6e. The gap between anactivegoal's auto-continued turns also readsdone(§6c) — one more reasondonealone proves nothing.- Never touch what you did not create. Act only on ids recorded in the state file. Never
herdr server stop. Neverherdr agent focus/workspace focus— it steals the human's UI focus and silently flipsdonetoidle, destroying your own signal. - Never destroy work; publish only what you verified. Finishing a lane means pushing its own
branch and opening a PR for it (§6f) — both additive and reversible, and both yours to do, never
the lane's. Everything else stays forbidden: never force-push (
--force,--force-with-lease), never push the base branch or any branch absent from the state file, never merge, neverworktree remove. Print those commands and let the user run them:worktree removekills the running codex process and deletes uncommitted changes even without--force. - Rollout files reach 100+ MB. Never parse one whole — read only the tail.
§1 Gate and parse
Run test "${HERDR_ENV:-}" = 1, test -n "${HERDR_PANE_ID:-}" and herdr agent list. If
HERDR_ENV or HERDR_PANE_ID is unset or the CLI cannot
reach the socket, stop and tell the user in Chinese that this session is not inside a herdr pane, so
there is nothing to dispatch into — an exported HERDR_ENV alone can pass in a non-pane shell,
and a run recorded without its pane id has no working notify-back. Do not install or launch herdr,
and do not run codex yourself.
Parse flags from the raw request; everything else is task text.
| Flag | Meaning | Default |
|---|---|---|
--lanes N |
cap on concurrent lanes, 1–16 | 16 |
--base <ref> |
base ref for lane branches | origin/<current> if it exists, else current branch |
--no-yolo |
launch codex under the user's own approval config instead of bypassing it | off — yolo is the default |
--yolo |
accepted and explicit, but redundant: this is already the default | on |
--draft |
open pull requests as drafts instead of ready for review | off — ready for review is the default |
--no-pr |
push each verified lane but stop there; print the gh pr create command instead |
off |
--resume |
skip §2–§5 (this gate and parse still run); run ONE supervision sweep over the existing state file | off |
--no-loop |
do not arm the recurring supervision loop after dispatch | off |
Every lane gets its own git worktree. This is not a flag and there is no opt-out. With approvals
and the sandbox bypassed by default (§5c), the worktree boundary is the only thing left keeping one
lane's mistakes out of the other lanes and out of the user's own checkout. If the request contains
--no-worktree, stop before creating anything: say in Chinese that this skill always isolates
lanes in worktrees and that the flag no longer exists, and ask the user to re-run without it. Do not
silently proceed — a user who asked for a shared checkout should find out now, not after N lanes have
been dispatched under an isolation model they did not expect.
With --resume, first locate the run — conversation memory may be gone (§0.1): scan
~/.claude/dispatch-codex/*/state.json for runs whose repo matches the cwd and that still hold
non-terminal lanes; one match sweeps it, several means ask the user which, none means say so and
stop. Then read references/driver.md and references/supervise.md and go to §6. With no task text
and no --resume, ask the user in Chinese what to dispatch, and stop.
Otherwise — a fresh dispatch — read references/plan.md now and continue at §2.