Architecture
cairn is built around a strict one-way dependency: a domain-neutral engine plus packs that carry all domain knowledge. The engine never imports a pack.
Three layers
Section titled “Three layers”| Layer | What it holds | Example |
|---|---|---|
| Pack | intent — templates, skills, policies, and descriptors for a domain | the training pack’s finetune template |
| Profile | technology choices — which provider backs each capability ([profile.bindings]) | bind storage.put to S3 or to local disk |
| Environment | glue — secrets, endpoints, and per-deployment env vars | OPENAI_API_KEY, GPU/backend URLs |
A pack declares what it needs (a capability); a profile decides which provider satisfies it; the environment supplies the credentials. The same pack runs against different backends by changing the profile, with no code change.
Pack kinds and tiers
Section titled “Pack kinds and tiers”Packs are classified on two axes:
- kind —
domain(a multi-step workflow for a domain, e.g. fine-tuning or incident response),operator(executes a workflow node — a GPU job, an eval, a registry push), orservice_provider(backs a cross-cutting service like memory, RAG, redaction, artifact storage, or audit). - trust tier —
builtin(engine substrate) orofficial(first-party add-ons); community/private/local packs install as separate wheels and are sandboxed by trust level.
On disk this is kind-first: operators live under operators/{builtins,official}/,
domain packs under packs/. An operator is referenced everywhere by its stable
capability name — never by its tier or path — so moving it between tiers is a
metadata change, not a code change. Any operator that satisfies the contract
inherits the budget, policy gate, and audit automatically.
Engine subsystems
Section titled “Engine subsystems”- engine — template schema, compiler, and runner. Templates come in three
flow types:
prompt,agent_loop, andstate_machine. - dispatch — realtime and background lanes, deduplication, the scheduler, and the bus bridge.
- guards — citation validation and capped self-critique.
- actions — the executor registry plus in-process and durable handlers.
- runtime — checkpointer tiers and the durable runtimes:
in_process,dbos(SQLite or Postgres, library — no server), andtemporal(scale/HA). - storage — run store, memory, and RAG-catalog tiers (in-memory / SQLite / Postgres).
- llm / obs — the LLM gateway chokepoint and the cost / events / redaction / audit seams.
- pack — the pack contract, the entry-point loader, the registry, and profiles.
Request lifecycle
Section titled “Request lifecycle”flowchart LR T[Trigger: webhook / schedule / manual] --> SK[Skill match] SK --> TMPL[Template compiled to a graph] TMPL --> RUN[Run: LLM gateway + tools] RUN --> G[Guards: citation validation + budget] G --> POL[Policy gate] POL -->|low risk| EX[Executor] POL -->|high risk| HITL[Human approval] HITL --> EX EX --> STORE[Run + events stored, audit recorded]
A trigger is matched to a skill, which binds it to a template. The template compiles to a graph and runs through the LLM gateway with the pack’s tools. Guards verify the output, the budget is enforced, the policy gate decides whether an action may run automatically or needs human approval, and the run, its events, and the audit record are persisted.
Further reading
Section titled “Further reading”The internal decision record — architecture decisions (ADRs), the live roadmap,
and probe-backed status — lives in the repository’s docs/ tree. This site
documents the shipped, externally-facing surface only.