agent-patterns

staged-prompt-separation

flowchart TD
    SystemFile[system.md - role guardrails format] --> Cache[Prompt cache]
    UserFile[user.md - placeholders] --> Resolver[Placeholder resolver]
    RuntimeData([Runtime data - diff issue feedback]) --> Resolver
    Resolver --> UserPrompt[Resolved user prompt]
    Cache --> LLM[LLM call]
    UserPrompt --> LLM
    LLM --> Output([Agent output])

Each pipeline stage stores its prompt in two files: a system file containing the invariant context (role, guardrails, output format) and a user file containing dynamic placeholders resolved at runtime. The system prompt is cached by the LLM provider; only the user prompt varies per call.

How it works

  1. The system file (*-system.md) defines what the agent is and what it must never do. It changes only when behavior changes — not on every call.
  2. The user file (*-user.md) contains `` tokens resolved at runtime from the current call’s data (issue body, PR diff, review feedback).
  3. The system prompt is sent with cache_control: ephemeral (Anthropic) or equivalent. Subsequent calls with the same system prompt hit the cache — input tokens are not re-billed.
  4. Changing guardrails or output format requires editing only the system file, with no code change.

Where it came from

When to use

When not to use

Trade-offs

   
Pro System prompt cache hits eliminate re-billing of invariant tokens on repeated calls
Pro Guardrails and output format are editable without a code deploy
Pro System and user concerns are independently versioned and diffable
Con Two files per stage doubles the prompt artifact count
Con Placeholder resolution adds a runtime step; unresolved placeholders silently reach the LLM
Con Cache invalidation is opaque — providers cache on exact token match; even whitespace changes bust the cache

Failure modes

Implementation reference

autonomous-dev-loop: