Get started
Architecture
The current system design. Each diagram is sourced from the same reviewed constants that are mirrored into the internal architecture set and checked for documentation drift.
What eli.ai is
A self-hostable, knowledge-graph-grounded assistant and durable agent platform: a markdown knowledge base, an LLM-extracted entity graph with provenance, GraphRAG chat with citations, a provider-agnostic agent harness with guardrails and human-in-the-loop, evals with golden sets and drift detection, coverage and gap analysis, and client-facing graph/coverage visualizations — all multi-tenant and runnable on a laptop or a single VPS.
Process topology
Two long-lived Node processes over one Postgres (Supabase in production); local dev runs both plus a Postgres container or cluster. Not serverless.
- web serves the UI, session BFF, REST and MCP routes, streams chat, queues durable agent work, and exposes database-backed run reattachment.
- worker runs queued starts and approval continuations plus connector, enrichment, eval, drift, report, cache, and reaper jobs through pg-boss.
- Invariant: no LLM/network/file I/O inside a database transaction — retrieve → commit → stream → short write transaction.
Tenancy & security
All 79 tenant tables carry workspace_id and are protected by Postgres FORCE ROW LEVEL SECURITY (the app role owns the tables, so plain RLS would be bypassed without FORCE). All tenant access flows through withWorkspace(), which sets a transaction-local app.workspace_id GUC; policies compare against it and fail closed (zero rows) when unset. Session routes derive workspace identity from the URL; workspace keys bind it to the key; user keys require an allowed workspace selection. Mutations additionally require a named role capability.
A permanent CI canary seeds two workspaces and proves cross-tenant reads/writes are impossible; its catalog check asserts every workspace_id table is FORCE-RLS, so a new table cannot ship without it.
Ingestion → knowledge graph
A manual vault save is synchronous and local; its caller dispatches graph, embedding, and extraction enrichment. Connector crawls normalize and ingest each document before advancing their durable checkpoint.
- Wikilinks and co-occurrence build useful model-free nodes and edges with a weak or absent LLM; they do not guarantee one connected component.
- Extraction degrades gracefully: frontier models use native structured output; OpenAI-compatible/local models fall back to schema-in-prompt with a repair round and ontology type-normalization.
- Merges are non-destructive pointers;
canonical_relationsis the only edge table read at serve time.
Retrieval & grounded chat (GraphRAG)
Query understanding feeds FTS and vector retrieval. Reciprocal-rank fusion produces visible seed concepts for graph expansion, then optional reranking and token-budgeted context assembly. The answer policy can answer, caveat, request clarification, or abstain with pointers; generated answers carry [Sn] sources.
Semantic layer ↔ data layer
The knowledge graph extracted from documents is the semantic layer (what things mean). It binds to a data layer — scoped external data sources queried through governed, read-shaped named queries — so structured queries and explicit agent data-tool calls resolve against live data. Answers are structured and dual-cited: [Sn] document sources plus [Dn] data-call citations, each backed by a persisted data_calls provenance row.
- Multi-engine via adapters: connectors speak Postgres, MySQL, and Snowflake through one adapter contract — schema discovery snapshots
information_schema, previews validate identifiers against the snapshot, and an LLM can draft component SQL from it, saved only after human review through the same read-only validation. - Governed named queries over model-written SQL: humans author and gate the SQL templates; the model supplies validated parameters only (per-connector
allowRawSqlis an owner opt-in escape hatch under the same guards). - Read-only by construction: single-statement SELECT/WITH enforced at save and execution time; every call bounded by
maxRows+timeoutMs; credentials encrypted, decrypted only at execution. - Natively consumable: the
kb_dataagent tool,POST /api/v1/queryfor third-party systems, and the MCP server at/api/mcpfor external agents. See Semantic ↔ data layer.
Agent platform
The harness is a hand-owned loop on the Vercel AI SDK. KB tools execute in-process under RLS — the registry injects workspaceId/kbScope; the model never supplies scope, which is the tenant-isolation guarantee.
- Runtime: the selectable runtime is the portable, provider-agnostic harness. Anthropic model calls may use supported prompt-caching/adaptive-thinking options, but there is no separate Tier-1 or managed Tier-2 executor.
- Durability: run state persists at every step; the worker reaper marks crash-orphaned runs
interrupted; HITL suspend/resume survives restarts. - Exposure: the UI and the authenticated
/api/v1both drive the same harness (hashed, workspace-scoped API keys); the MCP server at/api/mcpadditionally exposes the KB/graph/data tools to external agents.
Evals, coverage, and the feedback loop
Chat and agent answers collect feedback; human-approved answers are promoted into golden sets. The eval runner replays the real pipeline with deterministic checks and an LLM judge, producing per-tag metrics that overlay the coverage dashboard and drive A/B regression diffs. Scheduled drift snapshots raise alerts on orphan and churn thresholds.
Data model
90 physical tables: 79 tenant tables under FORCE-RLS and 11 control-plane tables. The major groups:
- Content: documents, chunks, embedding_spaces, chunk_embeddings.
- Graph: entities, entity_aliases, relations, mentions, relation_evidence, canonical_relations, merge_log, entity_types/relation_types, extraction_runs, rejection_tombstones.
- Conversations: conversations, messages.
- Agents: agents, agent_versions, agent_runs, run_steps, run_approvals, guardrail_verdicts, feedback, api_keys, agent_memory, agent_proposals.
- AI layer: ai_providers, model_slots, provider_credentials, config_snapshots, llm_calls, spend_counters, prices.
- MCP & prompts: mcp_servers, mcp_tools, prompt_templates, fewshot_examples.
- Evals & QA: golden_items, golden_assertions, golden_citations, golden_item_tags, eval_configs, eval_runs, eval_results, judgments, run_metrics, drift_snapshots, alerts, judge_calibration, judge_runs, qa_samples.
- Data layer: data_connectors, data_queries, entity_bindings, data_calls — the semantic↔data layer: scoped connectors, domain components, bindings, and the append-only
[Dn]provenance trail. - Scheduling & delivery: scheduled_jobs, webhook_endpoints, webhook_deliveries, report_snapshots, sso_providers.
- Viz & lifecycle: graph_layout, workspace_meta, coverage_stats, workspace_exports, destruction_records.
- Control plane (non-tenant): user, session, account, verification, organization (=workspace), member, invitation, workspace_roles, user_api_keys, sso_providers, and worker_heartbeats.
Stack
Next.js (App Router) + React + TypeScript · Postgres + pgvector + pg_trgm via Drizzle · pg-boss · Vercel AI SDK (OpenAI/Anthropic/Google/OpenAI-compatible) · Better Auth (organizations = workspaces) · shadcn/ui + Tailwind · sigma.js + graphology (WebGL graph) · shiki + mermaid (docs).
Go deeper