Platform note 01 / thesis

Every answer shows its work

eli.ai turns your documents and live systems into one knowledge layer for chat, agents, and APIs. Every claim links to the document or the database call behind it — and when the evidence is not there, it says so instead of guessing.

composable systems
8
documented API operations
92
automated tests
2,300+

Self-hostable on a laptop or a single VPS — Postgres and two Node processes, no managed services required.

Grounded chatverified 2/2

answers when the evidence is there

Is anything stuck on the Order Platform right now?

Yes — 14 orders are stuck totalling $8,120 D1, all older than 24 hours. Per the incident runbook, requeue them from the fulfilment console S1.

S1
Order Platform incident runbook · § Requeue
D1
order-backlog · 4 rows · 41 ms · ok

and stops when it is not

Which vendor should we consolidate onto next quarter?

I cannot answer that from this workspace. The vendor comparison is a draft and no certified source covers next quarter — here is what does exist.

abstained · reason: no_certified_source

Composition / grounded answer

  1. Intake
  2. Atlas
  3. Warrant
  4. Lens
  5. Ports

Five systems, in the order they hand off. The annotated plate is below.

Platform note 02 / composition

Composition is the product.

Documents, live data, policy, evaluation, lineage, and programmatic surfaces participate in one result. Follow a path to see where each handoff happens.

One machine, four documented paths

Every step of the grounded answer path, listed in order below, followed by all eight systems and every documented handoff between them. On large screens the plate also draws those systems and handoffs as a map, with this path picked out.

A cited answer that respects source permissions and stops when certified evidence ends.
  1. Intake

    Normalize source material and preserve source permissions.

  2. Atlas

    Connect evidence through typed entities and relations.

  3. Warrant

    Apply certification, lifecycle, and content ACL policy.

  4. Lens

    Retrieve, rerank, answer, clarify, or abstain.

  5. Ports

    Deliver the result to a person or programmatic caller.

  • Intake
  • Atlas
  • Warrant
  • Lineage
  • Conduit
  • Lens
  • Crucible
  • Ports
All system handoffs
  • Intake → Atlas Normalized documents feed typed entity and relation extraction with sentence evidence.
  • Atlas → Warrant Graph concepts receive authority tiers, lifecycle state, ownership, and governed change.
  • Atlas → Lens Graph neighborhoods join lexical and vector retrieval before reranking.
  • Warrant → Lens Content ACLs and certification state constrain what the answer pipeline may state.
  • Conduit → Lens Entitled named queries contribute live rows and auditable Data Citations.
  • Lens → Ports Grounded results reach the workspace, REST clients, MCP hosts, and durable agents.
  • Lens → Crucible The real answer pipeline runs against golden sets and measured quality gates.
  • Crucible → Warrant Significance-gated evaluation results govern consequential configuration changes.
  • Lens → Lineage Answer claims, source revisions, data calls, and policy verdicts remain traceable.
  • Lineage → Intake Reverse provenance resolves a result back to the exact ingested source revision.

What composing them produces

  • Both halves of an answer

    One claim can carry a Source Citation S1 to the paragraph it came from and a Data Citation D1 to the query that fetched the number. The two registries are separate and each resolves on its own.

    • Lens
    • Conduit
  • A refusal is a result

    When no certified source covers the question, the answer policy abstains and points at what does exist instead of filling the gap. Every verdict is recorded, so you can read what was declined and why.

    • Warrant
    • Lens
  • Checked afterwards, not asserted

    Lineage keeps the trail from an answer back to the document revision behind it. Crucible scores the same pipeline against golden sets, and a configuration change ships only when the difference is statistically significant.

    • Lineage
    • Crucible
  • Humans stay in the loop

    Consequential agent actions suspend into an approvals inbox — draft, rationale, and three verbs: approve, reject, or edit. A per-tool review policy earns autopilot over time: every autopiloted call is logged and risk-scored, a sample gets a retrospective verdict, and overturns tighten the policy on their own.

    • Warrant
    • Ports
  • One engine for every number

    Matrices, deal configurations, pricing rules and estimation factors live as versioned structured records. Prices come from rules, estimates come out as ranges with visible assumptions, and report figures freeze their source values — so a number a buyer sees is the number delivery reports.

    • Atlas
    • Conduit

