Skill Herdr: relatório para aprovação

Síntese do swarm de revisão da skill operacional, auditada contra Herdr 0.7.5.

1. Resumo executivo

O swarm reuniu 6 Sols em effort-low — comunidade de skills, players/harness builders, minimalismo pi, Matt Pocock, revisão adversarial e enforcement > convenção — mais 1 revisão final em effort-medium; os Sols tiveram pesquisa web via --search.

A skill final caiu de 268 linhas no arquivo atual e 257 no .proposed para 148 linhas, com modelo mental, seis invariantes e procedimentos orientados às falhas reais.

Quatro wrappers novos transformam os caminhos mais frágeis em fail-fast: start, dispatch, verify e compatibilidade.

A validação real cobriu Herdr 0.7.5, ambos os exits do verify, o padrão de dispatch usado nos 7 Sols, bash -n e Bash 3.2 do macOS.

Todas as 11 findings da revisão final foram tratadas; rejeições foram conscientes e estão registradas abaixo.

Nada foi aplicado nem commitado. O único gate agora é Fernando aprovar o diff completo.

2. O que precisa ser feito

  1. Fernando aprova o diff. Responsável: Fernando Gate único
    Nenhum arquivo da skill instalada foi alterado e nenhum commit foi criado.
  2. Aplicar a skill e os wrappers. Executor: Fable Gate: aprovação
    Copiar proposal/SKILL.md e proposal/scripts/ para ~/agents-config/shared/skills/herdr/ e remover SKILL.md.proposed.
  3. Commitar no repositório agents-config. Responsável: Fernando/Fable Gate: aplicação revisada
    Já existia uma modificação não commitada de +14 linhas no SKILL.md anterior à tarefa; decidir explicitamente se o commit engloba essa substituição inteira.
  4. Propagar para Claude. Responsável: Fernando/Fable Gate: commit definido
    ~/.claude/skills/herdr/ hoje é uma cópia, não um symlink. Decidir se passa a apontar para a fonte canônica para eliminar drift entre cópias.
  5. Fechar os 7 panes dos Sols. Responsável: Fable Gate: autorização
    Os panes permanecem na tab do orquestrador e só devem ser fechados após autorização explícita.
  6. Decidir os pedidos upstream ao Herdr. Responsável: Fernando Gate: decisão de produto
    Converter ou não em issues: (1) dispatch atômico de agente; (2) frontier transacional com preflight e barreiras; (3) ownership/proveniência e close protegido; (4) pane run --wait --exit-code; (5) policy allowlist para rejeitar mutações inseguras.
  7. Manutenção futura. Responsável: mantenedor da skill Gate: próxima iteração/release
    Criar evals comportamentais e rodar check-compat.sh a cada release do Herdr; o segundo passo agora é barato e determinístico.

3. Como o swarm chegou nisso

Comunidade de skills

  • Priorizou check de compatibilidade read-only e protocolo de monitor em wrapper.
  • Defendeu progressive disclosure e evals de trigger/comportamento; a matriz congelada foi removida, e os evals ficaram como futuro.

Players / harness builders

  • Exigiu contratos sem sobreposição, critérios de aceite e revisão do diff antes do merge.
  • Introduziu verificação por exit status, invariantes fail-fast e limite de concorrência por capacidade real.

Minimalismo pi

  • Mandou remover inventário 0.7.5 copiado e descobrir sintaxe no runtime.
  • Comprimiu repetição de topologia/frontier e deslocou implementação frágil para wrappers; o alvo rígido de 120 linhas foi rejeitado em favor de 148.

Matt Pocock / ensino e DX

  • Colocou modelo mental e tabela de estados antes dos procedimentos.
  • Adicionou anti-exemplos de erros prováveis, contrato de saída scoreável e headings orientados ao job.

Revisão adversarial

  • Expôs corrida do working, monitor/PID compartilhado e ausência de loop não bloqueante.
  • Forçou nomes únicos, gate de startup e tratamento explícito de ambiguidade sem re-prompt automático.

Enforcement > convenção

  • Classificou 57 regras: 4 ENFORCED, 1 FAIL-FAST e 52 DISCIPLINE (91%).
  • Direcionou wrappers para start, dispatch e verify, além de cinco primitives upstream que eliminariam disciplina residual.

Revisão final

  • Corrigiu fail-open de schema, falhas parciais, resolução de paths, monitor órfão e isolamento do verify.
  • Exigiu manifest, capacity gate, remoção do fallback manual e check-compat.sh.

4. Decisões de síntese

Em relação ao SKILL.md.proposed, a síntese remove a matriz estática de comandos, encurta a implementação shell inline, antecipa o modelo mental, torna as seis invariantes visíveis e substitui sequências críticas por wrappers. Em relação ao SKILL.md atual, corrige drift de 0.7.5 (herdr wait e agent send), exige pane explícito, impede espera foreground no orquestrador, padroniza frontier com capacity gate e troca “texto parece sucesso” por exit code verificável.

Os wrappers validam antes de mutar sempre que possível: start-executor.sh é fail-closed para colisão/schema, preserva e revela pane em falha parcial e tenta novamente uma vez após agent_pane_busy; dispatch.sh arma o monitor antes do prompt e mata órfão se o prompt falhar, sem fingir eliminar a corrida; verify.sh usa Bash filho, manifesta o pane e o preserva em falha; check-compat.sh bloqueia versão/flags incompatíveis sem mutação.

