Customize the orchestrator prompt
View as markdownThe orchestrator is your runner (claude, codex, …) booted with a
system prompt that explains the board, the workspaces, and the loop. That
prompt is the contract for who initiates what, how dispatch is decided,
and how the agent reports back. Shelbi ships a sensible default and
seeds it into every project as an editable file. (This page is about
that prompt. The status pipeline issues move through is a separate
thing, the YAML workflow.)
This page customizes the orchestrator's prompt, encodes three concrete tweaks, and applies them. The underlying machinery lives in the orchestrator concept page; this is the practical version.
Where the prompt lives
The orchestrator is a project-local agent with shipped defaults.
Its prompt is composed from two files, both under the project's agents/
directory (~/.shelbi/projects/<name>/agents/ in the default
global mode, or <repo>/.shelbi/agents/
in in-repo mode):
agents/orchestrator/instructions.md: the orchestrator-specific system prompt. Seeded with the shipped default byshelbi init; your edits stay put on upgrade. (Self-heal does merge a few runner-critical orchestrator sections back in if your copy is missing them, and re-adds the## Changelogsection if you delete its heading.)agents/_shared/preamble.md: project-wide context prepended to every agent (developer, review, qa, orchestrator…). Put the repo layout, house style, and test command here so you write it once instead of pasting it into every agent's prompt.
Every time the orchestrator launches (at session start and on every
shelbi reload), Shelbi composes preamble.md + instructions.md and
writes the rendered output to
~/.shelbi/projects/<name>/.claude/agent-instructions.md, which is
state, so it lives under ~/.shelbi/ in both modes. Claude receives it
through --append-system-prompt; Codex gets it as part of its startup
prompt.
Don't hand-edit the rendered prompt
.claude/agent-instructions.md is a rendered artifact, rewritten on
every orchestrator launch, so hand-edits are silently lost. Put
project-wide bits in _shared/preamble.md and orchestrator-specific
bits in agents/orchestrator/instructions.md. Older versions rendered
the prompt to ~/.shelbi/projects/<name>/CLAUDE.md; that file is no
longer read, so move anything you added there into those two files and
delete it.
Start from the default
Don't rewrite from a blank file. The default prompt encodes load-bearing contracts (bootstrap, reaction rules, reason strings) that the rest of Shelbi expects the orchestrator to honor. Open the seeded default and edit in place:
shelbi agent edit orchestratorThat opens agents/orchestrator/instructions.md (seeded by
shelbi init) in $EDITOR. The file is plain markdown. Read it top to bottom before changing
anything. The comments explain why each section exists.
What to keep when you fork
A handful of pieces are the contract between the orchestrator and the rest of the system. Edit them carefully, but don't delete:
-
The bootstrap flow. The first reply of every session (and after every
shelbi reload):- runs
shelbi status --full --handofffor one snapshot of the board, workspaces, Zen mode, and any handoff note; - starts a non-consuming
shelbi events tail --follow --project <you>as a latency accelerator; - runs the periodic self-drain,
shelbi orchestrator events next --follow --max-lifetime 2sfollowed byshelbi orchestrator events ack <id>. This drain is the delivery guarantee: drop it and events go unprocessed; - reads
shelbi config upgrade --needs-judgment --format jsonfor config findings that need a decision.
Drop any of these and the orchestrator boots without state.
- runs
-
The reaction rules tied to specific reason strings. The orchestrator dispatches on
user:*promotions, rolls workspaces onworkspace:ready-marker, and wakes onheartbeatlines. The rest of Shelbi emits those strings. Your prompt has to recognize them. -
The "you are the scheduler" framing. Without it, the agent reverts to chatbot mode and waits to be told what to do. The whole loop falls apart.
-
The
## Zen Modesection (if you intend to use Zen). It points the orchestrator atzenmode.md, which holds the judgment categories and merge conditions. Tune Zen by editingzenmode.md(tweak 2 below), not this section.
Everything else is fair game.
Three example tweaks
A prompt override pays for itself the first time the agent stops asking a question you've answered the same way a dozen times. Three patterns worth stealing.
1. Pin certain task shapes to specific workspaces
The default scheduler picks the first free workspace in YAML
declaration order, skipping review-tagged workspaces and any slot you
have open as a shell, and honoring each issue's prefers_machine: hint. If your project
has natural routing (infra issues always to a beefy box, UI issues
always somewhere with the design system pre-cached), bake it into
the prompt:
## Routing rules
In addition to each issue's `prefers_machine:` hint, apply
these project-specific rules when picking a workspace for a `todo`
card:
- **Infra issues**: titles containing `infra:`, `terraform`,
`helm`, `kubectl`, or paths under `infra/`. Always route to
`devbox` (the beefier remote). If no `devbox` workspace is free,
leave the card in `todo` rather than routing to the hub.
- **Docs and content**: titles containing `docs:` or paths under
`site/content/**`. Route to the first free hub workspace; these
are short, IO-light issues that don't need the remote.
- **Migration touch-ups**: anything matching `db/migrate/**` or
`crates/shelbi-state/src/migrations/**` always goes to
`charlie` (so the same agent context accumulates across the
series). If charlie is busy, hold in `todo`.
These rules take precedence over default declaration-order
selection. An issue's `prefers_machine:` hint still overrides
everything if it is set.The orchestrator now applies your routing on top of the default free-workspace scan. No code change.
2. Tune Zen's judgment categories for this project's reality
Zen's policy doesn't live in the orchestrator prompt. The judgment
categories and merge conditions are in a separate user-owned file,
zenmode.md (~/.shelbi/projects/<name>/zenmode.md in global mode, or
<repo>/.shelbi/zenmode.md in in-repo mode). The orchestrator reads it
as the source of truth whenever Zen is on, so edit that file, not
instructions.md. See the zenmode.md file
for its full shape.
The bundled default's judgment categories are deliberately
conservative: promote if you've routinely accepted this shape, or
the user just raised the issue, or it's part of a larger body of
work they kicked off. That's a sensible starting bar, but every
project has its own "always safe" pattern. Replace the
## Auto-promote judgment categories section of zenmode.md to
encode it:
## Auto-promote judgment categories
Promote a backlog candidate to `todo` only if **at least one** is
true:
1. **Tagged `automation:` in the title.** Always in scope: these
are bot-filed PR-bumps and lint sweeps we have years of
acceptance history on.
2. **Touches only `docs/**` or `site/content/**`.** Content
edits are reversible and never reach prod. If the issue body
names a file outside those globs, fall through.
3. **The user has accepted ≥3 issues of the same shape (same
verb-prefix, same target directory) without changes in the
last week.** Track this against the `done` status via
`shelbi issue list --status done`.
If none of the above, leave the card in `backlog`, emit
`reason=orchestrator:zen-decline reason-text=<short>`, and surface
it in the next reply ("I considered promoting `<issue>` but wasn't
sure, want me to?").Leave the ## Merge conditions section as shipped unless you mean to
change it. Keep the file's first line a one-line summary of the
policy and update it when you change the rules: the hub's heartbeat
re-injects that line into the orchestrator every few ticks while Zen
is on.
The Rust side (shelbi zen scan) never inspects this prose. It
just emits the mechanically-eligible candidates. Your policy
decides which of those actually get promoted.
3. Change the reporting style
The default prompt's ## Reporting rule leads each reply with a terse
one-line summary of what moved, naming issues by branch without the
user prefix (palette-icons started on alpha, fetch-loop -> handoff, no ready issues for charlie). If you'd rather get a richer rundown (or a
quieter one), say so:
## Reporting style
When dispatching, reply with:
- The card id and chosen workspace (always).
- The full first line of the issue body (so the user sees what
you're about to make the workspace work on).
- An estimated complexity tag (`xs` / `s` / `m` / `l`) based on
the body and any `depends_on`. Don't overthink it: a one-token
guess is better than nothing.
When reporting a finished review:
- The card id, the workspace, and the branch.
- A two-bullet summary of what the diff changed (read it via
`git diff main..<branch> --stat`).
- Whether a relevant `done`-column precedent exists for this
shape of change.
Background sweeps (heartbeat-triggered re-checks) report nothing
unless they take action. Silence is fine when the board is quiet.This is the easiest place to start customizing. The behavior the orchestrator gives you is downstream of the prose you write here. Ask for the report you actually want.
Apply the edits
Edit the orchestrator's instructions
shelbi agent edit orchestratorOpens agents/orchestrator/instructions.md in $EDITOR.
Re-render and restart the orchestrator
shelbi reloadRestarts the orchestrator session so it relaunches with the prompt composed from your edits.
Verify what landed
shelbi agent show orchestratorPrints instructions.md followed by the agent's skills/.
The composed prompt (preamble + instructions) is written to
~/.shelbi/projects/<name>/.claude/agent-instructions.md every time the
orchestrator launches. Read that file to see exactly what the runner
loads.
shelbi reload reloads the whole project: it restarts the daemon,
reattaches open clients, and replaces the orchestrator session.
Workspaces keep running. Before the old orchestrator goes away it
writes a handoff note (agents/orchestrator/handoff.md) that its
successor ingests and then deletes, so in-flight context carries over.
The raw conversation transcript does not.
Iterate from prose, not code
The whole point of putting the orchestrator's policy in markdown is that you can keep tightening it. Two practical habits:
- Treat surprises as prompt bugs. When the orchestrator does
something you didn't expect (promotes a card you'd have held,
reports in a style you find noisy, picks the wrong workspace), open
agents/orchestrator/instructions.mdand add the rule that would have produced the outcome you wanted. Reload. Try again. - Version-control the prompt. Check
agents/orchestrator/andagents/_shared/into the repo (or a dotfiles repo) and symlink them into place. These prompts are the most opinionated artifacts in your Shelbi setup, and the ones most worth preserving across machine moves and reinstalls.
What you should not do is try to encode policy in code. The
mechanical layer (the Rust CLI) is intentionally generous.
shelbi zen scan will hand the orchestrator everything that's
mechanically safe, and your zenmode.md picks which of those to actually
run. That separation is what lets you raise or lower the bar by
editing prose.
See also
- Workflow config: the YAML field reference for the status pipeline the orchestrator runs work through.
- Orchestrator: how the prompt template is loaded, the bootstrap flow it triggers, and the reaction rules tied to specific event reason strings.
- Zen Mode: the high-confidence bar your custom judgment categories sit on top of.
- The events log: the full reason string vocabulary the orchestrator emits and your override may want to recognize or extend.
shelbi zen: the single-purpose primitives the orchestrator sequences during auto-merge, available to call by hand any time.