Platform note 03 / capabilities

Every mechanism, and what it changes.

Each capability below is stated twice — the mechanism, so your engineers can verify it, and the outcome, so everyone else knows why it matters. Both lines describe the same shipped code.

  • Lens

    Cited answers, honest abstentions

    the mechanism
    Hybrid retrieval with reranking and graph fusion, ACL-filtered before ranking. A citation policy validates every claim, retries with named gaps, then abstains rather than shipping uncited — span-level offsets included.
    what it changes
    Answers you can forward to a customer or an auditor without re-checking them — and a refusal you can trust instead of a confident guess.

    composes with

  • Conduit

    Live data, frozen provenance

    the mechanism
    Governed read-only named queries over Postgres, MySQL and Snowflake with per-user row entitlements. Every result is snapshotted and hashed, so a cited figure re-verifies months later.
    what it changes
    The number in the report is the number in the warehouse — and an amendment cycle ends with a hash check, not an argument.

    composes with

  • Warrant

    Humans stay in the loop

    the mechanism
    Consequential agent actions suspend durably: approve, reject, or edit. A per-tool review policy earns autopilot — every autopiloted call logged, risk-scored, and sampled for retrospective review.
    what it changes
    Pilot-grade safety that relaxes into throughput as measured trust accrues, not as attention fades.

    composes with

  • Crucible

    Quality gates on every release

    the mechanism
    Golden test sets run the real pipeline on schedule; acceptance gates bind metric thresholds to consequential flips; drift detection ships with statistical significance.
    what it changes
    A regression is a finding with a confidence interval — caught before your customers become the eval.

    composes with

  • Atlas

    One engine for every number

    the mechanism
    Matrices, deal configurations, pricing rules and estimation factors live as versioned structured records. Prices come from rules; estimates ship as ranges with visible assumptions.
    what it changes
    The price quoted is the price delivered — and no spreadsheet quietly disagrees with the contract.

    composes with

  • Intake

    Team knowledge, real permissions

    the mechanism
    Connectors and office-format intake normalize everything into one lineage-carrying corpus. Team file stores hold decks and templates with explicit cross-team grants.
    what it changes
    Each team's material stays theirs, is searchable and citable, and stops rotting in shared drives.

    composes with

  • Lineage

    Provenance end to end

    the mechanism
    Append-only audit the database enforces, document lineage across revisions, full run traces with token-level cost attribution, and a configurable zero-retention model posture.
    what it changes
    Compliance evidence without archaeology — and client-data features that pass security review the first time.

    composes with

  • Ports

    Every front door

    the mechanism
    Durable agents with budgets, pinned versions and capability locks — each servable as its own scoped MCP mount — installable team skills, a versioned REST API with a typed SDK, and MCP in both directions.
    what it changes
    It works where your team already works — chat, CRM, assistants, and your own product surfaces.

    composes with

Platform note 04 / use cases

Every job is a different path.

Each row below runs on the machine above. Read a path for the systems a job needs and the order it needs them in: the chain that builds the result, then what happens to it once it exists. Breadth follows scope — a focused job runs on four of the eight, a whole-workspace walkthrough runs on all of them, and it is the same machine either way.

  • Research synthesisPattern

    Ingest papers, reports and field notes, connect them in a concept graph, and trace every synthesised claim back to the document it came from.

    1. Intake
    2. Atlas
    3. Lens
    then
    1. Lineage
  • Support deflectionPattern

    Answer a customer in their own words from the help centre and ticket history — citing the canonical answer, and abstaining rather than bluffing.

    1. Intake
    2. Warrant
    3. Lens
    then
    1. Crucible
  • Compliance & audit trailsPattern

    Certify policies with named owners and review SLAs, then hand an auditor append-only provenance, a blast radius and a programmatic trail.

    1. Warrant
    then
    1. Lineage
    2. Crucible
    3. Ports
  • Sales enablement

    A rep on a live call gets the current price, the certified positioning and the security posture — cited, never guessed.

    1. Intake
    2. Warrant
    3. Lens
    then
    1. Lineage
    2. Crucible
  • Automated reports

    The same client report every Monday — current numbers, defensible definitions, a reproducible PDF — with nobody assembling it by hand.

    1. Conduit
    2. Warrant
    3. Lens
    then
    1. Crucible
    2. Ports
  • Matter research

    State a certified controlling authority plainly, read the live matters database, and decline when a settlement call has no authority on file.

    1. Intake
    2. Atlas
    3. Warrant
    4. Conduit
    5. Lens
    then
    1. Lineage
    2. Crucible
  • Incident response

    A 2am page becomes a cited incident answer carrying live open-incident counts, abstaining when no record backs the claim — then ships as an assistant.

    1. Intake
    2. Atlas
    3. Warrant
    4. Conduit
    5. Lens
    then
    1. Lineage
    2. Crucible
    3. Ports
  • Sales AI desk

    One deal record drives the deck, the proposal, the price and the contract; estimates ship as ranges, claims trace to the matrices, and consequential sends wait for a human — until autopilot is earned.

    1. Intake
    2. Atlas
    3. Warrant
    4. Conduit
    5. Lens
    then
    1. Lineage
    2. Crucible
    3. Ports

