Skip to content
Back to skills

Coordinator Dispatching Work

ASecurity

**Why:** Manual `tmux send-keys 'claude'` followed by `$thrum:thrum-prime` skips identity registration and produces silent CWD drift. The `thrum tmux launch <name>` flow registers the agent against the worktree path correctly and gives the daemon a real PID to track.

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added November 7, 2026
researchrustgobashgitapisecurity

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned November 7, 2026

npx -y skills add thrum-team/thrum-pro --skill coordinator-dispatching-work --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Coordinator Dispatching Work?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Coordinator Dispatching Work
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/thrum-team-coordinator-dispatching-work-thrum-pro/badge)](https://www.skillsdirectory.com/skills/thrum-team-coordinator-dispatching-work-thrum-pro)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: coordinator-dispatching-work
description:
  "Use when starting an epic, dispatching to an implementer or orchestrator,
  choosing or re-routing which orchestrator gets a task, creating a worktree for
  an agent, or spawning a sub-agent. Loads coordinator-specific discipline for
  kicking off implementation work - routing by requirement and checking the
  target's load first."
# source: claude-plugin/skills/coordinator-dispatching-work/SKILL.md
---

## Coordinator: Dispatching Work

### Use `thrum tmux launch` — not raw send-keys

**Why:** Manual `tmux send-keys 'claude'` followed by `$thrum:thrum-prime` skips
identity registration and produces silent CWD drift. The
`thrum tmux launch <name>` flow registers the agent against the worktree path
correctly and gives the daemon a real PID to track.

**How to apply:** Whenever you need to start a runtime in an existing tmux pane,
use `thrum tmux launch <session_name>` even if you've already typed the runtime
command yourself. If you've already started one wrong, kill the pane and
re-launch via the daemon. If the pane doesn't exist yet, use
`thrum tmux start <name>` (creates, launches, primes, attaches in one command).

### Recycling an agent: destroy then teardown

**Why:** The inverse of dispatch is removal, and it has the same "two-step
ritual or things break silently" property as dispatch via tmux launch + thrum
send. See `coordinator-managing-state-and-lifecycle` § "Destroy an agent before
tearing down its worktree" for the canonical sequence (`thrum tmux kill` BEFORE
`thrum worktree teardown`). The dispatching skill mentions it here so you find
the cross-reference when planning a wave recycle, not just when reading the
lifecycle skill end-to-end. Teardown does not delete the agent row: it stays
retired until a separate `thrum agent delete <agent>` (after the worktree is
gone) or the sweeper reaps it.

### Never spawn sub-agents into worktrees where Thrum agents are running

**Why:** Sub-agents (Agent tool) and Thrum agents (`thrum send`) are different
coordination mechanisms. A sub-agent spawned into a worktree where a Thrum agent
already sits competes for files, identity, and tmux state — the result is
identity drift, broken nudges, and silent message loss.

**How to apply:** Run `thrum team` before spawning any Agent tool call. If a
worktree shows a registered agent, communicate with it via
`thrum send --to @<agent_name> --body-file msg.md` instead. Sub-agents are for
research/explore, code review, and message listeners running in the main repo —
use message listeners only when tmux pane delivery is unavailable, and never for
implementation work in another agent's worktree.

### Dispatch via `thrum send` after launch — not via tmux send-keys

**Why:** After `thrum tmux launch`, all coordination flows through the inbox +
daemon nudge: `thrum send` enters the message in the daemon's state, the daemon
nudges the pane, the agent reads the inbox and starts work. Injecting the prompt
with `thrum tmux send` or `tmux send-keys` bypasses the inbox entirely, breaks
the nudge for future messages, and strands the agent without a recorded message.

**How to apply:** Correct flow: `thrum tmux launch <name>` → agent auto-primes →
`thrum send --to @agent_name --body-file prompt.md` (body: work prompt) → daemon
nudges the pane → agent reads inbox and begins work. Never inject the prompt as
raw keystrokes.

### Always dispatch sub-agents in the background — never block the coordinator

Set `run_in_background: true` on every Agent/Explore call, without exception.
The coordinator is long-lived and must never block on a result — after
dispatching, continue with inbox checks, task tracking, or the next dispatch
draft; slot the result in when notified (even if it's "needed before" the next
step). Account token cost is irrelevant; preserving coordinator context is the
optimization.

### Subagent model selection

> **Model tiers:** pass an explicit `model:` on every dispatch; choose model and
> effort per the `choosing-subagent-models` skill (read `runtime.role_models` at
> the moment of use). Never let a sub-agent inherit your own model.

### Check the target's queue before you dispatch (R3)

