# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

AI Truman World is an AI social simulation system built with Claude Agent SDK. It is a small-scale, 可持续运行、可观察、可回放的 AI 小镇仿真器，当前定位更接近持续演进中的实验系统，而不只是最初的 MVP 样机。

## Common Commands

```bash
# Install dependencies
make install

# Start backend (FastAPI on http://127.0.0.1:18080)
make backend-dev

# Start frontend (Next.js on http://127.0.0.1:13000)
make frontend-dev

# Start both (with Docker database)
make dev

# Database (Docker)
make db-start      # start PostgreSQL container
make db-stop       # stop container
make db-migrate    # run Alembic migrations
make migrate       # apply migrations

# Code quality
make lint          # ruff check
make format        # ruff format
make pre-commit    # pre-commit hooks

# Run tests
make test          # pytest (run from backend/)

# Single test (from backend/)
cd backend && python -m pytest tests/test_file.py::test_name -v

# Frontend checks
cd frontend && npm run lint
cd frontend && npm run build
```

## Architecture

### Tech Stack
- **Backend**: Python + FastAPI
- **Frontend**: Next.js + TypeScript + Tailwind
- **AI Cognition**: Claude Agent SDK
- **Database**: PostgreSQL (pgvector 预留)
- **Cache**: Redis (预留)

### Backend Modules

```
backend/app/
├── api/           # HTTP routes, run control, queries
├── sim/           # Tick orchestration, world state, persistence coordinators
├── agent/         # Claude SDK, registry, planner/reactor/reflector
├── store/         # SQLAlchemy models, repositories, persistence facades
├── scenario/      # Bundle-driven scenario layer (bundle_world / open_world)
├── director/      # Director planning and observation
├── infra/        # Settings, logging, database
└── protocol/     # Protocol definitions
```

### Agent Configuration Pattern

Agents are configured declaratively in `agents/<id>/` directories:

```
agents/
├── _template/
│   ├── agent.yml   # id, name, occupation, home, personality, capabilities, model
│   └── prompt.md   # role definition and behavior instructions
└── <agent_id>/
    ├── agent.yml
    └── prompt.md
```

Key capability flags in `agent.yml`:
- `reflection`: 是否启用每日反思
- `dialogue`: 是否启用对话生成
- `mcp`: 是否启用 MCP 工具
- `subagents`: 是否启用子 agent

Example `agent.yml`:
```yaml
id: alice
name: Alice
occupation: barista
home: apartment_a
personality:
  openness: 0.7
  conscientiousness: 0.6
capabilities:
  reflection: true
  dialogue: true
  mcp: false
  subagents: false
model:
  max_turns: 8
  max_budget_usd: 1.0
```

### Agent Runtime Flow

```
registry.py         → 扫描 agents/*/agent.yml
config_loader.py    → 解析人格、职业、model config
prompt_loader.py    → 加载 prompt.md 并拼装上下文
runtime.py          → 封装 Claude Agent SDK 调用
context_builder.py  → 组装世界状态、地点、附近 agent、记忆
providers.py        → Agent provider 抽象 (heuristic/claude)
connection_pool.py  → Claude 连接池管理
memory_mcp_server.py → 记忆 MCP 工具服务器
planner.py          → 早晨生成日计划
reactor.py          → 遇到社交/异常事件时反应
reflector.py        → 晚上做每日反思
```

### Tick Flow and Persistence Boundary

Current inline tick path:

```text
SimulationService.run_tick
├── load run / world
├── day boundary planner (before agent decisions, best-effort outer task)
├── TickOrchestrator.execute_tick
├── TickPersistenceCoordinator.persist
│   ├── PersistenceManager.set_agent_locations
│   ├── RunRepository.set_tick
│   └── TickEventWriter.persist
│       ├── EventRepository.add_many
│       ├── PersistenceManager.persist_tick_memories
│       ├── PersistenceManager.persist_tick_relationships
│       └── Scenario.update_state_from_events
└── day boundary reflector (after tick writes, best-effort outer task)
```