Rejeição conscienteRacional
Matriz CLI em references/Congela, apodrece e duplica a autoridade; discovery em runtime substitui.
Política local em arquivo separadoO modelo de sincronização do agents-config é single-file por skill.
Harness de evals comportamentais agoraCusto de manutenção desproporcional nesta rodada; registrado como trabalho futuro.
Meta rígida de 120 linhas148 linhas preservam gates e recuperação necessários sem voltar ao volume anterior.
Upstream asks dentro da skillPedidos ao produto não ajudam o runtime da skill; ficam no plano de ação.

5. Tabela de disposição

Reprodução atualizada do Finding 10 da revisão final. “Incorporado” indica correção na rodada final; limitações deliberadas permanecem explícitas.

ReviewTop-5 itemDisposição final atualizada
adversarial 1Fast working raceParcial e consciente: wrapper arma antes, mas 0.7.5 não oferece handshake atômico; ambiguidade e pedido upstream documentados.
adversarial 2Distinct monitor files/PIDsIncorporado: arquivo novo obrigatório e PID retornado por dispatch.
adversarial 3Nonblocking collection loopIncorporado: polling limitado com kill -0.
adversarial 4Unique executor namesIncorporado e corrigido: collision check agora falha fechado em erro/schema.
adversarial 5Start failure/unknown gateIncorporado: valida antes, trap revela pane_id em falha parcial e preserva recurso.
community 3Read-only compatibility scriptIncorporado: check-compat.sh.
community 7Script monitor protocolIncorporado e corrigido: arquivo síncrono, monitor pré-prompt e cleanup se prompt falhar.
community 1Move CLI matrix to versioned referenceRejeitado conscientemente: matriz deletada; discovery em runtime evita snapshot apodrecido.
community 5Separate portable/local policyRejeitado conscientemente: skill é sincronizada como single-file.
community 9Behavior and trigger evalsAdiado conscientemente para trabalho futuro.
enforcement 1Require monitored-dispatch wrapperIncorporado.
enforcement 2Upstream atomic dispatchNão pertence à skill; incluído no plano de ação upstream.
enforcement 3Manifest-driven frontier wrapperParcial: manifest exigido e verify registra pane; batch transacional permanece pedido upstream.
enforcement 4Exit-bearing run; sentinel fallbackFallback incorporado e corrigido com Bash filho; primitive nativa permanece upstream.
enforcement 5Ownership metadata/guarded closeParcial: manifest e regra de close; enforcement nativo permanece upstream.
pi 1Delete frozen inventory/use discoveryIncorporado.
pi 10Approximately 120 linesParcial por decisão: 148 linhas finais.
pi 4One nonblocking orchestration contractIncorporado via dispatch.sh.
pi 7Collapse topology/frontier repetitionIncorporado por condensação; política local permanece no hot path por decisão de sync.
pi 2Remove copied command signaturesMajoritariamente incorporado: discovery runtime; assinaturas mínimas permanecem como contratos de wrapper.
players 2Non-overlapping contractsIncorporado, incluindo files, ports, databases e caches.
players 3Exit-status verificationIncorporado e corrigido: sentinela não pode ser suprimida pelo comando filho.
players 4Diff review before mergeIncorporado.
players 1Capacity gateIncorporado: wave limitada por panes, CPU, memória, serviços e review.
players 10Fail-fast invariantsIncorporado em seis invariantes.
pocock 1Ownership/state mental modelIncorporado no início, com tabela de ação por status.
pocock 2Early runnable self-verifying exampleParcial por decisão: contratos de wrappers são curtos e verificáveis, mas usam placeholders explícitos.
pocock 3Foreground-freeze anti-exampleIncorporado.
pocock 4Scoreable prompt contractIncorporado na política de frontier.
pocock 5Five-failure preflight checklistIncorporado entre seis invariantes e o gate executável de compatibilidade.

6. Artefatos

Diff completo — proposal/SKILL.md.diff

--- /Users/fernandodudata/agents-config/shared/skills/herdr/SKILL.md	2026-07-21 11:42:25
+++ /Users/fernandodudata/Documents/Codex/2026-07-21/herdr-skill-swarm/proposal/SKILL.md	2026-07-21 19:02:57
@@ -1,268 +1,148 @@
 ---
 name: herdr
-description: "Control Herdr, a terminal multiplexer for coding agents. Use only when the user explicitly mentions Herdr or asks to use Herdr to inspect or control panes, tabs, workspaces, terminals, commands, or communication with another agent. Do not use merely because a task could benefit from a background terminal, delegation, or parallel work. Requires HERDR_ENV=1."
+description: "Control Herdr, a terminal multiplexer for coding agents. Use when the user explicitly mentions Herdr or asks to start an agent in Herdr, inspect or prompt a Herdr pane, dispatch parallel executors through Herdr, or run commands in Herdr panes. Do not use merely because a task could benefit from a background terminal, delegation, or parallel work. Requires HERDR_ENV=1."
+metadata:
+  herdr-cli-version: "0.7.5"
 ---
 
 # Herdr
 
-Herdr is a terminal multiplexer and runtime for coding agents. It organizes terminals into workspaces, tabs, and panes, detects agent identity and status, and exposes the running session through the `herdr` CLI.
+Herdr is a terminal multiplexer and runtime for coding agents. A workspace contains tabs; a tab contains panes; a pane owns one terminal process and its working directory. Herdr detects the agent running in a pane and exposes the running session through the `herdr` CLI.
 
