Red Rabbit
Production OS
A canonical source of truth for an alternate-history espionage franchise — screenplay extraction, relationship mapping, writer management, and a web CMS, with every canon mutation flowing through a reviewable PR.
§ 01Mission
A creator builds the Red Rabbit universe. An infrastructure engineer builds the production OS that lets them do it without ever touching a terminal, a JSON file, or a schema definition. Constitution Principle II is load-bearing: creative users live behind a writer-friendly surface; engineering ugliness stays on the engineering side of the boundary.
The system is opinionated about how canon evolves: AI proposes, humans dispose. Every mutation — a new character, an edited story arc, a role grant — opens a pull request against the canon repo. Merges are explicit. Rollback is a single revert.
Canon is the source of truth
Every agent and product derives from a single, versioned canon. Deprecated ideas are archived, not deleted.
Writer UX is non-negotiable
Zero terminal, zero JSON, zero schema. Engineering ugliness lives behind a writer-friendly surface.
Grounded realism over confident recall
Real-world claims must trace to a retrieval source. Ungrounded "training data advice" is a failure mode.
Human-in-the-loop on consequential acts
Major canon changes, access grants, outreach sends, and schedule commits all require explicit confirmation.
Ship lightest viable first
Commoditized backends (Drive, Obsidian, Claude Desktop) before custom code. Every spec must justify deviation.
§ 02Architecture
The system has two write surfaces and two MCP transports, all terminating in a single canon-core write engine. The architecture is symmetric on purpose: contract drift between advertisement and enforcement is impossible by construction.
flowchart TB
subgraph mike["Mike's Mac"]
desktop["Claude Desktop"]
stdio["stdio MCP server
packages/mcp-server"]
desktop -->|local Node| stdio
end
subgraph browser["Browser (Mike or Justin)"]
cms_form["CMS form harness
/canon/[type]/new + /edit
/admin/writers"]
end
subgraph vercel["Vercel — operation-red-rabbit-cms"]
cms_app["Next.js CMS
apps/cms"]
api_propose["/api/canon/propose-change
Pages Router"]
server_action["proposeChangeAction
Server Action"]
hosted_mcp["Hosted MCP
/api/mcp
OAuth + bearer"]
kv[("Upstash KV
roles · audit · rate-limit · sessions")]
cms_app -.-> api_propose
cms_app -.-> server_action
api_propose --> kv
hosted_mcp --> kv
end
subgraph engine["Canon engine — packages/"]
schema["@redrabbit/schema
zod + .describe()"]
canon_core["@redrabbit/canon-core
proposeChange + find_conflicts"]
mcp_server["@redrabbit/mcp-server
tools + RBAC + roles cache"]
indexer["@redrabbit/index
SQLite mirror"]
schema --> canon_core
schema --> mcp_server
canon_core --> mcp_server
end
subgraph github["GitHub"]
canon_repo[("operation_red_rabbit
canon/ + .mcp/roles.yml")]
gh_app["GitHub App
write credential"]
end
cms_form -->|HTTPS · cookie + CSRF| api_propose
cms_form -.->|RSC form action| server_action
desktop -.->|claude.ai web| hosted_mcp
stdio --> mcp_server
hosted_mcp --> mcp_server
api_propose --> canon_core
server_action --> canon_core
canon_core -->|Octokit + GH App| gh_app
gh_app -->|writes branch + PR| canon_repo
canon_repo -->|reads .md| canon_core
canon_repo -->|nightly index| indexer
indexer -.->|local lookups| mcp_server
classDef writer fill:#1e1a17,stroke:#c14a36,color:#f4ebd9
classDef cloud fill:#1c1815,stroke:#8a847a,color:#f4ebd9
classDef code fill:#1a1817,stroke:#d6cdb8,color:#f4ebd9
classDef store fill:#1a1614,stroke:#c14a36,color:#f4ebd9
class mike,browser writer
class vercel cloud
class engine code
class github store
Two write surfaces, one engine
Both /api/canon/propose-change (Pages Router, called from the form harness) and proposeChangeAction (App Router Server Action) compose the same proposeChange() in @redrabbit/canon-core. They differ in caller fit:
- Pages Router endpoint — adds explicit CSRF (double-submit cookie), per-request fresh
getRoles(), slug-collision pre-check, 9-secondAbortController-plumbed timeout cap, and audit logging. Used by client-direct callers. - Server Action — integrates with
revalidatePath()and theActionResult<T>envelope. Used by React Server Components.
Two MCP transports, one server package
The NEW_V1_1_ENTITY_TYPES Set in packages/mcp-server/src/tools/write.ts is the single source of truth for which entity types are blocked from chat-based writes. Both transports inherit; server_info advertises the same Set so the contract cannot drift from runtime enforcement.
Standing automation
Two always-on systems run without human intervention between canon edits and PR merge.
Structural conflict detection — every proposed canon change runs findStructuralConflicts() in @redrabbit/canon-core before the PR is openable. Six check categories:
missing_block— a scene references a block that does not exist in the repomissing_block_in_season/orphan_block/duplicate_block_membership— block↔season membership must be bijectiveevolution_chronology— character relationship timelines are checked for ordering; intentional flashback structure surfaces as a soft warning, not a hard blockblock_ordering_drift— each block'sordinalinteger must agree with its season'sblocks[]array order; drift is flagged before merge
Both the hosted MCP and the CMS Server Action invoke the same engine — what chat warns about and what the form warns about cannot diverge.
60-second canon pulse — a Vercel cron polls the canon repo's HEAD SHA every minute. On mismatch it increments a KV generation counter. All relationship-map clients key cache reads to mcp:relmap:g<N> — the moment a PR merges, the next cron tick invalidates the stale map and forces a fresh compute on the following request. Sub-90-second freshness with no webhook surface.
§ 03Pipeline
Specs land before code lands. The pipeline is six stages from intent to merged PR, with explicit review gates between each. Artifacts persist at docs/specs/<feature>/{spec,review,plan,check}.md.
flowchart LR spec["/spec
Q&A → spec.md"] --> review["/spec-review
6 PRD agents → review.md"] review --> plan["/plan
6 design agents → plan.md"] plan --> check["/check
5 plan reviewers → check.md"] check --> build["/build
parallel agents
wave-based execution"] build --> codereview["/code-review
5 Sonnet + Codex
→ PR comment"] classDef stage fill:#1e1a17,stroke:#c14a36,color:#f4ebd9 class spec,review,plan,check,build,codereview stage
§ 04Status
| Layer | State | Reference |
|---|---|---|
| Canon ontology v1.1 | Shipped | PRs #22 – #25 |
| MCP-on-Vercel — Phase A + B | Shipped | PRs #4 – #21 |
| Writer-management — Phase 1 | Shipped | PR #27 |
| Canon relationship map | Shipped | PR #33 |
| Episode / feature authoring | Shipped | PR #35 + main |
| Script extraction + MCP setup page | Shipped | main |
| Canon ontology v1.2 (required-flip) | Gated | ≥ 80 % authoring threshold |
§ 05IP boundary
The repository is a single tree with two ownership boundaries. Toolkit code is portable consultant IP; canon content is the creator's IP under all rights reserved.
Toolkit · MIT
Reusable infrastructure toolkit, with extract-to-separate-repo rights.
packages/apps/
Canon · All Rights Reserved
Creator's creative IP. Stays with the creator if the toolkit is ever extracted.
canon/inbox/tests/fixtures/cms-config.yml
§ 06Stack
operation_red_rabbit/
├── packages/ Toolkit (MIT)
│ ├── schema/ zod entity schemas + .describe() registry
│ ├── canon-core/ octokit-backed read/write + find_conflicts
│ ├── mcp-server/ MCP SDK transport + hosted-server.ts + KV cache
│ ├── index/ SQLite indexer + ALL_ENTITY_TYPES + edge classes
│ ├── extractor/ AI script-extraction (Anthropic-backed)
│ ├── fountain/ Fountain-format script parser
│ ├── actions/ GitHub Actions integrations
│ ├── pr-body/ PR humanizer (one title per entity type)
│ ├── demo/ Stub canon for tests + dev
│ └── testing/ Shared vitest helpers
├── apps/
│ ├── cms/ Next.js 14 — CMS + hosted MCP route
│ └── cli/ Local dev CLIs
├── canon/ Mike's IP — markdown one-file-per-entity
├── docs/specs/ Pipeline artifacts per feature
└── docs/runbooks/ Operational procedures
§ 07References
- Constitution v1.0 — five core principles
- Spec backlog — durable cross-spec carry-over
- CANON_OWNERSHIP.md — IP ownership, dispute resolution, recovery
- TOOLKIT_LICENSE.md — MIT terms + file-level classification
- CLAUDE.md — codebase + workflow conventions for Claude Code agents
- PR #27 — writer-management Phase 1 (live)