Skip to content

Database reference

Talon uses SQLite with WAL mode and foreign keys enabled. The entire daemon state — messages, queue, personas, memory, schedules, audit log — lives in a single file. No external database dependency.

TablePurpose
channelsChannel connector configs and credentials
personasAgent profiles with model, capabilities, and skill lists
bindingsChannel-to-persona routing (thread-level or channel-default)
threadsConversation threads keyed by channel + external ID
messagesFull message history, append-only, inbound and outbound
queue_itemsDurable work queue with status, retry, and dead-letter
runsAgent execution records with session ID and token usage
schedulesCron/interval/one-shot job definitions
memory_itemsPer-thread structured memory (facts, summaries, notes)
artifactsAgent output files with path, MIME type, and checksum
audit_logAppend-only audit trail of all side-effecting operations
tool_resultsIdempotent tool result cache keyed by run + request ID

Schema is defined in src/core/database/migrations/001-initial-schema.sql and later migrations.

SQLite is opened in Write-Ahead Logging mode. This gives:

  • Concurrent readers — reads don’t block writes and vice versa
  • Crash safety — WAL file is replayed on restart after an unclean shutdown
  • Better write throughput — multiple writes batch into WAL before checkpoint

Foreign keys are enabled on every connection. Cascade deletes are defined where appropriate (e.g., deleting a thread cascades to messages, queue items, and memory items).

Migrations are versioned SQL files in src/core/database/migrations/. They’re numbered sequentially: 001-initial-schema.sql, 002-...sql, etc.

Apply pending migrations:

Terminal window
npx talonctl migrate

The daemon also runs migrate automatically on startup. It’s idempotent — already-applied migrations are skipped. Migration state is tracked in a _migrations table.

All database access goes through repository classes in src/core/database/repositories/. Each table has a typed repository:

RepositoryTable
ChannelRepositorychannels
PersonaRepositorypersonas
BindingRepositorybindings
ThreadRepositorythreads
MessageRepositorymessages
QueueRepositoryqueue_items
RunRepositoryruns
ScheduleRepositoryschedules
MemoryRepositorymemory_items
ArtifactRepositoryartifacts
AuditRepositoryaudit_log
ToolResultRepositorytool_results

Every repository method returns Result<T, E> from neverthrow. There are no raw throws across module boundaries. This makes the database layer swap-able in the future — the interface contract is typed, not SQLite-specific.

Terminal window
npx talonctl backup

This snapshots the SQLite file and the data/ directory to a timestamped archive. Run it before upgrades or migrations.

The database file path is configured in talond.yaml:

dataDir: ./data

The database lives at <dataDir>/talon.db. WAL and SHM files (talon.db-wal, talon.db-shm) are co-located and managed automatically by SQLite.