-Before issuing any control command, check that this agent is running inside a Herdr-managed pane:
+Resolve the absolute directory containing this loaded `SKILL.md` as `<herdr-skill-dir>`; wrapper paths below are relative to that directory, never to the project cwd. Never `cd` into the skill directory — pass the executor or verification cwd as the wrapper argument. If a required wrapper is missing or non-executable, stop before any mutation and report a broken skill installation; do not reconstruct split/start/dispatch/verify sequences from prose.
 
-```bash
-test "${HERDR_ENV:-}" = 1
-```
+## Mental model
 
-If the check fails, say that you are not running inside Herdr and stop. Do not inspect or control the focused Herdr session from outside Herdr.
+- `pane` commands create, place, read, and control terminal processes. Target panes by ID.
+- `agent` commands address a supported agent already running in a pane: start, prompt, inspect, wait. Target agents by unique name (preferred) or by the hosting pane ID.
+- Minimal lifecycle: create a pane → start an agent in it → wait `idle` → arm a monitor → prompt without blocking → observe `working` → accept `idle`, `done`, or `blocked` → verify the work yourself.
 
-When the check passes, the `herdr` binary in `PATH` talks to the running session. Use it to inspect neighboring work, create isolated terminal contexts, start agents and commands, read their output, and wait for state changes.
+| Status | Meaning | Your action |
+| --- | --- | --- |
+| `unknown` | No supported agent detected yet | Read the pane, investigate startup; do not prompt |
+| `working` | Processing | Keep orchestrating; monitor in background |
+| `blocked` | Needs input or approval | Read the transcript, arm a fresh monitor, answer it |
+| `idle` | Ready, or finished with result seen | Before first prompt: ready. After observed `working`: complete |
+| `done` | Finished, result unseen | Complete; read the result |
 
-## Learn the current CLI
+Completion monitors must accept both `idle` and `done`: which one appears depends only on whether the human has seen the result.
 
-The installed binary is the authority for command syntax. Begin with:
+## Environment gate
 
-```bash
-herdr --help
-```
+Run before any control command; if either fails, stop and report instead of adapting ad hoc:
 
-Then print the relevant command group by running it without a subcommand:
-
-```bash
-herdr pane
-herdr workspace
-herdr worktree
-herdr tab
-herdr wait
-herdr terminal
-herdr notification
-herdr integration
-herdr session
+```text
+test "${HERDR_ENV:-}" = 1
+<herdr-skill-dir>/scripts/check-compat.sh
 ```
 
-Do not run bare `herdr` for discovery; it launches or attaches the TUI. Do not probe a mutating nested command by omitting arguments; some commands, including `herdr workspace create`, are valid with defaults and will execute. Use the command-group output above instead.
+`check-compat.sh` is read-only: it requires the audited herdr version and verifies that the `pane` and `agent` groups still advertise every command and flag the wrappers rely on.
 
-Most control commands print JSON. Read identifiers and state from those responses instead of predicting either one.
+## Non-negotiable invariants
 
-## IDs and current context
+1. The installed binary is the authority. Before first use of a command group in a session, run the bare group (`herdr agent`, `herdr pane`, …) and follow its current usage. Never infer a flag — including `--json` — from another command or from this skill.
+2. Target the caller with `--current` or an explicit ID parsed from a JSON response. Never rely on any client's focus; never construct an ID.
+3. Never block the orchestrator foreground on an executor: no `agent prompt --wait` for dispatch — use `scripts/dispatch.sh`.
+4. Give each parallel code-writing executor its own worktree, unique branch, and unique agent name.
+5. `idle`/`done` is not "shippable". Verify with `scripts/verify.sh` (exit-code gated) and review the diff before merging.
+6. Do not close resources you did not create in this run. Never run `herdr server stop` from an active session.
 
-Public IDs are short stable handles:
+If an invariant cannot be satisfied, stop that operation and report the blocker instead of improvising around it.
 
-- workspace: `w1`
-- tab: `w1:t1`
-- pane: `w1:p1`
-- terminal: `term_...`
+## Discover syntax at runtime
 
-The encoded suffix can contain letters and can grow beyond one character. Treat every ID as an opaque string.
+Run `herdr --version` once per session. This skill was audited against 0.7.5; when the binary and this skill disagree, follow the binary and report the mismatch. Print only the groups you will actually use:
 
-Closed tab and pane IDs are not reused and do not retarget later resources. A pane moved into another workspace receives a new public pane ID. Re-read create, split, move, list, or get responses after mutations; never construct an ID from a workspace or display number.
-
-Herdr injects the caller's stable context into every managed pane:
-
 ```bash
