3 min read · 665 words
Database Schema
Nine tables. agents is the root; everything else hangs off it and cascade-deletes with it.
Full ERD
Rendering diagram…
Reading guide by table
Column-level semantics, defaults, and design commentary live on the ORM Models page; the highlights that matter when querying:
| Table | Written by | Gotchas when querying |
|---|---|---|
agents | create endpoint | enabled_tools is a CSV string — use LIKE '%tool%' carefully (substring false-positives) |
messages | chat | two rows per exchange; order by created_at or id |
agent_runs | chat | status='failed' rows hold the real LLM error in error_message |
tasks | analyze + workflow | due_date is free text, not a date — don't ORDER BY it expecting chronology |
tool_calls | everything | success is the string 'true'/'false'; cost columns are NULL except on workflow LLM stages |
documents / document_chunks | upload | chunks_count is denormalized; chunk agent_id duplicates the document's for direct filtering |
workflow_runs | workflow | final_output and quality_score need JSON/float parsing; running status can mean crashed-in-flight |
workflow_steps | workflow | order by id asc for chronological trace |
Cascade topology
Deleting an Agent removes: messages, runs, tasks, tool calls, documents (→ their chunks), workflow runs (→ their steps). Two important non-cascades:
- Chroma vectors survive — no code deletes from the vector collection (Known Issues).
tool_calls.agent_run_idlinks also cascade via the run, but tool calls belong to the agent first — a tool call never outlives its agent.
Useful queries
sql
-- Failure investigation: last 5 failed automated steps with errors
SELECT tool_name, error_message, created_at
FROM tool_calls WHERE success = 'false'
ORDER BY id DESC LIMIT 5;
-- Workflow quality over time
SELECT id, quality_score, status, created_at
FROM workflow_runs WHERE workflow_name = 'multi_agent_email_workflow'
ORDER BY id;
-- Spend proxy per tool (workflow stages only — see cost coverage docs)
SELECT tool_name, COUNT(*), SUM(CAST(estimated_cost AS REAL)) AS est_cost
FROM tool_calls WHERE estimated_cost IS NOT NULL
GROUP BY tool_name;
-- Verify SQLite↔Chroma linkage for a document
SELECT chunk_index, vector_id FROM document_chunks WHERE document_id = 1 ORDER BY chunk_index;Indexes
Only the primary keys are indexed (index=True on every id). FK columns (agent_id, etc.) have no explicit indexes — full scans are fine at dev scale; add indexes alongside real load (Design Decisions).
Related pages
- ORM Models — the SQLAlchemy definitions
- Migrations — how this schema evolves