Agents
Three agents run in the application, one per agent step of the workflow, each a stateless function from versioned artefacts to a proposal — never to the record.
| Role | Step | In | Out |
|---|---|---|---|
requirements |
Draft the requirements | the brief and the source profiles | structured requirements with gradeable criteria |
modelling |
Design the data model | the scoped sources' profiles and the shared model | a Data Vault design: the shared layer and the product on top |
contract |
Data contract v0.1, and the data contract | the requirements, the model, the glossary | a v0.1 section per source system; then the draft contract |
Two more role files exist and are not wired to a step yet: review (a failed
validation run in, a proposed revision and blame out) and sql.
They live in dpf/roles/*.md with frontmatter and a playbook — the house rules,
kept separate because that is the part a data team actually edits and its diff should be
readable on its own. On startup, any file whose hash is not registered becomes a new
agent_versions row; old versions are never touched.
On reproducibility. A model is not bit-reproducible and no amount of version control makes it one. It does not need to be, because of where the deterministic boundary sits: agents produce specifications, and specifications compile to code deterministically. So "run it back" means pinned agent version, pinned inputs, re-run, and diff the proposal against the one that shipped. The code was never the unreproducible part.
What reaches the model
Three agents send text to Anthropic. DPF_LLM_DATA decides what:
| What is sent | ||
|---|---|---|
full |
Profiles, six sample rows per scoped table, and each column's smallest and largest value. | the default, and what a laptop demo wants |
metadata |
Column names, types, null rates, distinct counts, candidate keys. No value from any row. | what a deployment should set |
off |
Nothing. The agents are unavailable and every document is written by hand. |
metadata is not "send less" — it is a promise about a category, enforced in the
one function that gathers grounding, and allow-listed rather than deny-listed so
that a statistic the profiler starts reporting tomorrow is left out rather than
shipped. It costs something real: without sample rows the agent is materially
worse at noticing that a column holds two spellings of the same status. That is a
trade the customer should make, which is why it is configuration.
The prompt, the response, the model and the token cost of every call are written
to llm_calls before the result is returned, and the mode in force is stated on
the Connections page.