-printf '%s\n' "$HERDR_WORKSPACE_ID" "$HERDR_TAB_ID" "$HERDR_PANE_ID"
+herdr pane
+herdr agent
 ```
 
-Prefer `--current` when a pane command should target the calling pane. Omitting a target can use the UI-focused pane, which may belong to the user or another client.
+Add `herdr worktree`, `herdr tab`, etc. only when the task needs them. Do not run bare `herdr` — it launches or attaches the TUI. Do not probe a mutating nested command by omitting arguments; some (e.g. `herdr workspace create`) are valid with defaults and will execute. In 0.7.5 there is no top-level `herdr wait` (use `herdr agent wait` and `herdr pane wait-output`) and `agent send` is gone (submit task text atomically with `herdr agent prompt`; reserve `send-keys` for raw key events).
 
-Discover live state with:
+Group help proves syntax only — not semantics, output schemas, or exit codes. Most control commands print JSON by default: parse IDs and state from those responses, and pass `--json` only where the group inventory advertises it. The wrappers validate the response shapes they depend on and fail closed on schema drift.
 
-```bash
-herdr workspace list
-herdr tab list --workspace "$HERDR_WORKSPACE_ID"
-herdr pane current --current
-herdr pane list --workspace "$HERDR_WORKSPACE_ID"
-```
+## Caller context
 
-## Control agents through panes
+Herdr injects the caller's identity into every managed pane:
 
-An agent runs inside a pane. Use the pane ID as the control target for agents, shells, servers, tests, and logs. This keeps spawning, input, reads, waits, and cleanup on one stable control surface.
-
-Use workspace and tab commands for organization. Use worktree commands only when you intentionally want Herdr to create, open, or remove a Git checkout.
-
-Pane records expose `agent`, `agent_status`, and native session metadata when available. Agent status is `idle`, `working`, `blocked`, `done`, or `unknown`.
-
-`idle` and `done` are the same underlying semantic state with different attention state:
-
-- `idle`: the agent is waiting and its result is considered seen.
-- `done`: the agent finished and its result has not been seen.
-
-An agent that first opens at its prompt reports `idle`, including in a background pane. After a working or blocked agent completes, it reports `done` when its tab or workspace is in the background. It reports `idle` when it completes in the active tab while the foreground client is focused. If the foreground client is explicitly unfocused, completion can become `done` even in the active tab.
-
-Focusing a pane, switching to its tab, or regaining outer terminal focus marks the visible tab as seen, so `done` becomes `idle`. Switching away does not turn an existing `idle` status into `done`; `done` is created by a later completion while the pane is unseen. With no foreground client, a new completion in the globally active tab is treated as seen while completions in background tabs still become `done`.
-
-## Start agents interactively
-
-Default to a sibling pane in the current tab and current working directory. Do not create a workspace, tab, worktree, or different cwd unless the user explicitly requests that topology or location.
-
-Honor a direction requested by the user. Otherwise inspect the caller pane's current rectangle:
-
 ```bash
-herdr pane layout --pane "$HERDR_PANE_ID"
+printf '%s\n' "$HERDR_WORKSPACE_ID" "$HERDR_TAB_ID" "$HERDR_PANE_ID"
 ```
 
-Split a wide pane to the right and a narrow or tall pane down. Avoid repeated same-direction splits that would create unusably narrow columns or short rows. Keep the user's focus in the calling pane:
+Inspect live state with `herdr pane list --workspace "$HERDR_WORKSPACE_ID"` and `herdr agent list`. Closed IDs are never reused; a pane moved to another workspace gets a new ID — re-read list/get responses after every mutation.
 
-```bash
-herdr pane split --current --direction right --no-focus
-```
+Example notation: blocks labeled `bash` are runnable as-is; blocks labeled `text` are templates — replace every `<angle-bracket-token>` before running.
 
-Replace `right` with `down` when the layout calls for it.
+## Start an executor
 
-Read `result.pane.pane_id` from the JSON response. Give the pane a useful label, then start the requested agent by running only its normal executable so its interactive TUI opens:
+The wrapper validates its arguments and the launch policy before touching anything, splits the caller pane with the executor's final cwd and `--no-focus`, validates the returned pane, checks the name is free (failing closed if the check itself fails), and launches the agent with an allowlisted command line:
 
-```bash
-herdr pane rename <returned-pane-id> "reviewer"
-herdr pane run <returned-pane-id> "codex"
+```text
+<herdr-skill-dir>/scripts/start-executor.sh <name> codex <cwd> <right|down> <low|medium|high>
+<herdr-skill-dir>/scripts/start-executor.sh <name> claude <cwd> <right|down>
 ```
 
-Use the executable that belongs to the requested agent:
+It prints the executor's pane ID on success. On nonzero exit do not prompt: if stderr contains `pane_id=...`, a pane was created and preserved — inspect it with `herdr pane get`/`herdr pane read --source recent-unwrapped --lines 80` and `herdr agent get <name>`, then report; never clean up automatically. A validation failure before splitting created nothing.
 
-- Codex: `codex`
-- Claude Code: `claude`
-- pi: `pi`
-- OpenCode: `opencode`
-- OMP: `omp`
+Codex effort is selected only through profiles (`-p effort-low|medium|high`; never edit base Codex config): low for mechanical/low-risk work, medium for domain invariants or authorization, high only when the human asks or the task is high-stakes and underspecified. Claude Code always launches with `--permission-mode auto` — an AI approver, NOT `--dangerously-skip-permissions`/`bypassPermissions`; never substitute those.
 
-Do not pass the task as an argv prompt by default. Do not add non-interactive flags. Only change the normal interactive launch when the user explicitly asks for a different launch mode or command.
+Split a wide pane `right` and a narrow or tall pane `down` (`herdr pane layout --pane "$HERDR_PANE_ID"` shows the rectangle); avoid repeated same-direction splits that produce unusable panes.
 
-Inspect the pane after launch. If `agent_status` is not yet `idle`, wait for the idle transition. Once it is idle, submit the task with `pane run`:
+## Dispatch without blocking the orchestrator
 
-```bash
-herdr pane get <returned-pane-id>
-herdr wait agent-status <returned-pane-id> --status idle --timeout 30000
-herdr pane run <returned-pane-id> "Review the current diff and report only actionable findings."
-```
+### Common mistake: freezing the orchestrator
 