**Spread the load:** if you have more than one orchestrator or implementer,
don't send every epic, bead or fix to the same one. List the live (◍) rows by
role with `thrum team --all --role orchestrator --compact` (implementers:
`--role implementer`), compare against `thrum queue list` assignees and stale
markers, pick an idle one and spread the work, and `thrum queue assign` the
bundle the same turn.

Before dispatching, read the target's load two ways: its queue AND its pane.
`thrum queue list --agent <target>` (a well-run orchestrator keeps its queue
current) plus a quick `thrum tmux capture <target>` to see what it is mid-task
on (message it to confirm if its state is unclear). An empty result does NOT
mean free — it also shows for an agent that keeps no queue or that you
mis-named; confirm by message before assigning. `assign` appends to
`assigned_to` with no duplicate check, so this pre-dispatch read is the only
guard against double-loading a busy agent. Record the handoff on your own queue
with `thrum queue assign <bundle> <target>`, then send the real dispatch via
`thrum send`. Without a Pro licence (`not entitled` / `requires a license`),
skip this write and track it in the message thread instead.

One bundle per epic/branch handed out — keep it reconciled as the work moves
(`start` → review → merge-gate → torn down), per `using-the-queue`. You RECORD
at dispatch (here); you CLOSE at a trigger — the moment the branch merges into
trunk or the last referenced bead closes, `done` + `drop` in that same turn (see
`coordinator-merging-code` §7 and `using-the-queue`). ADD has a natural trigger
and gets done; the close has one only if you make the merge/close BE it.

### Every dispatch carries a scope block — it is the spec

Before sending any dispatch, decide what the work should contain, what is out of
bounds, and roughly how big it should be. Put that at the top of the dispatch:

```text
SCOPE (coordinator ruling)
Ask:       <one sentence; the owner's own words where they gave them>
In:        <what changes: areas, behaviour, bundled bead IDs>
Out:       <what is excluded, especially the tempting extras>
Budget:    ~N production lines / M files
Model:     implementer model; the stronger role model at medium effort for
           security-touching, epic or complicated work, else the default
Gate path: <changed packages; test-only lands same turn; load test yes/no>
Rule:      If the work will exceed the budget or touch anything in Out, STOP
           and report to the coordinator before continuing. Hold your
           implementers to the same limit; no guards for unseen cases.
```

Send the scope block as the dispatch message, then queue the work with
`--ref msg:<dispatch-message-id>`. Post later rulings as replies in that thread,
so the queue item points at the spec plus every ruling on it.

When a tip comes back, compare `git diff --stat trunk...tip` with the Budget and
the Out line before relaying, approving or gating it. Over budget without a
report means stop the lane and ask; never approve growth because it is
technically better. Bundled candidates (next section) go on the In line with
their own budget.

### Bundle adjacent open issues into every dispatch

**Why:** Priority order and code locality are INDEPENDENT axes, and sequencing
by priority alone silently optimizes the wrong one. The expensive part of any
task is loading the context — the package, the call paths, the invariants. Once
an implementer has paid that cost, a second bead two files away is nearly free.
Ship them one at a time to cold implementers and you pay full context load for
each, while a P0 sits in the queue purely because it sorted into a different
row.

Most backlogs are far more adjacent than their titles suggest. Bundling
collapses the queue fast; one-at-a-time dispatch is the wasteful default that
feels orderly.

**How to apply — the coordinator half:**

Before sending ANY dispatch, run an adjacency pass. Delegate it (it is a wide
read across beads and packages — exactly what should not burn coordinator
context):

1. Determine each item's CODE AREA — package, subsystem, files. Derive it from
   `bd show <id>` **plus reading the code**, never from the bead title. Two
   beads with similar titles may live in different packages; two with unrelated
   titles may share a file.
2. Find OPEN issues touching those same areas — **including higher-priority
   ones**. A P0 adjacent to a P2 you are dispatching is the whole point of this
   pass.
3. Name the inverse too: which open issues have NO adjacency to this batch. That
   set is what genuinely stays unstaffed, and stating it stops a later reader
   from mistaking an un-surfaced issue for a deliberately parked one.
4. **You make the ride-along call.** The sub-agent reports adjacency and
   evidence; it does not rank, prioritize, or decide.

Do this at SEQUENCING time, before dispatch messages go out. Afterwards the
routing is committed and folding an item in costs more than the pass saves.

> 🔴 **NEVER run `bd list --all`** while doing this, in any form —
> `--all --limit N` is STILL unbounded — the limit is discarded. Get ground
> truth from `bd stats`, bound above that count, and **verify the printed
> `Total:` is not equal to your limit** — equal means you are at the ceiling and
> were silently truncated. Put these rules in the sub-agent's brief; it cannot
> see the damage from where it runs.

**How to apply — the orchestrator half (this is where validity gets checked):**

