How it works

One process, its own PostgreSQL and your app's webhooks. A question goes through a fixed pipeline in which code checks every step that matters.

In short

  • One process with its own PostgreSQL; your app supplies three webhooks.
  • A fixed pipeline: the model plans, code validates and builds the SQL.
  • Your app runs every query; Fidara never holds database credentials.

The process

Fidara runs as one process on one port. It serves the API under /api/fidara/ and the pre-built chat screen at /. It keeps conversations, messages, favorites and shares in its own PostgreSQL. Files that users open in the chat are kept on the server, per user. It calls your app's webhooks and nothing else of yours. One process serves one app, and it holds no call-home code.

PartHoldsOwned by
Fidara processThe pipeline, the SQL emitter, the chat screen and the APIYou run it
Fidara's PostgreSQLConversations, messages, favorites, sharesYou run it
Your app and its databaseThe data, the users, the permissions, the loginYour app

Your app runs every query itself, as the user who asked, and Fidara verifies the user's token with your app on every request. The contract is on Integrate your app.

The pipeline

This is the path of one question. Blue boxes call a language model. Boxes with a solid outline are plain code. Dashed boxes are calls to your app.

  • model call
  • code
  • your app
Fidara pipeline A vertical flow. A question from the chat goes to Triage, Resolve, the catalogue webhook and a router. The router picks a subagent. The retrieval agent runs a plan cache check, Scout, Builder, validate, critique, value match and SQL emit, then calls the query webhook. Components are chosen and the turn is persisted. Steps that call a model are shaded blue. Steps that are plain code have a solid outline. Calls to the app are dashed. Chat in your app (iframe) Triage chat, decline, refuse end here Resolve new, refine, or about the last result Catalogue app webhook: this user's tables and scope Route to a subagent code, no model retrieval refine guide write records Retrieval agent (default) Plan cache hit: stored plan, scope re-injected Scout picks tables; up to 6 rounds in all Builder writes the query as JSON, never SQL Validate tables, columns, joins, aliases, fan-out Critique only for joins with aggregations Value match maps a typed name to the stored one SQL emit parameterised SQL, scope added by code Query webhook your app runs it, returns rows Components table, chart, card, pivot, report: by code Persist every path ends here; status is set
  1. Triage. A small model call, made before the catalogue is fetched. Chat, a decline or a refusal is answered right here. A refusal uses a fixed template, never model text. Anything else is passed on.
  2. Resolve. Decides whether the message refers to an earlier answer. A new question is rewritten as a standalone question. A question about the last result is answered from that result, with no query. A change to one earlier answer goes to Refine.
  3. Catalogue. One call to your app: the tables, columns, row scope, denied columns and business defaults for this user.
  4. Route to a subagent. Plain code. The routing table is generated from the subagent registry, and an unknown target falls back to retrieval.
  5. Retrieval. The default agent.
    • Plan cache: a stored plan for the same question is re-run, with the scope injected again.
    • Scout chooses the tables, for up to six rounds. Builder writes the query as JSON.
    • Validate checks the JSON with code. Critique is a second model opinion, run only when a query has both joins and aggregations. A failure goes back to Scout. All retries share one budget of six rounds.
    • Value match maps a typed name to the stored one. SQL emit builds parameterized SQL, adds the scope and strips denied columns. Then the query webhook runs it.
  6. Components. Code picks how the rows are shown: table, chart, stat card, detail card, timeline, pivot, heatmap, dashboard, plain text, clarification or report.
  7. Persist. Every path ends here. The turn gets a status: success, ambiguous, refused, unavailable, unsure or error. Suggested follow-up questions are fetched after the answer is shown, so they add no wait.

The diagram shows the retrieval agent in full. The other agents are routed from the same table and end in the same persist step. The next section lists them.

The agents

Each agent has a declared set of capabilities and nothing else. The router picks one agent per turn. Five are registered in the code: retrieval, refine, guide, write and records. Deep Research is started from its own switch in the chat. Plug-in agents can be added through entry points.

AgentWhat it doesWhat it may not do
RetrievalChooses tables, builds and runs a validated query plan, shows tables, charts and cards, asks a clarifying question.Write SQL. See anything outside the user's scope.
RefineAnswers a follow-up that filters, regroups or ranks an earlier answer. It edits that answer's stored query plan with a small set of declared operations, then runs it through the normal validate, emit and execute path.Add tables outside the catalogue. Write SQL.
GuideReads the user's own screen through the page script and says where to click. It can press the app's own menu item to take the user to a screen.Answer about the data. Fill or press anything else. It needs a web app.
RecordsMaps an attached spreadsheet to the app's fields, matches rows to live records, fills a column from the app's data, and keeps live sheets.Write a number it did not get from the app. Write anything before the user presses Apply.
WritePrepares a reviewable create or update through an action the app declared.Write without approval. Act outside a declared action. It needs the optional write webhook.
Deep ResearchAnswers a multi-part question with a cited report. It plans sub-topics, queries the data for each, then writes and renders the report. It runs as a background job.Cite what it did not query. Show internal ids in the report.
Plug-insAdd agents and tools through Python entry points.Read data except through the core's scoped path. A plug-in runs in your process, so this is a convention, not a sandbox.
LimitsGuide works only on web apps. In the three ERP adapters, real writes are off by default and must be switched on for a run; the sandbox writes for real. PDF export of a report needs the optional pdf extra and the Pango system library. Deep Research can run sandboxed analysis code over fetched rows.

The code on your side of the webhooks is the adapter. The reference adapters and how to write one are on Integrate your app.

API surface

Everything is mounted under /api/fidara/. Every call carries the user's bearer token, and Fidara verifies it with your app each time. One route sits outside the prefix: GET /share/{token}, which serves a public report link when that setting is switched on.

GroupWhat it covers
/chat, /chat/streamSend a message, with or without streaming
/me, /suggestions, /healthWho the user is, their preferences, starter questions, a health check
/conversations, /messages, /favorites, /pinsStored chats, one answer (paging, follow-ups, feedback, report PDF), saved answers, pinned places
/sharesColleague links that re-run a question in the viewer's own scope
/files, /sheets, /liveFiles kept per user, spreadsheet import and fill, live sheets
/writeApply an approved write
/exportWord and Excel export of an answer
/pageThe bridge Guide uses to read the host page
/adminThe catalogue view, and metrics, funnels and predictions an admin defines