Author a custom Shelbi workflow

View as markdown

The orchestrator is your runner (claude, codex, …) booted with a system prompt that explains the board, the workspaces, and the loop. That prompt is the workflow: 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 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 on first load; your edits stay put on upgrade.
  • agents/_shared/preamble.md — project-wide context prepended to every agent (developer, qa, orchestrator…). Put the repo layout, house style, and test command here so you write it once instead of pasting it into four prompts.

On every shelbi reload (and at session start) Shelbi composes preamble.md + instructions.md and writes the rendered output to ~/.shelbi/projects/<name>/CLAUDE.md, which is state, so it lives under ~/.shelbi/ in both modes. The orchestrator launches in that directory and auto-loads the rendered prompt. No flags, no env vars, no MCP.

Don't hand-edit CLAUDE.md

CLAUDE.md is a rendered artifact. Put project-wide bits in _shared/preamble.md and orchestrator-specific bits in agents/orchestrator/instructions.md. Every shelbi reload overwrites CLAUDE.md, so hand-edits are silently lost.

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 orchestrator

That opens agents/orchestrator/instructions.md in $EDITOR (and materializes the shipped default first if you haven't touched it yet). 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 runs shelbi task list, shelbi workspace list, starts shelbi events tail --follow, and reads shelbi zen status. Drop any of these and the orchestrator boots without state.
  • The reaction rules tied to specific reason strings. The orchestrator dispatches on user:* promotions, rolls workspaces on workspace:ready-marker, and wakes on heartbeat lines. 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-Mode section (if you intend to use Zen). Replace the judgment categories and the merge conditions if they don't fit your project, but keep the section structure. The wrapper around shelbi zen probe reads the same primitives regardless of the prose around them.

Everything else is fair game.

Three example tweaks

A workflow 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, honoring prefers_machine hints. If your project has natural routing (infra tasks always to a beefy box, UI tasks always somewhere with the design system pre-cached), bake it into the workflow:

## Routing rules
 
In addition to the project YAML's `prefers_machine` hints, apply
these project-specific rules when picking a workspace for a `todo`
card:
 
- **Infra tasks** — 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 tasks 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. The YAML's `prefers_machine` hint still overrides
everything if set explicitly on a card.

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

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. Encode it:

## Zen Mode
 
### 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 task body
   names a file outside those globs, fall through.
3. **The user has accepted ≥3 tasks of the same shape (same
   verb-prefix, same target directory) without changes in the
   last week.** Track this against the `done` column via
   `shelbi task list --column 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 `<task>` but wasn't
sure — want me to?").
 
### Merge conditions
 
(Inherit from the default — see the bundled template.)

The Rust side (shelbi zen scan) never inspects this prose. It just emits the mechanically-eligible candidates. Your override decides which of those actually get promoted.

3. Change the reporting style

The default prompt errs toward terse one-line status updates ("✓ dispatched to delta. branch: shelbi/fix-login"). 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 task 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

1

Edit the orchestrator's instructions

shelbi agent edit orchestrator

Opens agents/orchestrator/instructions.md in $EDITOR.

2

Re-render and respawn the dashboard

shelbi reload

Composes the prompt against your edits and respawns the panes.

3

Verify what landed

shelbi agent show orchestrator

Prints instructions.md followed by the agent's skills/.

The composed prompt (preamble + instructions) is written to ~/.shelbi/projects/<name>/CLAUDE.md on every shelbi reload. Read that file to see exactly what the runner loads.

shelbi reload respawns the sidebar, Tasks, and Review panes against the new config without restarting workspaces or losing chat history. It does recycle the orchestrator pane, so its conversation context resets: the cost of changing the system prompt mid-session. Heads up before the next turn.

Iterate from prose, not code

The whole point of putting the workflow 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.md and add the rule that would have produced the outcome you wanted. Reload. Try again.
  • Version-control the prompt. Check agents/orchestrator/ and agents/_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 prompt 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.