The fourteen industry walkthroughs — one per seeded demo workspace, each runnable locally — all follow the long path, Intake through Ports, because touring a whole workspace touches everything in it. The shorter rows above are the useful lesson: a job takes the systems it needs, and the rest stays switched off.

Platform note 05 / atlas

Eight systems, and any one alone.

Each system owns one job, one set of endpoints under /api/v1, and one entry point in the SDK. Together they are a single path from a document to a cited answer. Separately, each is something you can adopt without the other seven.

You do not have to adopt the platform to use a module

There is no base install and no required order. Run Lens over documents you never modelled in Atlas. Run Conduit against your warehouse and never ingest a document at all. The minimum to use one module is a workspace API key carrying that module's scope, and that module's endpoint — nothing else has to be configured.

Reactone subpath, one module in your bundle

import { createEliTransport } from "@eli-ai/client/core";
import { EliProvider } from "@eli-ai/react/provider";
import { EliQuery } from "@eli-ai/react/query";
import "@eli-ai/react/styles.css";

// Only the query module is in your bundle. No
// provider holds a key — a same-origin route
// injects it server-side.
const transport = createEliTransport({
  fetch: proxyFetch,
});

<EliProvider transport={transport}>
  <EliQuery initialMode="ask" />
</EliProvider>

HTTPone key, one endpoint

# Conduit alone, against your own warehouse.
# Nothing was ingested, modelled or governed
# first, and no other module is switched on.
curl -L -X POST \
  https://eli.ai/api/v1/data/queries/order-backlog/run \
  -H "Authorization: Bearer eli_sk_..." \
  -H "Content-Type: application/json" \
  -d '{"params":{"status":"stuck"}}'
# { "dataCallId": "01K7V...", "rows": [...],
#   "rowCount": 14, "durationMs": 41 }

one subpath per module — @eli-ai/react/{query, documents, graph, governance, data, agents, quality, connectors} · plus /provider and /hooks

The headless client mirrors the same split — createDataClient from @eli-ai/client/data imports no other capability module, and no React.