-Status waits match the current status immediately or wait for a future matching transition.
+Wrong — occupies the orchestrator's foreground until the executor changes state or times out:
 
-`pane run` sends the text and Enter together. Use it for initial prompts and follow-ups instead of coordinating `send-text` and `send-keys` separately.
-
-For normal background work, wait for the agent to start working. If the pane remains in a background tab or workspace, wait for `done` before reading its transcript:
-
-```bash
-herdr wait agent-status <returned-pane-id> --status working --timeout 30000
-herdr wait agent-status <returned-pane-id> --status done --timeout 120000
-herdr pane read <returned-pane-id> --source recent-unwrapped --lines 120
+```text
+herdr agent prompt ex-a "Implement the task." --wait --until done --timeout 120000
 ```
 
-If the user is watching that tab, completion reports `idle` instead, so wait for `idle`. Always treat either `idle` or `done` as completed when inspecting `pane get`; the difference is whether the result has been seen.
+Correct — arm a per-executor monitor, then submit and return immediately:
 
-If a wait times out, inspect `herdr pane get <returned-pane-id>` and `pane read` before deciding what to do. A `blocked` agent needs input; an `unknown` pane may not yet contain a detected or integrated agent.
-
-Submit follow-ups the same way:
-
-```bash
-herdr pane run <returned-pane-id> "Now check the failing test."
+```text
+<herdr-skill-dir>/scripts/dispatch.sh ex-a 1800000 <fresh-monitor-file-path> "<contract prompt>"
 ```
 
-## Run an ordinary command in another pane
+The wrapper validates the target, creates the monitor file (which must not already exist), starts a background `working` → `idle|done|blocked` wait chain writing to it, checks the monitor has not already exited (this is not a readiness handshake), submits the prompt — stopping the monitor if submission fails — and prints the monitor PID. Use a distinct monitor file and PID per executor, and use the wrapper again for every follow-up; a follow-up to a `blocked` agent needs a fresh monitor first.
 
-Split the calling pane using the same geometry rule without moving the user's focus:
+Herdr 0.7.5 has no atomic subscribe-and-prompt primitive, so this narrows but does not eliminate the fast-transition race. If the `working` wait times out, run `herdr agent get <name>` and `herdr agent read <name> --source recent-unwrapped --lines 120`; accept a quiescent state only when the transcript shows your prompt completed, otherwise report the ambiguity — do not re-prompt automatically.
 
-```bash
-herdr pane split --current --direction right --no-focus
-```
+To notice completions without blocking, poll the recorded monitor PIDs with `kill -0` in short bounded passes between other work, then inspect `agent get` and `agent read`. Use `--wait` only for a human-requested foreground one-off. After three materially identical failures on one executor, stop prompting it, preserve its pane and worktree, and escalate to the human.
 
-Read the new `pane_id` from the JSON response, then run and inspect the command:
+## Dispatch a ready frontier at once (local policy)
 
-```bash
-herdr pane run <returned-pane-id> "just test"
-herdr wait output <returned-pane-id> --match "test result" --timeout 120000
-herdr pane read <returned-pane-id> --source recent-unwrapped --lines 120
-```
+The human's explicit topology request outranks everything in this section. Absent one: executor panes are splits inside the orchestrator's own tab — no per-task tabs or workspaces — and Herdr panes, not agent-internal subagents, are the parallelism layer (one interactive agent process per pane).
 
-Inspect existing output before waiting for future output. A wait timeout exits with status `1`.
+For N tasks with no unresolved dependency between them, dispatch the frontier at once — the serial-pull pattern (start one, wait, pull the next) is not allowed. If N would exhaust usable pane geometry, CPU, memory, mutable services, or review capacity, cap the wave at the safe limit and queue the remainder — queueing for capacity is not serial-pull; foreground-waiting on one executor is. Phase-separated:
 
-Use the read source that matches the task:
+1. Write one short contract per executor: objective, owned files/subsystem, non-goals, acceptance checks, required verification, and this fixed report shape: `STATUS: complete|blocked`, `CHANGED: <paths|none>`, `VERIFY: <commands and exit codes>`, `BLOCKER: <concrete need|none>`. Contracts in the same frontier must not claim the same writable files, ports, databases, or caches unless the orchestrator plans reconciliation. Include the contract verbatim in the prompt.
+2. Create all worktrees: `herdr worktree create --branch <b> --base main --path <p> --label <l> --no-focus --json` — unique branch and path per executor.
+3. Start all executors with `scripts/start-executor.sh`.
+4. Dispatch all prompts with `scripts/dispatch.sh`.
+5. Service whichever monitor finishes first. A `blocked` pane is a pull request for a follow-up, not a reason to stall the others. A genuine dependency defers only the dependent task to a later frontier.
 
-- `visible`: the current rendered viewport
-- `recent`: recent scrollback as rendered, including soft wraps
-- `recent-unwrapped`: recent scrollback with soft wraps joined; prefer it for logs and transcripts
-- `detection`: the bottom-buffer snapshot used by agent detection
+### Common mistake: the worktree-owned workspace
 
-Use `--format ansi` when colors and terminal styling are evidence. Otherwise use text.
+`worktree create` auto-creates a workspace to own and track the checkout. That is bookkeeping, not executor topology. Do not start the executor there: the wrapper splits a pane in the orchestrator's tab with `--cwd <checkout-path>` and passes that pane to `agent start --pane`.
 
