After this guide, your chief of staff can write each routine as a numbered procedure with named files, sub-agents, and postconditions; move date math, queries, and file gathering into a prep script; and mark freshness steps as unconditional with the rationalisation to resist named.

Commands, Not Prompts

Claude Code lets you define slash commands: Markdown files in .claude/commands/ whose content becomes the instructions when you type /name. The chief of staff runs on a deliberately small set. Each is a written procedure — numbered steps, named files and sub-agents, stated postconditions — versioned in git like everything else. None is clever prompting; each encodes hard-won process.

The Core Set

/daily-brief — the flagship. Pull the channel first, unconditionally; run the prep script; fan out to curators in parallel; synthesise; measure; deliver; archive; commit. See The daily brief.

/inbox-triage — drain the inbox in two phases: the chief of staff handles dispositions and hand-offs that need its authority; the inbox triager handles free-form captures. Every capture ends as a task, a note, or a question. See Capture everything, organise nothing.

/sync-<channel> — pull inbound on demand, transcribe voice, return structured items. The scheduled dispatcher runs the same pull every ten minutes as the real safety net; the command is for a session that wants it now.

/route-<channel> — the headless routing session the dispatcher launches: sweep unprocessed inbound, route each to an outcome, send the receipt, mark processed. Also invocable by hand.

/cos-work — the execution lane worker: one system-owned task, to completion, delivered, closed, receipted. See The execution lane.

Two or three more exist for narrow recurring writes (a travel form; a report skill). That is the whole set, and every addition needed a felt limitation first.

The Design Rule: Spend the Model Only on Judgment

Push everything deterministic down into scripts. The daily brief’s prep script gathers the git log since the last brief, the open-task queries, the aging delegations, the due-date radar, and the exact lookback window — all as a text blob the model reads. Date math, git queries, and file gathering never belong in a prompt: a model doing arithmetic on dates is slower, costlier, and occasionally wrong in ways that are hard to see.

The same rule shaped the channel coordinator: its pull step existed as a shell script (correct, cheap, run by the scheduler) and as a version the agent re-derived from scratch every manual invocation — reading the entire history file into context each time. The duplicate was retired; the script became the canonical implementation and the agent invokes it. When you find an agent re-implementing something a script already does, that is the smell.

Derive Time Windows from Artifacts, Not Constants

“Since the last brief” beats “last 24 hours” every time the cadence slips. The prep script computes the lookback from the previous brief’s modification time, with a thirty-minute overlap to absorb jitter, and every curator receives it explicitly. A skipped day never loses a message; a curator invoked cold with no window falls back to a sane default and says so.

Mark Freshness-Critical Steps as Unconditional

Models rationalise skipping steps that look redundant: “I already pulled the channel twenty minutes ago.” The brief command says, in the file, that the pull always runs, and names the rationalisation to resist. The sentence is there because the step was skipped exactly once, and the brief asserted “no inbound” while an unprocessed message sat in the log. If a step certifies freshness, say it always runs.

Assert Completeness, Don’t Assume It

Any tool in a procedure that paginates or caps needs its completeness asserted — pass the unlimited flag explicitly, or compare the returned count against ground truth. Every task query in the daily brief was silently capped at fifty rows for the life of the routine; the due-date radar was reading a tenth of the graph. The fix was one flag and one check. See Paginate to exhaustion.

Postconditions Make a Command Finishable

Each command ends with what must be true before it counts as done: the brief archived at a named path, the commit made, the receipt sent, the task closed, the inbox empty. Without postconditions, “done” is a feeling; with them, it is a checklist the session can verify — and a receipt can cite.

Let Commands Evolve through the Feedback Loop

When a run goes wrong, the fix usually lands in the command file itself: one commit, visible in history. The review surface has a feedback box per command that drops a note into the inbox. Over months the command files become the most refined prose in the system, because every sentence in them was paid for.

Start with One

Build /daily-brief first — crude, no curators, vault plus tasks. Everything else grows out of noticing what the brief is missing.

#commands · #routines · #scripts · #claude-code

Hand this to your chief of staff. Plain Markdown: /guides/commands-are-procedures.md. Tell it: "Read this guide and tell me what in our system it would change."