Build verifiable data workflows
AI reasoning and planning. Deterministic actions. Full lineage.
Start by , then ask queries about your data.
Architecture
Planning and execution are separate by design.
A model proposes the analysis plan. albirint validates it, runs the calculations against the prepared source data, and records the inputs and outputs of each completed step. The bounded profile sent for planning is described below.
What you connect
- A file you upload
- Your database, read directly
- A server or bucket you own
Inside albirint
One US-East region
- ExtractYour source is read once into a typed snapshot. Credentials are unsealed for that read and are not retained — the analysis engine persists nothing at all.
- PlanA model is asked which actions to run, and in what order. It gets your column names, their types and a bounded profile — never the file or the table itself.
- CheckThe plan is compiled against your real schema before anything runs. One that does not hold is refused rather than improvised.
- RunDeterministic Python does the arithmetic. Every value in a result table is computed here, from your rows.
- RecordEach step stores the artifacts it consumed, the action that ran, and the columns it read and produced.
Claude, on the Anthropic API
Outside albirint, and the planner albirint uses today. Writes the plan; runs nothing, computes nothing.
- Sent
- Column names, their types, and a bounded profile computed from your data — see the ledger below for its exact size
- Returned
- A proposed plan: which actions to run, and in what order
What you get back
- A result table you can sort and filter
- CSV, Excel or Parquet export
- Steps — the sources, actions and columns behind it
What the model is given
“Your data never reaches the AI” would be the easier sentence. It would also be false. A bounded profile does — so here is exactly what is in it, and exactly where the line is drawn.
Sent with your question
The shape of your data, plus a bounded look at the values so the plan matches how your data is actually spelled.
- The name and description you gave each source. For a database source that name is the table's own name.
- Your column names and their types.
- Per column: what percentage of values are missing, how many are distinct, and up to five data-quality issue codes with their counts.
- For numbers and dates, the range — the smallest and the largest value, and nothing in between.
- For text, up to five of the most common values with their counts when a column has 30 or fewer distinct ones; otherwise up to three examples, so the model can see the format. Every value truncated to 40 characters.
- All of it computed, by default, from up to the first 5,000 rows of each source.
- Your question, the conversation in this notebook, and a bounded history of earlier steps — each action, its parameters, its one-line summary (which carries counts, such as how many rows a filter kept), and the titles, row counts and column names of recent results.
Never sent
Everything that would make the model a copy of your dataset rather than a reader of its shape.
- Your uploaded file, your table, or the rows a query returned. Nothing is attached to the request — only the profile described on the left.
- Database passwords, keys or connection secrets. They are encrypted at rest and unsealed only for the read they authorise; the plan and its request carry a reference, never a value.
- Who you are. No email and no name reach the model, and the analysis engine has no notion of accounts at all — nothing it could attribute a question to. The one identifier it handles is the numbered storage folder your results are written under, and the model never sees that either.
- Anything from another notebook, or from anyone else's. A request carries only the sources attached to the notebook you are working in.
- The arithmetic. Every value in a result table and every metric is computed by deterministic Python from your rows — the model only chooses which actions run, and a plan that will not compile is refused rather than improvised.
These limits bound size, not sensitivity
The profile holds real values, and that is what buys a plan that fits your data instead of guessing at it — a filter for NA only works if the model can see the column says NA and not North America.
But a bound on how much is not a bound on how revealing. On a very small table the values across its columns can add up to a whole record, and a column with only a few distinct values can have all of them listed. If a field should not be read by a model, mask it or leave it out of the source you connect.
Reads are read-only
A SQL source is opened in a session your own database server marks read-only, before the first statement runs, and the read is a bounded SELECT. albirint writes nothing back unless you build a pipeline and give it a destination — and writing into a table in your own database needs a separate write grant on that source, checked again every time the pipeline runs.
Credentials never travel with the plan
Connector secrets are encrypted at rest, unsealed only for the read they authorise, and kept out of the plan, out of lineage and out of every model request — each of which carries a reference instead.
One region, and what leaves it
Compute, the database and object storage sit in US-East. The database accepts connections from albirint's own host and nothing else; the bucket is private. Two things cross that line: the planning request the ledger above describes, and whatever a pipeline destination you set up sends — to a server, bucket or database of your own, or to an inbox, Slack channel or webhook you named.
Every step is on the record
Each step stores the artifacts it consumed, the action and version that ran, its parameters, and the columns it read and produced. Open Steps on any answer and walk an output back to the source it came from.
Check it yourself, before you connect anything
Load the sample dataset, ask it a question, then open Steps on the answer and read the plan albirint actually ran.
Questions about how your data is handled — hello@albirint.com