-If the user explicitly asks for another tab, workspace, or worktree, discover that command group and use returned IDs. Do not infer a larger topology from a request to start an agent or command.
+Merge reviewed branches sequentially in dependency-safe order. Before each merge, review the executor's diff against its base: contract satisfied, no unrelated files, no secrets or generated artifacts. Run the full integration suite once after the final merge. Project-specific verification and merge commands belong to the project's AGENTS.md, not here.
 
-## Safety and coordination rules
+## Ordinary commands and verification
 
-- Use `--no-focus` for background work unless the user asked to switch context.
-- Use `--current` or an explicit ID. Do not rely on another client's focused pane.
-- Parse IDs from JSON responses. Do not derive them from sidebar order or examples.
-- Inspect before waiting. Read current output first, then wait for the next state or output you expect.
-- Do not close workspaces, tabs, panes, or sessions you did not create unless the user explicitly asked.
-- Never run `herdr server stop` from an active session unless the user explicitly intends to stop the server and its pane processes.
-- Never kill the main Herdr process. Use named test sessions for experiments that need an isolated server.
+Keep shells, tests, servers, and logs pane-native — never prompt an agent to run them. `pane wait-output` matches text already present in scrollback; it is not a future-transition primitive. Gate on a unique exit-code sentinel, never on output words:
 
