Skip to main content

Local-first architecture, summarized

Circinus records where content came from (provenance) and what it may cause (authority), durably, on your machine, before anything asynchronous happens. While the agent keeps working, cheap-tier semantic analysis runs in the background — ahead of any sensitive action — and only escalates to a stronger analysis tier when needed. When the agent then attempts a sensitive action, a fast synchronous local gate reads that already-computed evidence plus a deterministic policy from a local SQLite database — no network call, no remote database round trip — and returns ALLOW, REVIEW, or BLOCK with an explanation of which source, which transformation, and which rule drove the decision.

The invariant this exists to defend: transformation must never silently expand authority. An artifact's verdict only gates an action it actually influenced, not everything that happens afterward in the same session — a single adverse artifact does not become a session-wide kill switch.

No context leaves your machine unless you configure your own model provider key (BYOK). There is no Circinus-operated service and no account required to run the runtime itself. A telemetry channel exists in code but is disabled by default — nothing is sent unless you explicitly set CIRCINUS_TELEMETRY_ENABLED=true; see Privacy for exactly what it will and will never collect when enabled.

The end-to-end decision path​

Two properties make this shape work:

  • Durable first. The artifact, its provenance, its extracted operands, and its queued analysis task are committed and fsynced in one transaction before any asynchronous work starts. A scheduled sync job is never the primary durability mechanism — nothing the gate later depends on is left to a best-effort write that a crash could lose without trace.
  • Analyze ahead. Analysis runs while the agent works, so the gate is a local read, not a network call. Target: p95 < 10 ms of total user-experienced security overhead — process spawn, IPC, database lookup, and policy evaluation included — with the deep verdict already ready for ≥ 80% of sensitive actions in long coding workflows.

If a verdict is not ready, pending is not permission: reversible actions proceed flagged; irreversible ones wait up to the active security profile's bounded budget and then ask (realtime, balanced, strict) or refuse outright (critical).

An artifact's verdict has a radius, not a session-wide reach

An artifact's verdict gates an action only when that artifact reached the action's arguments through the recorded lineage. This is what the slogan "authority has a radius" means literally: an artifact's radius covers what it actually influenced, not everything that happens after it in time. Without this, one adverse blog post would block every irreversible action for the rest of the session — a session-wide kill switch. Relevance is computed over the recorded lineage, not over timing or similarity.

How lineage is established​

Lineage comes from two mechanisms, always stored distinguishably:

  • observed — Circinus watched the boundary directly: a tool call whose result became an artifact, or an argument that is an artifact it already holds.
  • inferred — a distinctive operand of the argument (URL, hostname, path, IP, opaque token) appears in an ingested artifact. This is exact containment over normalized bytes, compared in a canonical form fixed by the operand's type (hosts lowercased, paths resolved) — no similarity scoring, no model in the loop.
Inferred resolution is a floor, not a guarantee

Inferred resolution is what covers the canonical attack, where the model reads untrusted content into its context and composes an argument from it — a path Circinus never directly observes. It catches the literal case and misses the transformed one: re-encoding, splitting, base64, paraphrase, and homoglyphs all evade it. No claim of general prompt-injection prevention follows from it. See Limitations for what this means in practice.

Evidence is a property of the artifact; the decision is a property of the artifact plus the action plus the policy. This split is what makes analyze-ahead work at all: evidence is identified only by what is knowable at ingestion, so a verdict computed minutes earlier still matches at the gate. What the agent is about to do is combined with that evidence only at decision time — never baked into the evidence itself.

Architecture seams​

Ten seams are mandated by the design. Nine own a module directly; the tenth is a boundary constraint with nothing behind it yet in this MVP.

#SeamModuleNotes
1Claude Code adapter / hookscircinus.adapters.claude_codeThe only agent-host integration in the MVP
2Event / artifact ingestioncircinus.ingestNormalizes what the host emits into artifacts
3Provenance + authority modelcircinus.domainDepends on nothing else
4Durable local persistencecircinus.persistenceSQLite, WAL, synchronous=FULL
5Deterministic policy enginecircinus.policyReproducible decisions, no model in the loop
6Semantic analyzer / providerscircinus.analysis, circinus.providersModel-backed judgement, pluggable, BYOK
7Adaptive routingcircinus.routingDecides when the expensive semantic path is worth invoking
8Action-boundary decision enginecircinus.gateAllow / Review / Block at the moment of action
9Explanation / CLIcircinus.cliWhy a decision was made, in terms a human can audit
10Sync / control-plane boundary(none)A constraint, not a module — see below

circinus.daemon hosts seams 2–9: it owns the unix socket, the worker pool, and the single database writer.

The tenth seam — an optional later sync / control-plane boundary — is a constraint, not a module: no circinus.sync package exists in this MVP, and the only obligation it imposes today is that the event log stays append-only and exportable.

Dependency direction is inward — adapters, CLI, and daemon depend on application modules, which depend on circinus.domain, which depends on nothing. Domain policy must not depend on Claude Code's JSON or hook formats.

Process shape​

With no provider key configured, nothing leaves the machine and Circinus runs deterministic-only analysis, and says so in circinus doctor.

What this MVP deliberately is not​

No SaaS control plane, no SSO/RBAC, no SIEM export, no Kubernetes, no graph database, no policy DSL or policy UI, no multi-framework adapters, no model training, no dashboard, no reputation network. Enforcement covers exactly the tool calls that traverse the PreToolUse matcher set — Circinus is a boundary enforcer, not a sandbox.

See Limitations for the concrete, current-build version of this list.