CREATE TABLE agents ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), slug text NOT NULL UNIQUE, name text NOT NULL, kind text NOT NULL CHECK (kind IN ('claude','ollama','mastra','mcp-client','external')), model text, persona_path text, capabilities jsonb NOT NULL DEFAULT '{"read":true,"suggest":true,"write":false}'::jsonb, scopes jsonb NOT NULL DEFAULT '{}'::jsonb, created_at timestamptz NOT NULL DEFAULT now() ); CREATE TABLE agent_tokens ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), agent_id uuid NOT NULL REFERENCES agents(id) ON DELETE CASCADE, label text, token_hash text NOT NULL, last_used timestamptz, created_at timestamptz NOT NULL DEFAULT now(), revoked_at timestamptz ); CREATE TABLE conversations ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), title text, agent_id uuid REFERENCES agents(id) ON DELETE SET NULL, participants text[] NOT NULL DEFAULT '{}', status text NOT NULL DEFAULT 'open' CHECK (status IN ('open','summarized','archived')), summary text, metadata jsonb NOT NULL DEFAULT '{}'::jsonb, embedding vector(1024), started_at timestamptz NOT NULL DEFAULT now(), ended_at timestamptz ); CREATE TABLE messages ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), conversation_id uuid NOT NULL REFERENCES conversations(id) ON DELETE CASCADE, role text NOT NULL CHECK (role IN ('user','assistant','system','tool')), agent_id uuid REFERENCES agents(id) ON DELETE SET NULL, body text NOT NULL, metadata jsonb NOT NULL DEFAULT '{}'::jsonb, created_at timestamptz NOT NULL DEFAULT now() ); CREATE INDEX idx_messages_conv ON messages(conversation_id, created_at); CREATE INDEX idx_messages_fts ON messages USING GIN (to_tsvector('english', body)); CREATE INDEX idx_agent_tokens_hash ON agent_tokens(token_hash) WHERE revoked_at IS NULL;