Transaction rules:

- Core tick writes are coordinated by `TickPersistenceCoordinator`.
- Event, memory, relationship, run tick, agent location, and scenario state updates commit or roll back together.
- Repository `create*` / `update*` methods may commit for simple call sites.
- Repository `add*` / `set*` / `*_no_commit` methods are for upper-layer transaction composition.
- Day boundary planner / reflector are outer tasks; they do not roll back completed tick event writes.
- LLM call telemetry is best-effort and must not roll back main simulation writes.

### Simulation Scheduler

- `SimulationScheduler` 负责自动 tick 推进
- 支持配置 tick 间隔（默认 5 秒）
- 可以在 run 运行时自动推进时间
- 支持暂停/恢复调度

### Data Model

- `simulation_runs` - run 生命周期, 当前 tick
- `locations` - 地点信息, 坐标, 容量
- `agents` - agent 状态, 目标, 地点, profile
- `events` - 所有结构化事件 (talk, action, director injection)
- `relationships` - familiarity, trust, affinity
- `memories` - episodic, daily plan/reflection, promoted memories
- `director_memories` - 导演记忆存储
- `governance_records` / `governance_cases` / `governance_restrictions` - 治理留痕与限制
- `agent_economic_states` / `economic_effect_logs` - agent 经济状态与影响日志
- `llm_calls` - LLM 调用统计与成本记录

### Director Layer

Director capabilities now include:

- run lifecycle control
- timeline / world / agent inspection
- manual event injection
- automatic observation and planning
- director memories
- governance records, cases, restrictions
- subject alert / continuity risk observation

Director and scenario code should avoid directly mutating unrelated agent attributes or
relationships outside an explicit persistence boundary.

### Claude SDK 调用边界

Only in:
- 早晨生成粗粒度日计划 (planner)
- 社交/异常事件反应 (reactor)
- 晚上反思 (reflector)

NOT in:
- 每个 tick 基础移动
- 简单 work/rest 执行
- 直接改 world state

## Environment Variables

Create `.env` from `.env.example`. See [docs/engineering/CONFIGURATION.md](docs/engineering/CONFIGURATION.md) for complete reference.

Key variables:
- `TRUMANWORLD_LLM_PROVIDER`: `anthropic` (default) or `openai`
- `TRUMANWORLD_LLM_API_KEY`: API key for LLM provider
- `TRUMANWORLD_LLM_BASE_URL`: API endpoint (optional, defaults vary by provider)
- `TRUMANWORLD_AGENT_BACKEND`: `heuristic`, `claude_sdk` (default), or `langgraph`
- `TRUMANWORLD_DATABASE_URL`: PostgreSQL connection URL (required)

## Coding Style

- **Python**: 4-space indent, snake_case modules/functions, PascalCase classes, 100-char line limit, formatted by Ruff
- **TypeScript**: 2-space indent, PascalCase components, Next.js App Router conventions
- **Commits**: Conventional Commits (`type(scope): subject`, e.g. `refactor(sim): extract tick persistence coordinator`)

## Persistence Refactor Notes

When changing simulation writes:

- Add rollback tests before changing transaction boundaries.
- Prefer existing repository no-commit helpers over adding commits inside lower layers.
- Keep scenario updater methods split into no-commit apply methods and explicit persist methods.
- Treat seed methods as independent entry points; cover failure rollback if adding a new seed policy.
- Keep day boundary telemetry best-effort.

See:

- [docs/engineering/CURRENT_ARCHITECTURE.md](docs/engineering/CURRENT_ARCHITECTURE.md)
- [docs/engineering/PERSISTENCE_REFACTOR_PLAN.md](docs/engineering/PERSISTENCE_REFACTOR_PLAN.md)
- [docs/engineering/roadmap.md](docs/engineering/roadmap.md)

## API Endpoints

