Data model
The orchestrator keeps a structured record of every run in a local SQLite database (agi.db by
default, configurable via dbPath / $AGI_DB). It uses Node’s built-in node:sqlite — no
native build. The JSONL transcript that claude writes stays the source of truth for raw
message content; this database is the structured index for history, timeline replay, resume,
and metrics.
Schema lives in src/db/schema.ts; it’s written by a Recorder
(src/db/recorder.ts) that maps the orchestrator’s event stream into rows. Timestamps are Unix
epoch milliseconds (INTEGER).
Entity relationships
erDiagram
sessions ||--o{ runs : "has"
runs ||--o{ turns : "has"
turns ||--o{ decisions : "has"
sessions ||--o{ events : "emits"
runs ||--o{ events : "emits"
sessions {
TEXT id PK
TEXT label
TEXT cwd
TEXT goal
TEXT done_criteria
TEXT permission_mode
INTEGER created_at
INTEGER updated_at
}
runs {
INTEGER id PK
TEXT session_id FK
TEXT status "running | ended | error"
TEXT stop_reason
INTEGER turns
REAL elapsed_min
INTEGER started_at
INTEGER ended_at
}
turns {
INTEGER id PK
INTEGER run_id FK
INTEGER n "turn number"
TEXT injected_prompt
TEXT assistant_text
INTEGER duration_ms
INTEGER gates_handled
INTEGER files_changed
TEXT diff "JSON: files, patch, truncated"
TEXT snapshot "git sha after this turn"
INTEGER created_at
}
decisions {
INTEGER id PK
INTEGER turn_id FK
TEXT action "continue | stop"
TEXT prompt
TEXT reason
TEXT feedback "up | down | null (learning)"
INTEGER created_at
}
events {
INTEGER id PK
TEXT session_id
INTEGER run_id
TEXT type
TEXT payload "JSON"
INTEGER created_at
}
Tables
| Table | Purpose |
|---|---|
sessions |
One row per configured session (id, cwd, goal, done-criteria, permission mode). |
runs |
One row per run of a session — a start-to-stop drive. Tracks status, stop reason, turn count, elapsed minutes. |
turns |
One row per turn within a run: the injected prompt, Claude’s reply text, duration, gates handled, and (for git repos) the per-turn diff + a pinned worktree snapshot sha to roll back to. |
decisions |
The brain’s decision for a turn (continue/stop + prompt + reason), plus an optional operator thumbs-up/down feedback used by the learning loop. |
events |
The raw orchestrator event stream (typed + JSON payload) — the fine-grained log behind timeline replay. |
Provisioned for later tiers (created, may be empty)
| Table | Purpose |
|---|---|
attention_requests |
Human-decision escalations and risky-gate approvals: the question, the JSON options, the chosen option, and status (open/resolved/timed_out). |
preferences |
Key/value store scoped for the learning loop. |
Indexes
idx_runs_session, idx_turns_run, idx_decisions_turn, idx_events_session,
idx_events_created — supporting the dashboard’s per-session history, turn timelines, and
time-ordered event queries. PRAGMA journal_mode = WAL and foreign_keys = ON are set.
Read APIs
The dashboard reads this store through read-only endpoints:
GET /api/runs— run list (optionally per session).GET /api/run— a single run’s turn-by-turn timeline (injected prompt → reply → decision → events).GET /api/metrics— aggregates: runs, turns, avg turns/run, intervention (“needed you”) rate, status breakdown.
Backups & privacy
agi.db (and its -wal / -shm companions) contain your goals, prompts, and Claude’s replies.
They are git-ignored by default. Treat them as sensitive; don’t commit them. To reset
history, stop the app and delete the agi.db* files — the schema is recreated on next start.