commit 14a07bca7a0fb270f9f187a572634d702e5c29aa Author: spencer Date: Thu Apr 23 17:19:55 2026 -0400 Initialize project structure with core files, environment settings, and basic configurations Co-authored-by: Copilot diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..6c878c3 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "chat.tools.terminal.autoApprove": { + "New-Item": true + } +} \ No newline at end of file diff --git a/charactergarden/.env b/charactergarden/.env new file mode 100644 index 0000000..f7fbd52 --- /dev/null +++ b/charactergarden/.env @@ -0,0 +1,8 @@ +NODE_ENV=development +APP_PORT=3000 +FRONTEND_PORT=5173 +DB_PATH=/data/sqlite/app.db + +# Optional — only needed when running with the llm profile +OLLAMA_URL=http://ollama:11434 +OLLAMA_MODEL=llama3 diff --git a/charactergarden/.env.example b/charactergarden/.env.example new file mode 100644 index 0000000..c82f97f --- /dev/null +++ b/charactergarden/.env.example @@ -0,0 +1,11 @@ +# Copy this file to .env and adjust values as needed. +# Never commit .env — it is gitignored. + +NODE_ENV=development +APP_PORT=3000 +FRONTEND_PORT=5173 +DB_PATH=/data/sqlite/app.db + +# Optional — only required when running with: docker compose --profile llm up +OLLAMA_URL=http://ollama:11434 +OLLAMA_MODEL=llama3 diff --git a/charactergarden/.gitignore b/charactergarden/.gitignore new file mode 100644 index 0000000..2475475 --- /dev/null +++ b/charactergarden/.gitignore @@ -0,0 +1,33 @@ +# ── Dependencies ──────────────────────────────────────────── +node_modules/ + +# ── TypeScript build output ────────────────────────────────── +app/dist/ +frontend/dist/ + +# ── Vite cache ─────────────────────────────────────────────── +frontend/.vite/ + +# ── SQLite database (keep the directory, not the data) ─────── +data/sqlite/*.db +data/sqlite/*.db-shm +data/sqlite/*.db-wal + +# ── Environment — commit .env.example, never .env ──────────── +.env +.env.local +.env.*.local + +# ── Docker volumes / build context artifacts ───────────────── +.docker/ + +# ── OS noise ───────────────────────────────────────────────── +.DS_Store +Thumbs.db +desktop.ini + +# ── Editor noise ───────────────────────────────────────────── +.vscode/settings.json +.idea/ +*.suo +*.user diff --git a/charactergarden/app/package.json b/charactergarden/app/package.json new file mode 100644 index 0000000..244e820 --- /dev/null +++ b/charactergarden/app/package.json @@ -0,0 +1,22 @@ +{ + "name": "charactergarden-app", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "ts-node-dev --respawn src/index.ts", + "build": "tsc", + "start": "node dist/index.js" + }, + "dependencies": { + "fastify": "^4.28.1", + "better-sqlite3": "^9.6.0", + "uuid": "^9.0.1" + }, + "devDependencies": { + "@types/better-sqlite3": "^7.6.11", + "@types/node": "^20.14.0", + "@types/uuid": "^9.0.8", + "ts-node-dev": "^2.0.0", + "typescript": "^5.4.5" + } +} diff --git a/charactergarden/app/src/types.ts b/charactergarden/app/src/types.ts new file mode 100644 index 0000000..365f7f6 --- /dev/null +++ b/charactergarden/app/src/types.ts @@ -0,0 +1,76 @@ +// Core contracts — DO NOT modify without updating project.md + +// ── Section 2.1 ───────────────────────────────────────────── +export interface Entity { + id: string; + type: string; + name: string; + attributes: Record; +} + +// ── Section 2.2 ───────────────────────────────────────────── +export const ALLOWED_VERBS = [ + "move", + "open", + "close", + "take", + "drop", + "use", + "inspect", + "speak", +] as const; + +export type Verb = (typeof ALLOWED_VERBS)[number]; + +export interface Action { + actor: string; // entity id + verb: Verb; + target?: string; // entity id + params?: Record; +} + +// ── Section 2.3 ───────────────────────────────────────────── +export interface ValidationResult { + accepted: Action[]; + rejected: { action: Action; reason: string }[]; + state_changes: StateChange[]; +} + +// ── Section 2.4 ───────────────────────────────────────────── +export interface StateChange { + entity_id: string; + field: string; + old_value: unknown; + new_value: unknown; +} + +// ── Section 2.5 ───────────────────────────────────────────── +export interface GameEvent { + id: string; + turn: number; + action: Action; + result: "success" | "fail"; + timestamp: number; +} + +// ── Section 4 — Memory types ───────────────────────────────── +export interface Turn { + id: string; + turn: number; + input: string; + output: string; + timestamp: number; +} + +export interface Belief { + entity_id: string; + claim: string; + confidence: number; +} + +export interface Summary { + id: string; + turn_range: [number, number]; + text: string; + timestamp: number; +} diff --git a/charactergarden/app/tsconfig.json b/charactergarden/app/tsconfig.json new file mode 100644 index 0000000..b4dc9bb --- /dev/null +++ b/charactergarden/app/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "commonjs", + "lib": ["ES2022"], + "outDir": "dist", + "rootDir": "src", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true + }, + "include": ["src"], + "exclude": ["node_modules", "dist"] +} diff --git a/charactergarden/data/sqlite/.gitkeep b/charactergarden/data/sqlite/.gitkeep new file mode 100644 index 0000000..77f0050 --- /dev/null +++ b/charactergarden/data/sqlite/.gitkeep @@ -0,0 +1 @@ +# sqlite data directory — tracked by git, contents ignored diff --git a/charactergarden/docker-compose.yml b/charactergarden/docker-compose.yml new file mode 100644 index 0000000..90c7df9 --- /dev/null +++ b/charactergarden/docker-compose.yml @@ -0,0 +1,34 @@ +version: "3.9" + +services: + app: + build: ./app + ports: + - "${APP_PORT:-3000}:3000" + environment: + - NODE_ENV=${NODE_ENV:-development} + - DB_PATH=/data/sqlite/app.db + - OLLAMA_URL=${OLLAMA_URL:-http://ollama:11434} + volumes: + - ./data:/data + depends_on: + - ollama + + frontend: + build: ./frontend + ports: + - "${FRONTEND_PORT:-5173}:5173" + depends_on: + - app + + ollama: + image: ollama/ollama:latest + ports: + - "11434:11434" + volumes: + - ollama_data:/root/.ollama + profiles: + - llm + +volumes: + ollama_data: diff --git a/charactergarden/frontend/package.json b/charactergarden/frontend/package.json new file mode 100644 index 0000000..8195d48 --- /dev/null +++ b/charactergarden/frontend/package.json @@ -0,0 +1,21 @@ +{ + "name": "charactergarden-frontend", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "devDependencies": { + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@vitejs/plugin-react": "^4.3.1", + "typescript": "^5.4.5", + "vite": "^5.3.1" + } +} diff --git a/project.md b/project.md new file mode 100644 index 0000000..28f3a57 --- /dev/null +++ b/project.md @@ -0,0 +1,367 @@ +# CharacterGarden – AI-Oriented Design Spec (Copilot-Ready) + +## 0. Purpose + +This document defines **hard contracts and system boundaries** for CharacterGarden. + +Goal: enable an AI coding assistant (e.g. Copilot) to implement the system step-by-step without ambiguity. + +Core principle: + +> The application owns truth. The LLM only translates and narrates. + +--- + +## 1. System Overview + +### Pipeline + +``` +Prose Input +→ Intent Extraction +→ Canonical Actions +→ Truth Engine Validation +→ State Changes + Events +→ Memory Storage +→ Narration Output +``` + +--- + +## 2. Core Contracts (STRICT) + +### 2.1 Entity + +``` +Entity { + id: string + type: string + name: string + attributes: object +} +``` + +### 2.2 Action (Canonical) + +``` +Action { + actor: string (entity id) + verb: string (enum) + target?: string (entity id) + params?: object +} +``` + +Allowed verbs (MVP): + +``` +move, open, close, take, drop, use, inspect, speak +``` + +### 2.3 Validation Result + +``` +ValidationResult { + accepted: Action[] + rejected: { action: Action, reason: string }[] + state_changes: StateChange[] +} +``` + +### 2.4 State Change + +``` +StateChange { + entity_id: string + field: string + old_value: any + new_value: any +} +``` + +### 2.5 Event + +``` +Event { + id: string + turn: number + action: Action + result: "success" | "fail" + timestamp: number +} +``` + +--- + +## 3. Truth Rules + +1. Only the **Truth Engine** can modify world state +2. LLM output is NEVER directly trusted +3. Every state change must be traceable to an Event +4. Invalid actions must return explicit failure reasons + +--- + +## 4. Memory Model + +Memory is NOT a single blob. + +### Types + +#### 4.1 Turn + +Raw input/output + +#### 4.2 Event + +Accepted or rejected actions + +#### 4.3 Fact + +Current world state (derived, not duplicated) + +#### 4.4 Belief + +``` +Belief { + entity_id: string + claim: string + confidence: number +} +``` + +#### 4.5 Summary + +Compressed narrative context + +--- + +## 5. Services + +### 5.1 App (Core Service) + +Responsibilities: + +* orchestrate turns +* call LLM (optional) +* run truth engine +* manage memory + +Tech: Node.js (Express or Fastify) + +--- + +### 5.2 Truth Engine (Module inside App) + +Responsibilities: + +* validate actions +* enforce rules +* apply state changes +* emit events + +NO LLM USAGE + +--- + +### 5.3 LLM Adapter (Optional) + +Responsibilities: + +* extract actions from prose +* resolve references +* generate narration +* summarize memory + +Backend: Ollama + +--- + +### 5.4 Frontend + +Responsibilities: + +* send input +* display output +* optionally inspect state/events + +Minimal React or Vue app + +--- + +## 6. Turn Flow (IMPLEMENT EXACTLY) + +``` +1. Receive user input (string) +2. Store raw turn +3. Extract actions (LLM or fallback parser) +4. Validate actions (truth engine) +5. Apply accepted changes +6. Store events +7. Generate narration +8. Return response +``` + +--- + +## 7. Storage + +### SQLite (MVP) + +Tables: + +* entities +* events +* turns +* beliefs +* summaries + +File location: + +``` +/data/sqlite/app.db +``` + +--- + +## 8. Docker Design + +### Services + +``` +services: + app + frontend + ollama (optional) +``` + +### Principles + +* No host dependencies beyond Docker +* Persist only `/data` +* Use `.env` for config +* No hidden setup scripts + +--- + +## 9. Folder Structure + +``` +charactergarden/ + docker-compose.yml + .env + app/ + frontend/ + data/ + sqlite/ +``` + +--- + +## 10. MVP Scope + +STRICT LIMITS: + +* 1–2 rooms +* ≤3 characters +* ≤10 actions +* no complex AI autonomy +* no multi-agent loops yet + +--- + +## 11. Non-Goals (DO NOT BUILD YET) + +* microservices +* distributed systems +* plugin frameworks +* advanced agent loops +* cloud dependencies + +--- + +## 12. Development Workflow Rule + +A root-level file named `thoughts.md` must exist and be maintained throughout development. + +Purpose of `thoughts.md`: + +* record current implementation status +* record the next planned steps +* record blockers, assumptions, and unresolved questions +* summarize architectural decisions already made +* preserve continuity across editor sessions or context loss + +Rules for `thoughts.md`: + +* update it after each meaningful implementation step +* keep entries concise and factual +* do not use it for chain-of-thought dumping or vague brainstorming +* use it as a project progress log and working memory +* when resuming work, review `thoughts.md` first before making changes +* when changing architecture, record what changed and why +* when a task is incomplete, note exactly what remains + +Recommended structure: + +```md +# thoughts.md + +## Current Status +- what is implemented +- what is partially implemented +- what is broken or unverified + +## Current Architecture Decisions +- key decisions and constraints + +## Next Steps +- ordered checklist of immediate tasks + +## Open Questions +- unresolved design or implementation questions + +## Session Notes +- short dated notes describing recent progress +``` + +Copilot instruction: + +> Before starting work, read `thoughts.md`. After completing any meaningful change, update `thoughts.md` to reflect current status, next steps, and any unresolved issues. + +## 13. Development Order + +1. Define entities + actions +2. Implement truth engine +3. Add SQLite persistence +4. Build API endpoints +5. Add minimal UI +6. Add LLM integration + +--- + +## 14. Key Rule + +> If the system works without an LLM, the architecture is correct. + +--- + +## 15. Expected Behavior + +* deterministic state +* explainable failures +* replayable sessions +* inspectable memory + +--- + +## 16. Future Extensions (NOT NOW) + +* branching timelines +* advanced belief systems +* multi-agent arbitration +* long-term memory compression + +--- + +## END SPEC diff --git a/thoughts.md b/thoughts.md new file mode 100644 index 0000000..38d411f --- /dev/null +++ b/thoughts.md @@ -0,0 +1,29 @@ +# thoughts.md + +## Current Status +- Scaffold complete: `charactergarden/` folder structure created per spec section 9 +- Core contracts defined in `app/src/types.ts`: Entity, Action, Verb, ValidationResult, StateChange, GameEvent, Turn, Belief, Summary +- `docker-compose.yml` created; ollama service gated behind `--profile llm` (not required for MVP) +- `.env` created with defaults +- Nothing is implemented yet — no logic, no database, no server + +## Current Architecture Decisions +- App: Node.js + Fastify + TypeScript +- Frontend: React + Vite + TypeScript +- Database: better-sqlite3 (synchronous, no ORM) +- Ollama is optional; system must work without it (per section 14) +- `Event` type renamed `GameEvent` in code to avoid collision with the DOM `Event` global + +## Next Steps +1. Implement Truth Engine (`app/src/truthEngine.ts`) — pure validation, no I/O +2. Add SQLite schema + db module (`app/src/db.ts`) with the 5 tables from section 7 +3. Implement App service / turn flow (`app/src/index.ts`) per section 6 +4. Add Fastify route `POST /turn` that executes the full pipeline +5. Stub LLM adapter (`app/src/llmAdapter.ts`) with a fallback parser + +## Open Questions +- Should room/location be an Entity attribute or a separate entity type? +- What is the initial world state for the MVP (1–2 rooms, ≤3 characters)? + +## Session Notes +- 2026-04-23: Project started. Scaffold and type contracts created. No logic yet.