### Run Management
- `POST /runs` - 创建新 run
- `GET /runs` - 获取 run 列表
- `GET /runs/{id}` - 获取 run 状态
- `DELETE /runs/{id}` - 删除 run
- `POST /runs/{id}/start` - 启动
- `POST /runs/{id}/pause` - 暂停
- `POST /runs/{id}/resume` - 恢复
- `POST /runs/{id}/tick` - 手动推进一个 tick

### Timeline & Events
- `GET /runs/{id}/timeline` - 获取时间线事件
- `POST /runs/{id}/director/events` - 导演注入事件

### World View
- `GET /runs/{id}/world` - 世界快照
- `GET /runs/{id}/world/clock` - 世界时钟
- `GET /runs/{id}/world/locations` - 地点列表
- `GET /runs/{id}/world/events` - 世界事件列表

### Agent Management
- `GET /runs/{id}/agents` - 获取 agent 列表
- `GET /runs/{id}/agents/{agent_id}` - 获取 agent 详情
- `GET /agents/{id}/memories` - 获取 agent 记忆
- `GET /agents/{id}/relationships` - 获取 agent 关系

### Director
- `GET /runs/{id}/director/observation` - 导演观察
- `GET /runs/{id}/director/plan` - 导演计划

### Health
- `GET /api/health` - 健康检查

## Frontend Routes

- `/` - Home
- `/runs/[id]` - Run overview
- `/runs/[id]/timeline` - Timeline view
- `/runs/[id]/agents/[agentId]` - Agent detail
- `/runs/[id]/world` - World view

## Testing

### Backend (pytest)

Tests in `backend/tests/`, 按模块组织：

```
tests/
├── agent/         # registry, runtime, session, connection_pool, token tracking, ...
├── api/           # runs, agents, timeline, openapi, world presenters
├── sim/           # core, service, scheduler, bootstrap, action resolver, clock, ...
├── store/         # memory, repositories, economic state, governance case
├── director/      # planner, observer, strategy engine, manual planner
├── scenario/      # bundle/factory registry, rule evaluator, world config, governance
├── cognition/     # langgraph backend, reactor prompt cache
└── integration/   # postgres simulation, SDK initialize/stability
```

Key fixtures in `conftest.py`:
- `db_session` — SQLite in-memory 数据库 session（异步）
- `client` — FastAPI AsyncClient，自动注入 db_session 依赖覆盖
- `anyio_backend` — asyncio 后端
- `default_agent_backend` (autouse) — 自动设为 heuristic 避免真实 LLM 调用
- `cleanup_scheduler` (autouse) — 测试后清理调度器

已配置 `pytest-cov`，覆盖率报告可通过 `--cov` 参数生成。

```bash
# Run all tests
cd backend && uv run pytest -q

# Single test
cd backend && python -m pytest tests/test_file.py::test_name -v

# With coverage
cd backend && uv run pytest --cov=app --cov-report=term-missing
```

### Frontend (Jest)

使用 Jest + @testing-library/react，测试文件位于各模块的 `__tests__/` 目录：

```
frontend/
├── components/__tests__/    # event-card, run-list, story-timeline, phaser game, ...
├── lib/__tests__/           # event-utils, world-insights, world-map-motion, api
```

```bash
# Run frontend tests
cd frontend && npm run test          # 单次运行
cd frontend && npm run test:watch     # watch 模式
```

## Pre-commit Hooks

配置在 `.pre-commit-config.yaml`，分两个阶段触发：

**pre-commit（提交时）**：
- Trailing whitespace / EOF fixer
- YAML / JSON / TOML validation
- 大文件检测、合并冲突标记检测、debug 语句检测
- Ruff lint + format（仅 backend/）
- Actionlint（GitHub Actions 校验）

**pre-push（推送时）**：
- `backend-mypy` — 类型检查
- `backend-pytest` — 后端单元测试
- `frontend-jest` — 前端 Jest 测试
- `frontend-build` — 前端构建检查

可手动运行：`make pre-commit`。