Read each system as the code you would ship — or as the data flowing through it.

  • IntakeConnect & ingest

    Bring it in

    Sync Confluence, SharePoint, Slack and markdown vaults read-only, incrementally, and re-process only where content actually changed.

    API
    /api/v1/connectors
    SDK
    @eli-ai/react/connectors
    Intake reference

    Inputa source: non-secret config plus a credential, encrypted at write

    {
      "type": "confluence",
      "config": {
        "baseUrl": "https://acme.atlassian.net/wiki",
        "spaceKeys": ["ENG", "OPS"]
      },
      "credential": { "email": "svc@acme.com", "apiToken": "..." }
    }

    APIcreate the source, then enqueue a crawl — scope kb:write

    curl -L -X POST https://eli.ai/api/v1/connectors \
      -H "Authorization: Bearer eli_sk_..." \
      -H "Content-Type: application/json" -d @source.json
    # 201 { "id": "01K7Q...", "type": "confluence", "hasCredential": true }
    
    curl -L -X POST https://eli.ai/api/v1/connectors/01K7Q.../sync \
      -H "Authorization: Bearer eli_sk_..." \
      -H "Content-Type: application/json" -d '{"kind":"incremental"}'
    # 202 { "enqueued": true, "sourceId": "01K7Q...", "kind": "incremental" }

    Reactthe source list, with per-source sync

    import { EliConnectors } from "@eli-ai/react/connectors";
    
    <EliConnectors
      canSync
      onSyncQueued={(result) => toast(`sync queued: ${result.sourceId}`)}
    />
  • AtlasThe semantic layer

    Connect it

    Extract a typed entity graph with provenance on every relation — and a deterministic fallback that works with no model at all.

    API
    /api/v1/entities · /api/v1/relations
    SDK
    @eli-ai/react/graph
    Atlas reference

    Inputan entity, or an edge carrying the sentence that evidences it

    { "name": "Order Platform", "type": "system",
      "aliases": ["OP", "order-svc"],
      "description": "Checkout, capture and fulfilment hand-off." }
    
    { "srcEntityId": "01K7R...", "dstEntityId": "01K7S...",
      "type": "depends_on",
      "evidence": "Capture calls the ledger synchronously." }

    APIwrite an entity (kb:write), then walk the frontier (kb:read)

    curl -L -X POST https://eli.ai/api/v1/entities \
      -H "Authorization: Bearer eli_sk_..." \
      -H "Content-Type: application/json" -d @entity.json
    # 201 the canonical entity
    # 409 { "error": "conflict", "existingId": "01K7R..." }
    
    curl -L "https://eli.ai/api/v1/entities/01K7R.../neighborhood?depth=2" \
      -H "Authorization: Bearer eli_sk_..."
    # { "entity": {...}, "nodes": [...], "edges": [...], "truncated": false }

    Reactbrowse entities and their neighbourhood

    import { EliKnowledgeGraph } from "@eli-ai/react/graph";
    
    <EliKnowledgeGraph
      initialEntityId="01K7R..."
      onEntitySelect={(entity) => router.push(`/e/${entity.id}`)}
    />
  • WarrantGovern & certify

    Govern it

    Promote facts from extracted to certified through gated change requests, with owners, review SLAs and a versioned manifest.

    API
    /api/v1/change-requests · /api/v1/manifest
    SDK
    @eli-ai/react/governance
    Warrant reference

    Inputa proposal — kind, target, and the payload validated for that kind

    {
      "kind": "update",
      "entityId": "01K7R...",
      "payload": {
        "description": "Owns capture. Fulfilment moved to Logistics in Q3."
      },
      "note": "Scope changed after the Q3 split."
    }

    APIpropose, then decide — scope kb:write (kb:read to list)

    curl -L -X POST https://eli.ai/api/v1/change-requests \
      -H "Authorization: Bearer eli_sk_..." \
      -H "Content-Type: application/json" -d @request.json      # 201
    
    curl -L -X POST https://eli.ai/api/v1/change-requests/01K7T.../approve \
      -H "Authorization: Bearer eli_sk_..." \
      -H "Content-Type: application/json" -d '{"note":"Confirmed with the owner."}'
    
    curl -L https://eli.ai/api/v1/manifest -H "Authorization: Bearer eli_sk_..."
    # counts, governance distribution, hub concepts, review staleness
    # GET /api/v1/export/skos returns the same concepts as SKOS/PROV-O JSON-LD

    Reactthe review queue, gated on what the caller may do

    import { EliGovernance } from "@eli-ai/react/governance";
    
    <EliGovernance
      canPropose
      canReview={viewer.isSteward}
      onRequestReviewed={(id, decision) => audit(id, decision)}
    />
  • LineageProvenance & traceability

    Trace it

    Trace any document to what it produced, and see what breaks before you deprecate it.

    API
    /api/v1/documents
    SDK
    @eli-ai/react/documents
    Lineage reference

    Inputa markdown document — the thing an answer later cites as S1

    # Order Platform runbook
    
    ## Requeue
    Orders stuck longer than 24 hours are requeued from the
    fulfilment console. Escalate to #order-platform after two
    failed requeues.

    APIwrite it (kb:write), then ask what it produced (kb:read)

    curl -L -X POST https://eli.ai/api/v1/documents \
      -H "Authorization: Bearer eli_sk_..." \
      -H "Content-Type: application/json" \
      -d '{"path":"runbooks/order-platform.md","content":"# Order Platform runbook\n..."}'
    # 201 { "docId": "01K7U...", "path": "...", "contentHash": "...", "title": "..." }
    
    curl -L https://eli.ai/api/v1/documents/01K7U.../lineage \
      -H "Authorization: Bearer eli_sk_..."
    # { "document", "governance", "origin", "revisions",
    #   "audit", "derived", "downstream" }

    Reactthe trail for one document, origin through blast radius

    import { EliDocumentLineage } from "@eli-ai/react/documents";
    
    <EliDocumentLineage
      documentId="01K7U..."
      onLoaded={(lineage) => setImpact(lineage.downstream)}
    />
  • ConduitThe live-data layer

    Query it

    Bind graph entities to allow-listed, parameterized read-only SQL so an answer can quote a live number and show the call that fetched it.

    API
    /api/v1/data/queries
    SDK
    @eli-ai/react/data
    Conduit reference

    Inputa named query: SELECT/WITH only, typed params, row-capped

    slug:   order-backlog
    sql:    select id, total_cents, created_at
            from orders
            where status = $1
              and created_at < now() - interval '24 hours'
    params: [{ "name": "status", "type": "string", "required": true }]

    APIrun it against your own warehouse — scope data:run; the dataCallId is the D1 anchor

    curl -L -X POST https://eli.ai/api/v1/data/queries/order-backlog/run \
      -H "Authorization: Bearer eli_sk_..." \
      -H "Content-Type: application/json" \
      -d '{"params":{"status":"stuck"}}'
    # { "dataCallId": "01K7V...", "connectorId": "01K7W...",
    #   "columns": ["id","total_cents","created_at"], "rows": [...],
    #   "rowCount": 14, "durationMs": 41, "truncated": false }

    Reactthe query catalogue, with governed execution

    import { EliLiveData } from "@eli-ai/react/data";
    
    <EliLiveData
      initialQuerySlug="order-backlog"
      canExecute={viewer.canRunData}
      onResult={(result) => setRows(result.rows)}
    />
  • LensRetrieve & answer

    Answer it

    Retrieve across full-text, vectors and the graph, then answer, ask for clarification, surface a conflict, or abstain.

    API
    /api/v1/query · /api/v1/search
    SDK
    @eli-ai/react/query
    Lens reference

    Inputa question, and how hard the answer policy should hold the line

    {
      "question": "Is anything stuck on the Order Platform right now?",
      "includeData": true,
      "maxSources": 8,
      "policyMode": "enforce"
    }

    APIone call, evidence attached — scope agents:run (kb:read for search)

    curl -L -X POST https://eli.ai/api/v1/query \
      -H "Authorization: Bearer eli_sk_..." \
      -H "Content-Type: application/json" -d @question.json
    # { "answer": "...",
    #   "claims": [{ "text": "...", "citations": ["S1", "D1"] }],
    #   "sources": [...], "dataCalls": [...], "entities": [...],
    #   "groundedness": { "verified": 2, "total": 2 },
    #   "policy": { "verdict": "answer", ... } }
    
    curl -L "https://eli.ai/api/v1/search?q=requeue&limit=10&rerank=true" \
      -H "Authorization: Bearer eli_sk_..."      # retrieval only, no model
    # every verdict is kept: GET /api/v1/policy/decisions?verdict=abstain

    Reactsearch and ask in one surface; EliSearch drops the ask tab

    import { EliQuery } from "@eli-ai/react/query";
    
    <EliQuery
      initialMode="ask"
      searchLimit={10}
      onAnswer={(answer) => setSources(answer.sources)}
    />
  • CrucibleEvaluate & measure

    Measure it

    Measure quality against concept-anchored golden sets, and gate config changes on statistical significance rather than impressions.

    API
    /api/v1/qrels · /api/v1/evals/runs
    SDK
    @eli-ai/react/quality
    Crucible reference

    Inputa golden item: must/should assertions and whether citing is required

    {
      "question": "How do we requeue stuck orders?",
      "assertions": [
        { "text": "Requeue from the fulfilment console", "kind": "must" },
        { "text": "Escalate after two failures", "kind": "should" }
      ],
      "citations": [{ "docId": "01K7U...", "mode": "required" }],
      "difficulty": "medium", "tags": ["runbook"]
    }

    APIjudge, read the metrics, then compare two runs properly

    curl -L -X POST https://eli.ai/api/v1/qrels \
      -H "Authorization: Bearer eli_sk_..." \
      -H "Content-Type: application/json" \
      -d '{"queryId":"01K7X...","chunkId":"01K7Y...","grade":3}'   # append-only, 0-3
    
    curl -L https://eli.ai/api/v1/evals/runs/01K7Z.../metrics \
      -H "Authorization: Bearer eli_sk_..."
    # { "retrieval": { "recallAtK", "ndcgAt10", "mrr", ... },
    #   "abstention": { "abstentionRate", "meanTruthfulness", "aurc" },
    #   "errorClasses": {...}, "quality": {...} }
    
    curl -L "https://eli.ai/api/v1/evals/runs/compare?a=01K7Z...&b=01K80...&metric=truthfulness" \
      -H "Authorization: Bearer eli_sk_..."
    # significant only when the 95% bootstrap CI excludes 0 AND p < 0.05

    Reactrun metrics and the policy-decision log

    import { EliQuality, EliPolicyDecisions } from "@eli-ai/react/quality";
    
    <EliQuality initialEvalRunId="01K7Z..." />
    <EliPolicyDecisions surface="chat" verdict="abstain" limit={20} />
  • PortsProgrammatic surfaces

    Ship it

    Reach all of it from durable agents, a versioned API, an MCP server, and a typed SDK.

    API
    /api/v1/agents/{slug}/runs · /api/mcp
    SDK
    @eli-ai/react/agents
    Ports reference

    Inputan agent slug and the run input; the conversation is optional

    POST /api/v1/agents/ops-summary/runs
    
    {
      "input": "Draft the weekly ops summary for the Order Platform.",
      "conversationId": "01K81..."
    }

    APIqueued durably, reattachable — scope agents:run

    curl -L -X POST https://eli.ai/api/v1/agents/ops-summary/runs \
      -H "Authorization: Bearer eli_sk_..." \
      -H "Content-Type: application/json" -d @run.json
    # 202 { "runId": "01K82...", "status": "queued",
    #       "stream": "/api/v1/runs/01K82.../stream" }
    # the run continues on the worker; reattach to the stream at any time
    
    claude mcp add --transport http eli https://eli.ai/api/mcp \
      --header "Authorization: Bearer eli_sk_..."

    Reactstart a run, watch its steps, approve what needs a human

    import { EliAgentRunner, EliRunDetail } from "@eli-ai/react/agents";
    
    <EliAgentRunner initialAgentSlug="ops-summary" canApprove />
    <EliRunDetail runId="01K82..." canCancel />