----
-
-## Local conventions (this machine)
-
-These layer on top of the upstream skill above. They are generic and reusable across any Herdr + Codex orchestration on this machine; nothing here is project-specific.
-
-### Parallelism lives in Herdr, not in Codex subagents
-
-This machine's Codex config carries a layered v1/v2 subagent setup that is fragile to drive for parallel work. Do not use Codex's internal subagent delegation (`spawn_agent`, the `normalize_spawn_agent` hook, `fork_turns`, `max_threads`) as the parallelism layer for multi-task work. Herdr is the parallelism layer: one Codex process per pane, one pane per task, Herdr owns topology and state. Each executor is a fresh `codex` TUI process started in its own worktree pane.
-
-### Parallel dispatch discipline
-
-When the work has multiple tasks ready to start at the same time — a "frontier" of tasks with no unresolved dependency between them — dispatch ALL of them at once, in parallel. This is a rule on this machine, not a preference. The serial-pull pattern (start one task, wait, pull the next) defeats the purpose of running Herdr and is not allowed: if N tasks are ready, N worktrees and N executor panes are created up front, then all N prompts are submitted, then all N are monitored in parallel.
-
-Concrete sequence for a frontier of N ready tasks:
-
-1. Create all N worktrees first.
-2. Start all N executor panes (one Codex TUI per worktree), each with its effort profile.
-3. Submit all N initial prompts.
-4. Monitor all N in parallel — `wait`/`read` per pane — and service whichever blocks first. A `blocked` pane is a pull request for a follow-up, not a reason to stall the others.
-5. Merge sequentially in any order the contracts allow; run the full integration suite once after the last merge, not after each.
-
-Effort per task is chosen by the orchestrator. Default heuristic when the human does not say otherwise: `effort-low` for mechanical/low-risk tasks (rename, doc edits, pure config); `effort-medium` for tasks that touch domain invariants or authorization; `effort-high` only when the human asks, or the task is high-stakes and underspecified. A task that is genuinely blocked by another (a real dependency, not convenience) is not part of the frontier — it waits and is dispatched in a later round once its dependency merges. "Blocked by" is a dependency/merge-order signal, never a license to run the rest serially.
-
-### Select executor effort with a Codex profile, never by editing config
-
-Reasoning effort is selected per-invocation via Codex profiles that layer on top of `~/.codex/config.toml` (which keeps `model = "gpt-5.6-sol"` and its own default effort):
-
-- `codex -p effort-low`
-- `codex -p effort-medium`
-- `codex -p effort-high`
-
-The orchestrator chooses the profile per task; the base config is never edited for this. Each profile only overrides `model_reasoning_effort`, so model, sandbox, approval policy, and hooks all inherit from base.
-
-### Launching Claude Code agents: Auto Mode by default
-
-When the agent being started is Claude Code, always launch it with Auto Mode:
-
-```bash
-claude --permission-mode auto
+```text
+<herdr-skill-dir>/scripts/verify.sh <cwd> <timeout-ms> <manifest-file> "<verification command>"
 ```
 
-Auto Mode (the yellow "auto mode" indicator) uses an AI approver that judges each tool call against the prompt. It is NOT `--dangerously-skip-permissions` / `bypassPermissions` — never use those for this purpose. Without this flag Claude opens in manual mode and every permission prompt blocks the pane until a human or the orchestrator services it, which defeats background orchestration. Combine with other explicit requests as flags (e.g. `claude --model opus --permission-mode auto`).
+The wrapper splits a pane down from the caller, records the pane in the manifest, runs the command inside a child bash (so `exit`, `exec`, comments, traps, and syntax failures cannot suppress the exit marker), waits for a unique `TOKEN:<exit-code>` trailer, prints the transcript, and exits 0 only when the command's exit code was 0. On failure or timeout it prints the pane ID and transcript to stderr and preserves the pane. A timeout, a shell prompt, or an executor's claim of success is not evidence.
 
-### Start agents in an explicit tab, never the default
+For reads: `--source recent-unwrapped` for logs and transcripts, `visible` for the current viewport, `--format ansi` only when styling is evidence. (`detection` exists on `agent read` only, not `pane read`.)
 
-`herdr agent start` without `--tab` can drop the pane into whatever tab is active/last — including another orchestrator's tab. Always pass an explicit target: `--tab "$HERDR_TAB_ID"` to open next to the caller, or create a dedicated tab first (`herdr tab create --workspace "$HERDR_WORKSPACE_ID" --label <label> --no-focus`) and pass its returned tab_id.
+## Safety rules
 
-### Always start an executor in its own worktree
-
-Parallel executors never share a checkout. Create the worktree before starting the agent, then start Codex in that worktree as a TUI (not `codex exec`), so Herdr detects it and follow-ups stay possible:
-
-```bash
-herdr worktree create --branch <branch> --base main --path <worktree-path> --label <label> --no-focus
-herdr agent start <agent-name> --cwd <worktree-path> --workspace <ws> --no-focus -- codex -p effort-<level>
-```
-
-### Topology
-
-- One Herdr workspace per project.
-- One tab per parallel task; one pane per executor in that tab.
-- Name agent targets stably (e.g. `ex-<id>`) and address them by name parsed from JSON responses, never by sidebar order or guessed IDs.
-
-### Treat an executor as done only after the project verifies
-
-Before reading `done`/`idle` as shippable, run the project's own verification (tests/typecheck/build) in a split pane, not by stealing the executor's focus:
-
-```bash
-herdr pane split --current --no-focus   # then herdr pane run <split-pane-id> "<verify command>"
-```
-
-Project-specific verify commands belong to the project's AGENTS.md, not here.
+- `--no-focus` for background work; keep the human's focus in their pane.
+- Record every pane, workspace, and worktree you create (name + ID) in a per-run manifest file (`verify.sh` appends its panes automatically); close only IDs listed there, and only after `get` confirms them.
+- Never run `herdr server stop` or kill the main Herdr process from an active session. Use a named test session (`herdr --session <name>`) for experiments that need an isolated server.

proposal/scripts/start-executor.sh

#!/usr/bin/env bash
# Start an executor agent in a new split of the caller's pane.
# Usage: start-executor.sh <name> codex <cwd> <right|down> <low|medium|high>
#        start-executor.sh <name> claude <cwd> <right|down>
# Prints the executor's pane ID on success. On partial failure it prints
# "start failed; created pane_id=..." to stderr and preserves the pane.
set -euo pipefail

usage() { echo "usage: start-executor.sh <name> <codex|claude> <cwd> <right|down> [low|medium|high]" >&2; exit 64; }

[ "$#" -ge 4 ] && [ "$#" -le 5 ] || usage
name=$1 kind=$2 cwd=$3 direction=$4 effort=${5:-}

test "${HERDR_ENV:-}" = 1
test -n "${HERDR_PANE_ID:-}"
test -d "$cwd"
case "$direction" in right|down) ;; *) usage ;; esac
case "$name" in ''|-*|*[!A-Za-z0-9._-]*) echo "invalid agent name: $name" >&2; exit 64 ;; esac

# Validate launch policy BEFORE any mutation.
case "$kind" in
  codex)  case "$effort" in low|medium|high) ;; *) echo "codex requires effort low|medium|high" >&2; exit 64 ;; esac ;;
  claude) [ -z "$effort" ] || { echo "claude takes no effort arg" >&2; exit 64; } ;;
  *) echo "unsupported kind: $kind" >&2; exit 64 ;;
esac

# Name-collision check fails CLOSED: a failed list or changed schema aborts.
agents_json=$(herdr agent list) || { echo "herdr agent list failed" >&2; exit 69; }
printf '%s\n' "$agents_json" | jq -e '.result.agents | type == "array"' >/dev/null \
  || { echo "unsupported agent-list response schema" >&2; exit 69; }
if printf '%s\n' "$agents_json" | jq -e --arg n "$name" '.result.agents[] | select(.name == $n)' >/dev/null; then
  echo "agent name already in use: $name" >&2
  exit 65
fi

pane_id=""
report_partial_failure() {
  rc=$?
  if [ "$rc" -ne 0 ] && [ -n "$pane_id" ]; then
    printf 'start failed; created pane_id=%s; resource preserved\n' "$pane_id" >&2
  fi
  exit "$rc"
}
trap report_partial_failure EXIT

split_json=$(herdr pane split --pane "$HERDR_PANE_ID" --direction "$direction" --cwd "$cwd" --no-focus)
pane_id=$(printf '%s\n' "$split_json" | jq -er '.result.pane.pane_id')
herdr pane get "$pane_id" >/dev/null
herdr pane rename "$pane_id" "$name" >/dev/null

start_agent() {
  case "$kind" in
    codex)  herdr agent start "$name" --kind codex --pane "$pane_id" --timeout 60000 -- -p "effort-$effort" >/dev/null ;;
    claude) herdr agent start "$name" --kind claude --pane "$pane_id" --timeout 60000 -- --permission-mode auto >/dev/null ;;
  esac
}
# The fresh pane's shell can report agent_pane_busy for a moment; retry once.
if ! start_agent; then
  sleep 2
  start_agent
fi

herdr agent wait "$name" --until idle --timeout 30000 >/dev/null
trap - EXIT
printf '%s\n' "$pane_id"

proposal/scripts/dispatch.sh

#!/usr/bin/env bash
# Dispatch a prompt to an executor without blocking the caller.
# Starts a best-effort working -> idle|done|blocked monitor BEFORE submitting.
# Herdr 0.7.5 has no atomic subscribe-and-prompt primitive, so a fast working
# transition can still be missed; SKILL.md describes the ambiguity procedure.
# Usage: dispatch.sh <target> <completion-timeout-ms> <monitor-file> <prompt>
# Prints the monitor PID on success. Use a fresh monitor file per prompt.
set -euo pipefail

usage() { echo "usage: dispatch.sh <target> <completion-timeout-ms> <monitor-file> <prompt>" >&2; exit 64; }
[ "$#" -eq 4 ] || usage
target=$1 timeout_ms=$2 monitor_file=$3 prompt=$4

test "${HERDR_ENV:-}" = 1
case "$timeout_ms" in ''|*[!0-9]*) usage ;; esac
[ ! -e "$monitor_file" ] || { echo "monitor file already exists: $monitor_file" >&2; exit 64; }
(umask 077; : >"$monitor_file")

herdr agent get "$target" >/dev/null

(
  herdr agent wait "$target" --until working --timeout 60000 &&
  herdr agent wait "$target" --until idle --until done --until blocked --timeout "$timeout_ms"
) >"$monitor_file" 2>&1 &
monitor_pid=$!
# Confirms only that the monitor has not already exited; not a readiness handshake.
kill -0 "$monitor_pid"

if ! herdr agent prompt "$target" "$prompt" >/dev/null; then
  kill "$monitor_pid" 2>/dev/null || true
  wait "$monitor_pid" 2>/dev/null || true
  echo "prompt submission failed; monitor stopped" >&2
  exit 70
fi
printf '%s\n' "$monitor_pid"

proposal/scripts/verify.sh

#!/usr/bin/env bash
# Run a verification command in a fresh split pane and gate on its EXIT CODE,
# never on output text. The command runs in a child bash so exit/exec/comments/
# traps/syntax errors cannot suppress the exit marker. Prints the transcript;
# exits 0 only if the command exited 0. Records the pane in the manifest and
# preserves it on failure.
# Usage: verify.sh <cwd> <timeout-ms> <manifest-file> <command>
set -euo pipefail

usage() { echo "usage: verify.sh <cwd> <timeout-ms> <manifest-file> <command>" >&2; exit 64; }
[ "$#" -eq 4 ] || usage
cwd=$1 timeout_ms=$2 manifest_file=$3 command=$4

test "${HERDR_ENV:-}" = 1
test -n "${HERDR_PANE_ID:-}"
test -d "$cwd"
case "$timeout_ms" in ''|*[!0-9]*) usage ;; esac

pane_id=""
on_exit() {
  rc=$?
  if [ "$rc" -ne 0 ] && [ -n "$pane_id" ]; then
    printf 'verification pane_id=%s (preserved)\n' "$pane_id" >&2
    herdr pane read "$pane_id" --source recent-unwrapped --lines 200 >&2 || true
  fi
  exit "$rc"
}
trap on_exit EXIT

token="HERDR_VERIFY_${RANDOM}_$$"
split_json=$(herdr pane split --pane "$HERDR_PANE_ID" --direction down --cwd "$cwd" --no-focus)
pane_id=$(printf '%s\n' "$split_json" | jq -er '.result.pane.pane_id')
herdr pane get "$pane_id" >/dev/null
printf '%s\t%s\n' verification-pane "$pane_id" >>"$manifest_file"

printf -v quoted_command '%q' "$command"
pane_command="bash -c $quoted_command; rc=\$?; printf '%s:%s\\n' '$token' \"\$rc\""
herdr pane run "$pane_id" "$pane_command" >/dev/null
herdr pane wait-output "$pane_id" --regex "${token}:[0-9]+" --source recent-unwrapped --lines 200 --timeout "$timeout_ms" >/dev/null
output=$(herdr pane read "$pane_id" --source recent-unwrapped --lines 200)
printf '%s\n' "$output"
printf '%s\n' "$output" | grep -Fq "${token}:0"
trap - EXIT

proposal/scripts/check-compat.sh

#!/usr/bin/env bash
# Read-only compatibility gate for this skill's wrappers.
# Verifies the herdr version and that the pane/agent groups still advertise
# every command and flag the wrappers rely on. Never mutates anything.
# Usage: check-compat.sh
set -euo pipefail

test "${HERDR_ENV:-}" = 1

version=$(herdr --version)
case "$version" in
  "herdr 0.7.5") ;;
  *) echo "unsupported herdr version: $version (audited: herdr 0.7.5)" >&2; exit 69 ;;
esac

fail=0
need() { # need <group-help-text> <needle> <group-label>
  case "$1" in
    *"$2"*) ;;
    *) echo "missing from 'herdr $3': $2" >&2; fail=1 ;;
  esac
}

# Bare groups print usage and exit nonzero; capture regardless.
pane_help=$(herdr pane 2>&1 || true)
agent_help=$(herdr agent 2>&1 || true)

need "$pane_help" "pane split" pane
need "$pane_help" "--direction right|down" pane
need "$pane_help" "--cwd PATH" pane
need "$pane_help" "--no-focus" pane
need "$pane_help" "pane run" pane
need "$pane_help" "pane read" pane
need "$pane_help" "pane wait-output" pane
need "$pane_help" "--regex PATTERN" pane
need "$agent_help" "agent list" agent
need "$agent_help" "agent get" agent
need "$agent_help" "agent start <name> --kind KIND --pane ID" agent
need "$agent_help" "agent prompt <target> <text>" agent
need "$agent_help" "agent wait <target> [--until STATUS]" agent

[ "$fail" -eq 0 ] || exit 69
echo "herdr compatibility: ok (herdr 0.7.5)"