Edit without fear
Every fragment knows which prompts use it. See the blast radius of a change before it ships — not in an incident review.
System prompts end up as string spaghetti scattered through your codebase — nobody knows what’s shared, what’s safe to change, or what the model actually receives. promptbook turns them into a folder of small plain files you can see: Storybook for prompts, with an Obsidian-style graph.
$ npx skills add markbrutx/promptbook
Prompt logic hides in template literals: conditionals buried in strings, copies drifting across files, no way to tell which variants exist. A book makes the same logic visible — as data, not code.
const system = `You are a support assistant for ${brand}. Be concise.${ tone === "terse" ? TERSE_RULES : WARM_RULES }${locale === "de" ? DE_RULES : ""}`; // three sprints later, in another file… const escalation = SYSTEM_V2 .replace("{persona}", persona) + formatFor(model);
Which variants exist? What changed last sprint? What does the model actually receive? grep and pray.
prompts/ ├─ fragments/ │ ├─ persona.md │ ├─ reply-tone-warm.md │ ├─ reply-tone-terse.md │ └─ guardrails.md └─ rules/ └─ reply.yaml # the whole decision, one rule: - when: { tone: terse } replace: { reply-tone-warm: reply-tone-terse }
Same logic, as files. Every variant browsable, every edit's blast radius visible before it ships.
Plain files in, one pure function out. The engine never calls a model — the only stochastic step stays in your code, behind an adapter.
Fragments are Markdown, rules are YAML — data, not code. They diff, review and version like everything else in your repo. One command scaffolds it: npx @markbrutx/promptbook-cli init.
--- id: persona --- You are a support assistant for ${brand}. Warm, precise, never invents order data.
base: [persona, reply-tone-warm, guardrails, reply-task, locale] rules: - when: { tone: terse } replace: { reply-tone-warm: reply-tone-terse }
promptbook view is Storybook for your prompts: browse every assembled variant, flip a context axis, watch it re-assemble — or zoom out to the graph.
Same folder + same context → byte-identical prompt, in Node, edge or browser. The trace explains every decision.
import { resolve } from "@markbrutx/promptbook-core"; const { text, trace } = await resolve({ promptsDir: "./prompts", prompt: "reply", context: { tone: "terse", model: "claude" }, }); // text → the exact prompt, every time // trace → which rules fired, and why
Every fragment knows which prompts use it. See the blast radius of a change before it ships — not in an incident review.
One skills command teaches your coding agent to read, edit and migrate prompt books without breaking them.
Plain files diff cleanly in PRs. Lint flags dead fragments, eval pins fixtures — prompt changes get code-grade review.
Which fragments are shared, what is safe to change, and what the final prompt looks like under a given context — all answerable without a single model call.
Every fragment knows which compositions include it. Touch persona and all ten places it lands light up — the blast radius is on screen, not in an incident.
Every composition, every variant, live. Flip a context axis and watch the prompt re-assemble, segments colored by the fragment they came from.
resolve() is pure: same folder + context → byte-identical output. The trace shows which rules fired and why, what got replaced, what forbid removed.
The target model is just another context axis. One logical prompt compiles to a JSON contract for one model and XML tags for another — no forked copies.
- when: { model: gpt } replace: { format-prose: format-json } - when: { model: claude } replace: { format-prose: format-xml }
CSS for prompts: rules apply in declaration order, later wins, forbid is the final filter. You can compute the outcome in your head — no solver to appease.
One command teaches your agent to write fragments and rules safely. The CLI gives CI the same verbs — lint dead fragments, gate bundles, eval fixtures.
No. Three plain file kinds — Markdown fragments, YAML rules, JSON fixtures — plus one pure function. No orchestration, no chains, no lock-in: delete promptbook tomorrow and your prompts are still readable Markdown.
Never. The engine is deterministic glue — resolve() just assembles a string. The model call stays in your code, behind whatever client you already use.
All of them. The target model is just a context value, so one logical prompt can resolve to a different format per model — JSON for one, XML for another — without forking the text.
That’s the expected starting point. The skill bundle includes a migrate skill: your coding agent moves string literals into a book incrementally, one prompt at a time.
The full sports-broadcast book — 10 compositions, 30 fragments, six context axes — running entirely in your browser. No install, no model calls.