From 211b59e28f608de3a8740ded1ac8ca94f8301e18 Mon Sep 17 00:00:00 2001 From: Chris Guidry Date: Wed, 29 Jul 2026 19:21:45 -0400 Subject: [PATCH] Start the plans system and the reboot roadmap The reboot is a solo 5e RPG in Rust, one binary, with the agent loop in-process against an OpenAI-compatible API. plans/ holds in-flight design docs, plans/completed/ holds shipped ones, and plans/rejected/ holds the ones we walked away from. 0001 lays out the ground rules (playable at every phase, the context stack gets the most care, plain files, per-tool smartness decisions) and stubs the phases at low fidelity on purpose: each phase gets its real plan when we start it. Co-Authored-By: Claude Fable 5 --- plans/0001-roadmap.md | 76 ++++++++++++++++++++++++++++++++++++++++ plans/README.md | 44 +++++++++++++++++++++++ plans/completed/.gitkeep | 0 plans/rejected/.gitkeep | 0 4 files changed, 120 insertions(+) create mode 100644 plans/0001-roadmap.md create mode 100644 plans/README.md create mode 100644 plans/completed/.gitkeep create mode 100644 plans/rejected/.gitkeep diff --git a/plans/0001-roadmap.md b/plans/0001-roadmap.md new file mode 100644 index 0000000..348976f --- /dev/null +++ b/plans/0001-roadmap.md @@ -0,0 +1,76 @@ +# 0001: The reboot roadmap + +## What we're building + +Storied is a solo 5e RPG that lives in your terminal. You type what you do. +An LLM plays the DM: it narrates, runs the rules, and keeps the world alive +between sessions. The world persists as plain files you can read and edit +yourself. + +This time it's Rust, one binary, with the agent loop running in-process +against an OpenAI-compatible API. Any compatible endpoint works; the model +and provider are configuration, and DeepInfra is the likely first home. + +## What happened to the first one + +The first version was Python driving Claude Code as a subprocess, with tools +served over MCP. It worked, and it taught us a lot. It's archived on the +`python-and-claude` branch as inspiration. Nothing there is sacred; ideas +from it have to earn their way into the reboot. + +## Ground rules for the design + +- **Playable at every phase.** Each phase ends with something you can run + and feel. If a phase can't demo, it's cut wrong. +- **The context stack gets the most care.** The DM's knowledge comes in + layers: SRD rules, then world knowledge, then player knowledge. Building + each turn's context from those layers is the heart of the design. Some of + it gets pushed into every turn, and the long tail gets pulled through + lookup tools. What exactly goes where is the most important design work + ahead of us. +- **Plain files.** Worlds, characters, and history are markdown with + frontmatter. You can read your world with `cat` and edit it with `vim`. + Anything derived, like a search index, can be rebuilt from the files. +- **The DM owns the rules.** Tools are there for bookkeeping and state, not + to be a 5e engine. But how smart any single tool gets is a per-tool + conversation during its phase. Open models may want more mechanical help + than Claude did, and we'd rather discover that than legislate it now. +- **Organized by domain.** Modules are named for what they mean to the game + (rules, world, player), not what kind of code they are. Nothing gets + named `common`, `utils`, or `helpers`. + +## The phases + +Each phase gets its own plan when we're about to start it, and that's when +the real design happens. The blurbs here stay deliberately loose. + +- [ ] **Phase 0: Scaffolding.** A Rust project that builds a single binary + with formatting, linting, and tests wired up. *You can now: run `storied` + and get a hello.* +- [ ] **Phase 1: SRD download and prep.** A subcommand that fetches the 5e + SRD 5.2.1, extracts it, and splits it into per-section markdown with + frontmatter. A batch job with files in and files out, which makes it a + gentle Rust warm-up. *You can now: read Fireball from a file the binary + produced.* +- [ ] **Phase 2: Talk to a model.** A client for the chat API with + streaming, and a bare `storied play` that streams a DM-flavored reply. + No tools, no persistence. *You can now: have a conversation with a DM in + your terminal.* +- [ ] **Phase 3: Tool calls.** The loop grows in-process tools, starting + small with dice and SRD lookup. This phase settles how a tool declares + itself and how results flow back through the loop. *You can now: watch + the DM roll dice and quote real rules.* +- [ ] **Phase 4: The context stack.** Rules, world, and player knowledge + layered into each turn. The push/pull split gets decided here: what the + DM always sees versus what it looks up. *You can now: watch the DM + remember the world from turn to turn.* +- [ ] **Phase 5: Persistence.** Worlds and players as files on disk. + Character sheet, campaign log, session state. *You can now: quit, come + back tomorrow, and pick up where you left off.* +- [ ] **Phase 6 and beyond: ideas that have to earn it.** Character + creation, combat and initiative, background world motion, advancement, + name generation. Each one starts as a conversation, not a commitment. + +Phases 4 and 5 might swap or blur together; building context on in-memory +state first seemed simpler, but if it feels backwards when we get there, +we'll flip them. The roadmap is a map, not a contract. diff --git a/plans/README.md b/plans/README.md new file mode 100644 index 0000000..280a3b3 --- /dev/null +++ b/plans/README.md @@ -0,0 +1,44 @@ +# Plans + +This directory is our design notebook, our planning system, and our decision +record, all in one. If you want to know why Storied is the way it is, read +these files in order. + +## How a plan lives + +A plan is born as `NNNN-slug.md` right here. While it lives here, it is in +flight: a living document we edit freely as we build and learn. + +- `plans/*.md` is what we are working on or about to work on. +- `plans/completed/` is where a plan goes when the work ships. It moves + unchanged. From that moment it is a record of what we decided and why. +- `plans/rejected/` is where a plan goes when we bail on it. It gets a short + note at the top saying why. Rejected plans are some of the most useful + files in a repo, so we keep every one. + +Numbers never get reused, and a plan keeps its number when it moves. That +way "see 0003" always means the same thing. + +## How we work together + +- **Design first.** We talk an idea through before any code exists. The plan + gets written, Chris signs off, then we build. +- **Small pieces.** We build in phases, and every phase ends with something + you can actually run. No months-long foundation digs. +- **Stub the future lightly.** A phase we have not started yet gets a + paragraph, not a spec. We write the real plan when we are about to build + it, so the design happens with fresh eyes and real experience from the + phases before it. +- **Pick tools at the last minute.** No plan names a library, crate, or + dependency until the phase that needs it is being designed. Committing + early is how you end up serving your tools instead of the other way + around. +- **Chris steers the experience.** How the game feels at the terminal is the + whole point, so UX decisions get made together, in small steps, not + delivered in bulk at the end. + +## How to write one + +Write plans like you are explaining an idea to a friend at the table, not +like you are presenting at an architecture review. Short, plain, and fun to +read. If a plan starts sounding like an RFC, rewrite it until it doesn't. diff --git a/plans/completed/.gitkeep b/plans/completed/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/plans/rejected/.gitkeep b/plans/rejected/.gitkeep new file mode 100644 index 0000000..e69de29 -- 2.51.2