-- canonical.sql — Authoritative DDL for all AGOR SQLite databases. -- Both Tauri (Rust) and Electrobun (Bun) stacks MUST match this schema. -- DBs: settings.db, btmsg.db, search.db. See docs/SWITCHING.md. PRAGMA journal_mode = WAL; PRAGMA foreign_keys = ON; PRAGMA busy_timeout = 5000; -- ── VERSION TRACKING ────────────────────────────────────────────────── -- Schema version fence. One row per database file. CREATE TABLE IF NOT EXISTS schema_version ( version INTEGER NOT NULL, migration_source TEXT, -- e.g. 'tauri', 'electrobun', 'migrate-db' migration_timestamp TEXT -- ISO-8601 when last migrated ); -- ── settings.db TABLES ──────────────────────────────────────────────── -- Key-value application settings (theme, fonts, shell, cwd, etc.) CREATE TABLE IF NOT EXISTS settings (key TEXT PRIMARY KEY, value TEXT NOT NULL); -- Project configurations stored as JSON blobs. CREATE TABLE IF NOT EXISTS projects (id TEXT PRIMARY KEY, config TEXT NOT NULL); -- Workspace groups (sidebar tabs). CREATE TABLE IF NOT EXISTS groups ( id TEXT PRIMARY KEY, name TEXT NOT NULL, icon TEXT NOT NULL, position INTEGER NOT NULL ); -- User-created custom themes. CREATE TABLE IF NOT EXISTS custom_themes ( id TEXT PRIMARY KEY, name TEXT NOT NULL, palette TEXT NOT NULL -- JSON blob (color map) ); -- User-customized keyboard shortcuts. CREATE TABLE IF NOT EXISTS keybindings (id TEXT PRIMARY KEY, chord TEXT NOT NULL); -- Agent sessions per project (provider-agnostic). CREATE TABLE IF NOT EXISTS agent_sessions ( project_id TEXT NOT NULL, session_id TEXT PRIMARY KEY, provider TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'idle' CHECK (status IN ('idle','running','error','stopped','completed')), cost_usd REAL NOT NULL DEFAULT 0, input_tokens INTEGER NOT NULL DEFAULT 0, output_tokens INTEGER NOT NULL DEFAULT 0, model TEXT NOT NULL DEFAULT '', error TEXT, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL ); CREATE INDEX IF NOT EXISTS idx_agent_sessions_project ON agent_sessions(project_id); -- Individual agent messages within a session. CREATE TABLE IF NOT EXISTS agent_messages ( session_id TEXT NOT NULL, msg_id TEXT NOT NULL, role TEXT NOT NULL, content TEXT NOT NULL DEFAULT '', tool_name TEXT, tool_input TEXT, timestamp INTEGER NOT NULL, cost_usd REAL NOT NULL DEFAULT 0, input_tokens INTEGER NOT NULL DEFAULT 0, output_tokens INTEGER NOT NULL DEFAULT 0, PRIMARY KEY (session_id, msg_id), FOREIGN KEY (session_id) REFERENCES agent_sessions(session_id) ON DELETE CASCADE ); CREATE INDEX IF NOT EXISTS idx_agent_messages_session ON agent_messages(session_id, timestamp); -- Historical session metrics (cost, tokens, turns) per project. CREATE TABLE IF NOT EXISTS session_metrics ( id INTEGER PRIMARY KEY AUTOINCREMENT, project_id TEXT NOT NULL, session_id TEXT NOT NULL, start_time INTEGER NOT NULL, end_time INTEGER NOT NULL, peak_tokens INTEGER DEFAULT 0, turn_count INTEGER DEFAULT 0, tool_call_count INTEGER DEFAULT 0, cost_usd REAL DEFAULT 0, model TEXT, status TEXT NOT NULL, error_message TEXT ); CREATE INDEX IF NOT EXISTS idx_session_metrics_project ON session_metrics(project_id); -- Session anchors — preserved turns surviving compaction. CREATE TABLE IF NOT EXISTS session_anchors ( id TEXT PRIMARY KEY, project_id TEXT NOT NULL, message_id TEXT NOT NULL, anchor_type TEXT NOT NULL CHECK (anchor_type IN ('auto','pinned','promoted')), content TEXT NOT NULL, estimated_tokens INTEGER NOT NULL, turn_index INTEGER NOT NULL DEFAULT 0, created_at INTEGER NOT NULL ); CREATE INDEX IF NOT EXISTS idx_session_anchors_project ON session_anchors(project_id); -- Remote relay machine connections. CREATE TABLE IF NOT EXISTS remote_machines ( id TEXT PRIMARY KEY, label TEXT NOT NULL, url TEXT NOT NULL, token TEXT NOT NULL, auto_connect INTEGER NOT NULL DEFAULT 0, spki_pins TEXT NOT NULL DEFAULT '[]', -- JSON array of SPKI hashes created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL ); -- Legacy v2 layout state (single-row). CREATE TABLE IF NOT EXISTS layout_state ( id INTEGER PRIMARY KEY CHECK (id = 1), preset TEXT NOT NULL DEFAULT '1-col', pane_ids TEXT NOT NULL DEFAULT '[]' ); -- Legacy v2 terminal sessions. CREATE TABLE IF NOT EXISTS sessions ( id TEXT PRIMARY KEY, type TEXT NOT NULL, title TEXT NOT NULL, shell TEXT, cwd TEXT, args TEXT, created_at INTEGER NOT NULL, last_used_at INTEGER NOT NULL, group_name TEXT DEFAULT '', project_id TEXT DEFAULT '' ); -- SSH connection profiles. CREATE TABLE IF NOT EXISTS ssh_sessions ( id TEXT PRIMARY KEY, name TEXT NOT NULL, host TEXT NOT NULL, port INTEGER NOT NULL DEFAULT 22, username TEXT NOT NULL, key_file TEXT DEFAULT '', folder TEXT DEFAULT '', color TEXT DEFAULT '#89b4fa', created_at INTEGER NOT NULL, last_used_at INTEGER NOT NULL ); -- ── btmsg.db TABLES — inter-agent messaging & task board ────────────── -- Registered agents (Tier 1 management + Tier 2 project). CREATE TABLE IF NOT EXISTS agents ( id TEXT PRIMARY KEY, name TEXT NOT NULL, role TEXT NOT NULL, group_id TEXT NOT NULL, tier INTEGER NOT NULL DEFAULT 2, model TEXT, cwd TEXT, system_prompt TEXT, status TEXT DEFAULT 'stopped', last_active_at TEXT, created_at TEXT DEFAULT (datetime('now')) ); -- Agent-to-agent visibility ACL. CREATE TABLE IF NOT EXISTS contacts ( agent_id TEXT NOT NULL, contact_id TEXT NOT NULL, PRIMARY KEY (agent_id, contact_id) ); -- Direct messages between agents. CREATE TABLE IF NOT EXISTS messages ( id TEXT PRIMARY KEY, from_agent TEXT NOT NULL, to_agent TEXT NOT NULL, content TEXT NOT NULL, read INTEGER DEFAULT 0, reply_to TEXT, group_id TEXT NOT NULL, sender_group_id TEXT, created_at TEXT DEFAULT (datetime('now')) ); CREATE INDEX IF NOT EXISTS idx_messages_to ON messages(to_agent, read); CREATE INDEX IF NOT EXISTS idx_messages_from ON messages(from_agent); -- Broadcast channels within a group. CREATE TABLE IF NOT EXISTS channels ( id TEXT PRIMARY KEY, name TEXT NOT NULL, group_id TEXT NOT NULL, created_by TEXT NOT NULL, created_at TEXT DEFAULT (datetime('now')) ); -- Channel membership (many-to-many). CREATE TABLE IF NOT EXISTS channel_members ( channel_id TEXT NOT NULL, agent_id TEXT NOT NULL, joined_at TEXT DEFAULT (datetime('now')), PRIMARY KEY (channel_id, agent_id) ); -- Messages posted to channels. CREATE TABLE IF NOT EXISTS channel_messages ( id TEXT PRIMARY KEY, channel_id TEXT NOT NULL, from_agent TEXT NOT NULL, content TEXT NOT NULL, created_at TEXT DEFAULT (datetime('now')) ); CREATE INDEX IF NOT EXISTS idx_channel_messages ON channel_messages(channel_id, created_at); -- Agent liveness heartbeats (unix epoch seconds). CREATE TABLE IF NOT EXISTS heartbeats (agent_id TEXT PRIMARY KEY, timestamp INTEGER NOT NULL); -- Undeliverable messages (recipient not found, etc.) CREATE TABLE IF NOT EXISTS dead_letter_queue ( id INTEGER PRIMARY KEY AUTOINCREMENT, from_agent TEXT NOT NULL, to_agent TEXT NOT NULL, content TEXT NOT NULL, error TEXT NOT NULL, created_at TEXT DEFAULT (datetime('now')) ); -- Audit trail for agent actions. CREATE TABLE IF NOT EXISTS audit_log ( id INTEGER PRIMARY KEY AUTOINCREMENT, agent_id TEXT NOT NULL, event_type TEXT NOT NULL, detail TEXT NOT NULL, created_at TEXT DEFAULT (datetime('now')) ); -- Per-session message acknowledgment (prevents re-processing). CREATE TABLE IF NOT EXISTS seen_messages ( session_id TEXT NOT NULL, message_id TEXT NOT NULL, seen_at INTEGER NOT NULL DEFAULT (unixepoch()), PRIMARY KEY (session_id, message_id) ); CREATE INDEX IF NOT EXISTS idx_seen_messages_session ON seen_messages(session_id); -- Kanban task board. CREATE TABLE IF NOT EXISTS tasks ( id TEXT PRIMARY KEY, title TEXT NOT NULL, description TEXT DEFAULT '', status TEXT DEFAULT 'todo' CHECK (status IN ('todo','progress','review','done','blocked')), priority TEXT DEFAULT 'medium' CHECK (priority IN ('low','medium','high')), assigned_to TEXT, created_by TEXT NOT NULL, group_id TEXT NOT NULL, parent_task_id TEXT, sort_order INTEGER DEFAULT 0, created_at TEXT DEFAULT (datetime('now')), updated_at TEXT DEFAULT (datetime('now')), version INTEGER DEFAULT 1 -- optimistic locking ); CREATE INDEX IF NOT EXISTS idx_tasks_group ON tasks(group_id); CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status); -- Task discussion comments. CREATE TABLE IF NOT EXISTS task_comments ( id TEXT PRIMARY KEY, task_id TEXT NOT NULL, agent_id TEXT NOT NULL, content TEXT NOT NULL, created_at TEXT DEFAULT (datetime('now')) ); CREATE INDEX IF NOT EXISTS idx_task_comments_task ON task_comments(task_id); -- ── search.db TABLES — FTS5 full-text search ───────────────────────── -- Agent message search index. CREATE VIRTUAL TABLE IF NOT EXISTS search_messages USING fts5( session_id, role, content, timestamp ); -- Task search index. CREATE VIRTUAL TABLE IF NOT EXISTS search_tasks USING fts5( task_id, title, description, status, assigned_to ); -- Inter-agent message search index. CREATE VIRTUAL TABLE IF NOT EXISTS search_btmsg USING fts5( message_id, from_agent, to_agent, content, channel_name );