Executable surface / Ports

One engine, three surfaces.

People use the workspace, applications call the REST API, and agents mount the MCP server. All three execute the same governed pipeline under one workspace-scoped key: structured JSON with both citation registries intact, 92 documented operations with a live console, and a native MCP server — so an external agent can use your knowledge base without a bespoke integration.

Same key, same scopes, same provenance

Applications send POST /api/v1/query. MCP clients connect to /api/mcp and invoke the eli_query tool. Two transports that reach the same governed query pipeline, and get back the same cited answer.

Applications

the typed client — one POST /api/v1/query, key held server-side

// npm install @eli-ai/client
import { createEliClient } from "@eli-ai/client";

const eli = createEliClient({
  baseUrl: "https://eli.ai",
  apiKey: () => process.env.ELI_API_KEY,
});

// one POST /api/v1/query — scope agents:run
const answer = await eli.query.ask({
  question: "Is anything stuck right now?",
  includeData: true,
});
// answer.claims[0].citations -> ["S1", "D1"]
// answer.policy.verdict     -> "answer" | "abstain"

Agents

mount the workspace over streamable HTTP — POST /api/mcp

claude mcp add --transport http eli \
  https://eli.ai/api/mcp \
  --header "Authorization: Bearer eli_sk_..."

# Ten read-only tools — kb_search, kb_graph_query,
# kb_data_lookup, eli_query — under the same key,
# the same scopes, and the same row-level security.

Colophon / start here

Every answer shows its work

Open the hosted workspace and ask it something you can check, or run the quickstart on your own Postgres and two Node processes. Either way, the first cited answer is the test.