Cypher System (CSRD) Migration Plan
Background
The app migrated from D&D 5e to the Cypher System Reference Document (CSRD) — Monte Cook Games' open ruleset used in Numenera, The Strange, and others. The migration is complete. SAVE_VERSION is currently 3.
Every phase that changes gameState shape must increment SAVE_VERSION in public/index.html. Old saves are automatically offered for export and discarded.
Source material
All content is available under the Cypher System Open License (CSOL) — free for digital use.
| Source | URL | Used for |
|---|---|---|
| Cypher-System-JSON-DB | github.com/Jon-Davis/Cypher-System-JSON-DB | Data arrays — types (with pool values), descriptors, foci, abilities, cyphers. 1.74 MB JSON; too large to bundle directly, so we extract just the fields we need into compact inline JS arrays during development. |
| cyphersrd.quest | cyphersrd.quest | System prompt — authoritative rules text for task resolution, damage track, effort, GM intrusions, advancement. We write a tight summary (~800 tokens) from this. |
| Obsidian CSRD Markdown | github.com/Obsidian-TTRPG-Community/Cypher-SRD-Markdown | Cross-reference during development. |
Workflow for data extraction: download CSRD.json from JSON-DB, run a small local script to pull the specific fields needed (type name + starting pools + cypher limit + starting abilities summary; descriptor name + stat bonus; focus name + one-line summary + tier 1 ability), and paste the result as inline JS arrays in index.html. No build step needed.
Phase 1 — Character foundation
The biggest structural change. D&D's Race + Class becomes Cypher's Descriptor + Type + Focus sentence: "I am a Clever Adept who Talks to Machines."
1a — Data definitions
- [x] Replace
RACESarray withDESCRIPTORS(34 entries, each with pool bonus and starting skills) - [x] Replace
CLASSESarray withTYPES(4 entries: Warrior, Adept, Explorer, Speaker — each with starting pools, Cypher Limit, starting abilities, and starting skills) - [x] Add
FOCIarray (69 entries, each with settings tags, playstyle description, and Tier 1 ability)
1b — New gameState.character shape
Replace current { name, race, class, level, hp, maxHp, xp, gold, inventory } with:
{
name, descriptor, type, focus,
tier, // 1–6
effort, // = tier
might: { pool, max, edge },
speed: { pool, max, edge },
intellect: { pool, max, edge },
xp,
damageTrack, // 'hale' | 'impaired' | 'debilitated'
recoveryUsed, // 0–4, resets each full rest
cypherLimit, // from type (usually 2)
cyphers, // [{ name, level, effect }]
skills, // [{ name, rank: 'trained'|'specialized'|'inability' }]
abilities, // [{ name, cost, description }] — from type + focus
equipment, // string[] (replaces inventory)
shins, // currency (or 'gold' for generic settings)
}
- [x] Update
beginAdventure()to build this shape from Type + Descriptor + Focus selections - [x] Bump
SAVE_VERSIONto 2
1c — Creation screen
- [x] Replace two-grid layout (Race + Class) with three-grid layout (Descriptor + Type + Focus)
- [x] The sentence "I am a
______who___" assembles live as user picks each - [x] Type cards show starting pool values and Cypher Limit, not HP
- [x] Focus cards show a one-line flavour summary
- [x] Descriptor cards show the key stat bonus it provides
1d — Header title format
- [x] Update
header-titlefrom"Name — Race Class"to"Name — Descriptor Type who Focus"
Phase 2 — Core mechanics
2a — New UPDATE_TOOL schema
Replace current fields entirely:
might_damage // number — damage to Might pool
speed_damage // number — damage to Speed pool
intellect_damage // number — damage to Intellect pool
might_restore // number — points restored to Might pool
speed_restore // number — points restored to Speed pool
intellect_restore // number — points restored to Intellect pool
xp_gain // number
shins_change // number
cyphers_add // [{ name, level, effect }]
cyphers_remove // string[] — names of used/lost cyphers
abilities_add // [{ name, cost, description }]
equipment_add // string[]
equipment_remove // string[]
skills_add // [{ name, rank }]
tier_advance // boolean
recovery_used // boolean — mark one recovery slot as spent
reason // string
2b — New applyStatUpdate() logic
- [x] Apply pool damage/restore, clamping to 0 and max
- [x] Recalculate
damageTrackafter every pool change: - Hale → one pool at 0 → Impaired (−1 step to all rolls)
- Impaired → two pools at 0 → Debilitated (can barely act)
- Debilitated → all pools at 0 → Dead (end screen)
- [x] Enforce Cypher Limit: if
cyphers.length > cypherLimit, warn player to use one - [x] Handle
tier_advance: incrementtier, recalculateeffort = tier, show tier-up fanfare - [x] Handle
recovery_used: incrementrecoveryUsed(max 4; fourth resets all and marks 10-hour rest taken) - [x] Replace level-up toast with Tier-up toast (text: "TIER [N]!")
2c — System prompt rewrite ✅
Complete replacement of buildSystemPrompt. Claude needs to understand:
- Character sentence — what Descriptor, Type, and Focus each contribute
- Task difficulty — 0–10 scale; target = difficulty × 3; player rolls d20
- Special roll results — 1 = GM intrusion (free); 17 = minor effect; 18 = minor effect; 19 = major effect or +1 damage; 20 = major effect
- Effort — costs 3 from a pool per level (minus Edge); reduces difficulty by 1 per level applied
- Assets — each relevant asset reduces difficulty by 1 (max 2 from assets)
- Skills — trained = −1 difficulty; specialized = −2 difficulty; inability = +1 difficulty
- Damage track — Impaired penalty (−1 step = difficulty +1 to all rolls); Debilitated behavior
- GM Intrusions — Claude should offer them occasionally; player accepts (gains 2 XP, gives 1 away) or rejects (spends 1 XP); if player has no XP they must accept
- Recovery rolls — 1d6 + Tier; progression: 1 action → 10 min → 1 hour → 10 hours; after four the character must sleep to reset
- Cyphers — found during play; Claude should introduce them narratively; remind player when at Cypher Limit; one-use
- XP flow — earned via intrusions and discoveries; spent on advancement (4 per step) or short-term benefits (1 each: reroll, refuse intrusion, add +2 to any roll)
- Advancement steps (any 4 to advance a tier): increase pool max by 4; add +1 Edge to a stat; train a skill; other improvement
- Stat tracking — call
update_characterbefore narrative text, same as current
Phase 3 — Sidebar UI redesign
3a — Three pool bars
- [x] Replace HP bar with three bars: Might, Speed, Intellect
- [x] Each bar shows
current / maxandEdge: N - [x] Bar colour shifts: green (full) → amber (half) → red (low) — same as current HP logic
- [x] Damage Track indicator below the bars: coloured badge — green "Hale" / amber "Impaired" / red "Debilitated"
3b — XP & advancement panel
- [x] Replace XP progress bar (which tracked D&D level thresholds) with a plain XP counter
- [x] Tier shown as Roman numeral next to XP
- [x] Show advancement progress: 4 dot pips below XP/Tier row
- [x] "Spend 4 XP" button — disabled when XP < 4 or Tier 6; opens advancement modal (see Phase 5c); four steps advances the Tier and resets dots
3c — Cyphers panel
- [x] New sidebar section "Cyphers" (replaces or extends Inventory)
- [x] Each cypher shows name, level, effect summary
- [x] "Use" button per cypher — removes it and sends activation message to Claude
- [x] Cypher Limit displayed; section border turns orange when at limit
- [x] Equipment (non-cypher items) stays as a separate Inventory list
3d — Recovery roll button
- [x] Recovery section showing 4 slot pips (empty → filled as used)
- [x] "Recovery Roll (1d6 + Tier)" button — rolls and adds to most depleted pool
- [x] Marks one slot used per roll; when all 4 used button becomes "Full rest (reset slots)"
- [x] Clicking reset button clears all slots
Phase 4 — Setting / genre selector ✅
Cypher System is genre-neutral. Offer a setting choice at creation that adjusts tone, vocabulary, and available Foci.
- [x] Setting selector on creation screen: Fantasy / Numenera / Modern / Sci-Fi
- [x] Each setting customises: currency name, special abilities vocabulary, DM tone paragraph
- [x] System prompt includes setting context; currency label shown in sidebar
- [ ] Curated subset of Foci per setting (deferred — all foci remain available for now)
Phase 5 — Skill system ✅
The skills array in gameState.character is fully implemented: populated from Type and Descriptor starting skills, displayed in the sidebar with rank badges, managed via the advancement modal, and passed to Claude in the system prompt.
5a — Display
- [x] New "Skills" section in the sidebar (between Abilities and Equipment)
- [x] Each skill shows name + rank badge: green "Trained" / gold "Specialized" / red "Inability"
- [x] Empty state: "No skills yet"
5b — Type and Descriptor starting skills
Several Type Tier 1 abilities grant skill training ("Physical Skills", "Interaction Skills", "Danger Sense", etc.) but currently these are stored as narrative text in abilities, not as actual entries in skills. Fix by:
- [x] Add a
startingSkillsfield to each Type (parallel tostartingAbilities) - [x] Add
startingSkillsfield to each Descriptor for their trained skills - [x] Populate
character.skillsfrom both inbeginAdventure()— overlapping trained skills promote to specialized
5c — Skill advancement
The XP advancement path ("train a skill") is currently only narrated. To make it mechanical:
- [x] Add a "Train a Skill" option to the Spend 4 XP flow — prompts for skill name, adds it as trained
- [x] Allow upgrading trained → specialized for another advancement step
- [x] Specialization cap at 2 levels; inability cannot be trained away (only reduced to trained via advancement)
- [x] Full advancement modal: pool +4, edge +1, train skill, specialize skill, other improvement
5d — Skill lookup in task resolution
When a player's message mentions an action, Claude already references skills in its narration. Future enhancement:
- [x] Pass
character.skillsin the system prompt so Claude can cite which skills apply to a given roll - [ ] Expose "I am trained in X" as a quick action or structured input so the player can assert relevant skills before rolling
Notes
- Phases 1–2 land together (one
SAVE_VERSIONbump to 2) — they're too intertwined to separate safely - Phase 3 can ship independently after Phase 2 (UI only, no
gameStateshape change) - Phase 4 is cosmetic and can go in any order
- Phase 5a/5b/5d landed together with
SAVE_VERSIONbump to 3 - The CSRD is available at cyphersrd.quest for rules reference