Do NOT try to verify the adjacent items are still valid yourself. You are cold,
and your list goes stale between the pass and the dispatch. **The orchestrator
cuts its branches from the CURRENT tip and merges forward onto it (never
rebases) before handoff**, so it is working against today's code — which makes
validity checking nearly free at exactly the moment it is accurate.

So dispatch adjacent items as CANDIDATES and say so explicitly. The
orchestrator's own skill (`orchestrate`, Phase 1 Step 2b) defines what that word
obligates; you do not need to restate the procedure in the dispatch, only to
mark the items clearly and give each one its bead ID.

What comes back: still-valid candidates get folded into the warm implementer;
already-fixed ones return to you as COMPLETED with evidence so **you close the
bead** — draining the queue with nobody implementing anything; ambiguous ones
return as questions. Expect a disposition for every candidate, including the
folded-in ones.

**Expect returns, and act on them.** A candidate returned as already-fixed is
only half-drained until you actually close the bead.

### Create agent worktrees with `thrum worktree create`

**How to apply:** One command makes the branch, worktree, `.thrum/redirect`,
agent registration, tmux session and runtime launch:

```bash
thrum worktree create <name> -b <branch> --base <base-ref> \
  --name <agent> --role <role> --module <module> --intent "<one line>"
```

Never `git worktree add` an agent worktree: it leaves no `.thrum/redirect` and
can land outside `worktrees.base_path`. A worktree that already exists is wired
with `thrum worktree adopt <path>`.

### Prompt construction for implementers

**Why:** Implementer agents work better with a structured handoff than a
free-form request. Inconsistent dispatch produces inconsistent reports and
re-dispatch overhead.

**How to apply:** Every dispatch prompt should include:

1. The epic/task title and bead ID
2. One-paragraph scope (what to build, what NOT to build)
3. Acceptance criteria as bullets
4. The worktree path the work happens in
5. An explicit reminder to pass `model:` on any sub-agents the implementer
   spawns (model and effort per `choosing-subagent-models`)
6. Spec/plan paths to read before starting
7. **Adjacent candidate beads** from the adjacency pass above, labeled as
   CANDIDATES with their validity explicitly unverified — plus the instruction
   to check them against the merged-forward tip and either fold them in or
   return them as completed

### Anti-pattern-removal epics must ship a ratchet lens

**Why:** during a prior owner-bypass remediation, judgment review alone let 11
new instances of the exact anti-pattern being removed land through the merge
gate mid-sprint, because no mechanical check enforced a monotonic budget across
diffs.

**How to apply:** When dispatching an epic whose purpose is removing an existing
anti-pattern (not just fixing one instance of it), the acceptance criteria MUST
include a mechanical ratchet lens (see `coordinator-hotpath-merge-gate` §
"Invariant-ratchet lenses") wired into `.thrum/hotpath-gate.json` as
`always_run` before the epic is considered closeable — not as a follow-up. A
judgment-only acceptance ("reviewer confirms the count went down") is
insufficient; the count must be enforced by a standing mechanical budget the
gate itself checks on every subsequent merge.

### Execution invariants — carry these in every implementation dispatch

**Why:** A plan is a snapshot; trunk moves and reality drifts from it. Sprints
stall when an implementer treats the plan as ground truth, hits one mismatch,
and goes quiet.

**How to apply:** Put these in every implementation dispatch, and require each
implementer to propagate them to its own sub-agents:

1. **Branch off current trunk** — cut the work branch from the current tip,
   never the plan's authored-against base.
2. **Re-anchor before trusting any line number** — re-run the plan's "verify
   base" diff against the current tip and re-derive every file:line target. A
   moved anchor is expected, not a blocker.
3. **Run a spec-intent trace before grinding tasks** — walk every spec
   requirement forward into the plan (PLANNED / NAME-ONLY / ABSENT / PARTIAL)
   and confirm the tasks COMPOSE to the goal. A set of individually-passing
   tasks that does not deliver the intent is a failed sprint that looks green.
4. **Step back between increments** — re-check the whole against the intent, not
   task-by-task.
5. **Never go quiet on a mismatch** — when the plan diverges from reality,
   surface it up the tree with a proposed adaptation and keep moving. A mismatch
   is a routing event, never a stop.

### Never rename an agent tied to a worktree

**Why:** Agent identity is bound to the worktree, not the epic. Re-registering
`@implementer_api` as `@implementer_billing` mid-flight creates two identity
files in the same worktree, causing persistent stop-hook misfires and routing
failures.

**How to apply:** Run `thrum team` before assigning new work to confirm the
existing identity name. Send work to that name. Do not use `thrum quickstart`
with a new name in a worktree that already has an identity. If you absolutely
need a fresh identity, kill the existing tmux session and register a new one
with a different name — do not rename in place.

