agent-orchestrator/schema/canonical.sql
Hibryda 631fc2efc8 feat: canonical SQL DDL + schema validator + migration tool
- schema/canonical.sql: 29 tables across 3 databases, CHECK constraints,
  foreign keys, 13 indexes, WAL mode, schema_version tracking
- tools/validate-schema.ts: applies DDL to in-memory SQLite, extracts
  PRAGMA table_info + sqlite_master metadata as JSON
- tools/migrate-db.ts: CLI for Tauri→Electrobun data migration with
  atomic transaction, version fencing, INSERT OR IGNORE
- docs/SWITCHING.md: migration guide with prerequisites and troubleshooting
2026-03-22 03:33:15 +01:00

299 lines
10 KiB
SQL

-- 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
);