# CharacterGarden — Iterative Implementation Plan ## Copilot Operating Rules Work in small, reviewable steps. After every completed step: 1. Update `thoughts.md` 2. Record files changed 3. Record assumptions made 4. Record next step 5. Do not skip ahead unless the current step is complete Do not redesign the project without updating this plan. --- # Phase 1 — Contracts First ## Step 1.1 — Create contracts folder Create: ```txt app/src/contracts/ ``` Add: ```txt app/src/contracts/action.ts app/src/contracts/turn.ts app/src/contracts/validation.ts app/src/contracts/world.ts app/src/contracts/entity.ts ``` Goal: all shared types live here. --- ## Step 1.2 — Define Action contract In `action.ts`: ```ts export type Action = { actorId: string; type: string; targetId?: string; locationId?: string; metadata?: Record; }; ``` No other action shape should be used. --- ## Step 1.3 — Define ValidationResult contract In `validation.ts`: ```ts export type ValidationResult = { actionIndex: number; success: boolean; reason?: string; message?: string; }; ``` --- ## Step 1.4 — Define Turn contract In `turn.ts`: ```ts import type { Action } from "./action"; import type { ValidationResult } from "./validation"; export type Turn = { id: string; rawText: string; actions: Action[]; validation: ValidationResult[]; createdAt: number; }; ``` --- ## Step 1.5 — Define Entity contract In `entity.ts`: ```ts export type Entity = { id: string; name: string; type: string; attributes: Record; }; ``` --- ## Step 1.6 — Define WorldState contract In `world.ts`: ```ts import type { Entity } from "./entity"; export type WorldState = { id: string; entities: Record; metadata: Record; createdAt: number; }; ``` --- # Phase 2 — Enforce Layer Boundaries ## Step 2.1 — Refactor truth engine imports Update `truthEngine.ts` so it imports: ```ts import type { Action } from "./contracts/action"; import type { ValidationResult } from "./contracts/validation"; import type { WorldState } from "./contracts/world"; ``` Truth engine must only receive structured actions. --- ## Step 2.2 — Remove text parsing from truth engine Search `truthEngine.ts` for: * string parsing * natural language interpretation * prompt logic * LLM calls Move any such logic out. Truth engine should expose: ```ts export function validateActions( actions: Action[], worldState: WorldState ): ValidationResult[] { // deterministic validation only } ``` --- ## Step 2.3 — Create parser layer Create: ```txt app/src/parser/ app/src/parser/parseTextToActions.ts ``` Function: ```ts import type { Action } from "../contracts/action"; export function parseTextToActions(text: string): Action[] { // temporary simple parser return []; } ``` For now, returning `[]` is acceptable. --- ## Step 2.4 — Create world state engine Create: ```txt app/src/world/ app/src/world/applyActions.ts ``` Function: ```ts import type { Action } from "../contracts/action"; import type { ValidationResult } from "../contracts/validation"; import type { WorldState } from "../contracts/world"; export function applyActions( actions: Action[], results: ValidationResult[], worldState: WorldState ): WorldState { // apply only successful actions return worldState; } ``` --- # Phase 3 — Build First Deterministic Test Domain Use a simple door/key room before anything complex. ## Step 3.1 — Seed initial world Create initial world state: * actor: `player` * room: `room_start` * door: `door_1` * key: `key_1` Door starts locked. Key starts in room. Player starts in room. --- ## Step 3.2 — Support action types Truth engine should recognize: ```txt inspect take open move ``` Unknown action types fail with: ```txt reason: "unknown_action" ``` --- ## Step 3.3 — Validate take action Rules: * Actor must exist * Target must exist * Target must be in same location * Target must be takeable Failure reasons: * `actor_not_found` * `target_not_found` * `not_in_same_location` * `not_takeable` --- ## Step 3.4 — Validate open action Rules: * Actor must exist * Target must exist * Target must be openable * If locked, actor must have matching key Failure reasons: * `actor_not_found` * `target_not_found` * `not_openable` * `locked_requires_key` --- ## Step 3.5 — Apply successful take If `take` succeeds: * move item into actor inventory --- ## Step 3.6 — Apply successful open If `open` succeeds: * set door attribute `open: true` --- # Phase 4 — Wire Full Turn Processing ## Step 4.1 — Create turn processor Create: ```txt app/src/turns/processTurn.ts ``` Function: ```ts export async function processTurn(rawText: string): Promise { // parse // validate // apply // persist // return turn } ``` --- ## Step 4.2 — Enforce pipeline order The turn processor must call: ```txt parseTextToActions validateActions applyActions persistTurn ``` In that order. No layer may skip ahead. --- ## Step 4.3 — Add debug response API should return: ```ts { rawText, actions, validation, worldState } ``` This is for MVP debugging. --- # Phase 5 — Persistence ## Step 5.1 — Add database tables Minimum SQLite tables: ```sql turns actions validation_results entities world_states ``` --- ## Step 5.2 — Persist every turn Each call to `processTurn` must save: * raw text * parsed actions * validation results * resulting world state snapshot --- ## Step 5.3 — Add reset endpoint Add an endpoint to reset world state to seed state. This is needed for testing. --- # Phase 6 — LLM Adapter Reintroduction Only after deterministic flow works. ## Step 6.1 — LLM parser adapter Add optional LLM parser: ```ts parseTextToActionsWithLLM(text: string, worldState: WorldState): Promise ``` It must output only valid `Action[]`. --- ## Step 6.2 — LLM narrative adapter Add: ```ts generateNarrative(turn: Turn, worldState: WorldState): Promise ``` The narrative adapter may describe results but must not alter them. --- # Phase 7 — Frontend Debug UI ## Step 7.1 — Show raw text input User can submit a turn. --- ## Step 7.2 — Show parsed actions Display action JSON. --- ## Step 7.3 — Show validation results Display success/failure reasons. --- ## Step 7.4 — Show world state Display current world state JSON. --- # MVP Completion Criteria MVP is complete when this works: 1. User enters: `take key` 2. Parser returns a `take` action 3. Truth engine validates it 4. World state moves key to inventory 5. User enters: `open door` 6. Truth engine verifies key ownership 7. Door becomes open 8. All steps are visible in debug UI 9. All turns are persisted --- # Do Not Do Yet Do not implement: * autonomous agents * complex memory retrieval * embeddings * relationship simulation * long-term summaries * branching timelines Until the deterministic MVP is working.