File-based State
OpenAlice has no database. All state lives in the data/ directory as JSON, JSONL, and Markdown files. This makes everything inspectable, editable, and backupable with standard tools.
Directory Structure
data/
├── config/ # JSON configuration files (hot-reloadable)
│ ├── ai-provider-manager.json
│ ├── accounts.json
│ ├── engine.json
│ ├── agent.json
│ ├── connectors.json
│ ├── market-data.json
│ ├── news.json
│ ├── heartbeat.json
│ ├── snapshot.json
│ ├── compaction.json
│ ├── tools.json
│ └── web-subchannels.json
│
├── sessions/ # JSONL conversation histories
│ ├── web/default.jsonl
│ ├── web/{subchannel}.jsonl
│ ├── telegram/{chatId}.jsonl
│ └── cron/default.jsonl
│
├── brain/ # Agent cognitive state
│ ├── commit.json # Brain state export (commits, head, emotion)
│ ├── persona.md # Customized persona (gitignored)
│ ├── frontal-lobe.md # Working memory snapshot
│ ├── heartbeat.md # Heartbeat prompt (gitignored)
│ └── emotion-log.md # Emotion transition log
│
├── trading/ # Per-account trading state
│ └── {accountId}/
│ ├── git.json # Trading git state (commits, staging, head)
│ └── snapshots/ # Account snapshots (JSONL)
│
├── event-log/
│ └── events.jsonl # Persistent append-only event log
│
├── news-collector/
│ └── {date}.jsonl # News archive by date
│
├── cron/
│ └── jobs.json # Cron job definitions
│
├── tool-calls/ # Tool invocation logs
├── media/ # Content-addressable media store
└── cache/ # API response caches
Configuration Files
All config lives in data/config/ as JSON files validated by Zod schemas.
Auto-seeding — On first run, any missing config file is created with sensible defaults. You never need to create config files manually.
Hot-reload — Config files are re-read on each request. Edit a file, and the next AI interaction picks up the change immediately — no restart needed. This applies to all config files including ai-provider-manager.json, tools.json, and accounts.json.
Validation — Every config file has a Zod schema. Invalid values are caught at load time with clear error messages. See Configuration Reference for the full schema documentation.
Sessions
Conversations are stored as JSONL (one JSON object per line) in a format compatible with Claude Code:
{"type":"user","message":{"role":"user","content":"What's the price of AAPL?"},"uuid":"...","timestamp":"..."}
{"type":"assistant","message":{"role":"assistant","content":[{"type":"text","text":"Let me check..."}]},"uuid":"...","timestamp":"..."}
Each session entry includes:
- type —
user,assistant, orsystem(for compaction boundaries) - message — Role and content (text or content blocks with tool_use/tool_result)
- uuid / parentUuid — For threading
- provider — Which AI provider generated this (
vercel-ai,agent-sdk,human)
Sessions support compaction — when the context window approaches its limit, older messages are summarized into a compact preamble while keeping recent exchanges in full.
Trading History
Each trading account has a git.json file that stores the complete TradingGit state:
{
"commits": [
{
"hash": "a3f8c1d2",
"parentHash": null,
"message": "Buy 10 AAPL — market order",
"operations": [{ "action": "placeOrder", ... }],
"results": [{ "action": "placeOrder", "success": true, "status": "filled", ... }],
"stateAfter": { "positions": [...], "netLiquidation": 50000 },
"timestamp": "2025-03-15T14:30:00Z"
}
],
"head": "a3f8c1d2"
}
This is persisted after every commit, push, reject, and sync — giving you a complete, immutable audit trail.
Brain State
The brain persists as a JSON export (commit.json) containing:
- The full commit history (frontal lobe updates, emotion changes)
- Current head hash
- Current state (frontal lobe content, emotion)
Side-effect files (frontal-lobe.md, emotion-log.md) are written alongside for human readability — you can open them in any editor to see Alice's current working memory and emotion history.
Event Log
A persistent append-only JSONL file that records everything:
{"seq":1,"ts":1710500000000,"type":"trade.submitted","payload":{...}}
{"seq":2,"ts":1710500100000,"type":"heartbeat.ok","payload":{...}}
{"seq":3,"ts":1710500200000,"type":"cron.fire","payload":{"jobId":"..."}}
On startup, the event log is read to restore the sequence counter and populate an in-memory ring buffer (500 most recent entries) for fast queries.
Default / Override Pattern
Persona and heartbeat prompts use a two-tier pattern:
| Default (git-tracked) | User override (gitignored) |
|---|---|
default/persona.default.md | data/brain/persona.md |
default/heartbeat.default.md | data/brain/heartbeat.md |
On first run, defaults are auto-copied to the override paths. Edit the user files to customize without touching version control. Updates to the default files won't overwrite your customizations.