Initialize project structure with core files, environment settings, and basic configurations

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
2026-04-23 17:19:55 -04:00
commit 14a07bca7a
12 changed files with 622 additions and 0 deletions

5
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,5 @@
{
"chat.tools.terminal.autoApprove": {
"New-Item": true
}
}

8
charactergarden/.env Normal file
View File

@@ -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

View File

@@ -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

33
charactergarden/.gitignore vendored Normal file
View File

@@ -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

View File

@@ -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"
}
}

View File

@@ -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<string, unknown>;
}
// ── 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<string, unknown>;
}
// ── 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;
}

View File

@@ -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"]
}

View File

@@ -0,0 +1 @@
# sqlite data directory — tracked by git, contents ignored

View File

@@ -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:

View File

@@ -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"
}
}

367
project.md Normal file
View File

@@ -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:
* 12 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

29
thoughts.md Normal file
View File

@@ -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 (12 rooms, ≤3 characters)?
## Session Notes
- 2026-04-23: Project started. Scaffold and type contracts created. No logic yet.