### Propagate model-selection discipline downward

**Why:** Sub-agents inherit the parent model by default. A coordinator whose own
tier is costly that spawns an unspecified sub-agent gets costly work for tasks
that need a cheap tier. The same trap repeats inside an implementer's worktree:
if the implementer doesn't propagate the discipline, their own sub-agents
silently inherit too. Cost compounds across a session.

**How to apply:** Every dispatch prompt should include the model-selection rule
explicitly: "When you spawn your own sub-agents, pass explicit `model:` — choose
model and effort per the `choosing-subagent-models` skill (read
`runtime.role_models` at the moment of use); never inherit your own model."
Audit the dispatch prompt before sending.

### The impl-prompt review stamp satisfies pre-dispatch review

**Why:** When the planning-skill review loop runs, its final gate reviews the
implementation prompt against the plan — which IS the pre-dispatch review.
Re-running a pre-dispatch prose review on a prompt that already passed the loop
double-reviews the same artifact and wastes a cycle.

**How to apply:** At dispatch, grep the impl-prompt for the loop's verdict stamp
(case-sensitive, literal):

```bash
# Anchored, NOT -F: `verdict=Ready:Yes-with-residual` satisfies a bare
# substring match and skips the pre-dispatch review entirely.
grep -E 'THRUM-REVIEW: stage=prompt verdict=Ready:Yes([[:space:]]|-->|$)' "$PROMPT_FILE" \
  || grep -E 'THRUM-REVIEW: stage=prompt verdict=OVERRIDE([[:space:]]|-->|$)' "$PROMPT_FILE"
```

- **Stamp present** → the pre-dispatch review is already satisfied; SKIP
  re-running it and dispatch. (The binding check itself — does the stamp still
  bind the exact prompt object and locked plan — is `project-setup`'s job, not
  this gate's; see its canonical contract, `project-setup` SKILL.md § "Step 5:
  Stamp the prompt for the review loop" + Phase 0. Do not restate that recipe
  here.)
- **Stamp absent on a project-setup-produced prompt is an ANOMALY, not a
  sanctioned shortcut.** After the prompt-stamp fix (`project-setup` Step 5),
  project-setup cannot report completion or dispatch-readiness without appending
  this stamp — so a project-setup prompt reaching dispatch without one means
  something skipped a step. Do not treat its absence as normal; run the full
  pre-dispatch dual review AND surface the missing stamp as a finding. The one
  legitimate, narrow carve-out: **pre-feature prompts and prompts from
  non-project-setup flows** genuinely never carry this stamp — for those, fall
  through to the normal pre-dispatch dual review same as before, with no anomaly
  flag.

This is the prose side of the boundary; the post-DONE dual-review (which reviews
the implementer's CODE, a different artifact) always runs separately. The prompt
is never reviewed twice. (See `coordinator-running-review-cycles` for the
post-DONE side.)

### Dispatching to an Orchestrator (Manager-Tier Flow)

When the fleet has standing orchestrators and the work is a full plan execution:

🔴 **Route by what the work REQUIRES, not by which orchestrator is easiest to
reach.** An orchestrator co-located with special resources - a
build/signing/release box, the shared data store, a particular OS - is RESERVED
for work that needs those resources; all other work goes to a general-purpose
orchestrator, addressed BY NAME. The locally-visible orchestrator is the one you
reach for by reflex, and that reflex overloads it. Enumerate the FULL set first
(local and remote alike), then pick by requirement and by load - never by
visibility.

#### Step 1: Select an orchestrator

```bash
thrum team  # identify free orchestrators
# Read State.md for each free orchestrator to check affinity:
cat .thrum/agents/<orchestrator_name>/State.md | head -50
```

#### Step 2: Send the plan

```bash
thrum send --to @<orchestrator_name> --stdin <<'EOF'
Plan assigned: <plan-file-path>
Summary: <one-line>
Merge target: <branch>
Epic count: N
Invoke $thrum:orchestrate to begin.
EOF
```

#### Step 3: Your role during execution

- You receive the orchestrator's merge report when all epics complete.
- Run your merge-approval gate (see the merge approval rules in your preamble).
- Monitor the orchestrator's status updates; escalate to the operator only for
  genuine judgment calls (architectural pivot, scope change, budget concern).

### Project-specific rules (already loaded)

Load the $thrum:project-rules-protocol skill and follow it.

If you accumulate a new rule mid-session (the user corrects you), capture it via
the Memory section of your role preamble — it references the `thrum-memory`
skill for the canonical `thrum memory create` shape.

Files in this skill

  • SKILL.md19.4 KB
  • agents/openai.yaml752 B

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.