prompt-architecturelisted
Install: claude install-skill nikzlabs/shipit
# Prompt architecture
LLM prompts — agent system instructions, voice cleanup, session naming — are **content, not logic**. Keep the two separated.
## Prompt *text* is data: it lives in `.md` files
Co-locate the `.md` with the code that composes it. Prose reviews as prose, diffs cleanly, and needs no backtick or `${}` escaping.
Load it with `loadPrompt(import.meta.url, "./x.md")` (`orchestrator/load-prompt.ts`), **at module top level** — once at init, never per call. A missing file then throws at boot rather than mid-turn.
**Not** a bundler `?raw` import: production runs TS via tsx with no bundler, so `fs.readFileSync(new URL(...))` is what actually works.
Examples: `agents/<id>/system-prompt.md`, `voice/cleanup-prompt.md`, `orchestrator/prompts/*.md`.
**Known exception:** `session-namer.ts` still defines its `PROMPT_TEMPLATE` inline in TypeScript and substitutes per call. It predates this convention and is not a model to copy — if you touch it, move the text to an `.md` rather than extending the inline template.
## Prompt *composition* is code
Axis branching and fragment selection stay in TypeScript. In `agent-instructions.ts`, `renderInstructions` fills `{{TOKEN}}` holes in `prompts/skeleton.md` via `fillPromptTokens`, which **throws on an unfilled token** — that's the guard ensuring no literal `{{FOO}}` ever reaches the model.
There are **two axes**: `agentId` (Parallel-sessions wording) and the session **mode**, which has **three** values — `std`, `ops` (docs/128