Connects Claude and other MCP clients to Cruxible's deterministic decision engine for running auditable queries over entity graphs. Exposes tools for initializing workspaces, validating YAML configs, ingesting data, executing named queries, and retrieving DAG-based receipts that prove exactly how results were derived. Supports constraint evaluation, feedback loops for approving or rejecting edges, and candidate detection for finding missing relationships. Useful when you need reproducible decision logic with an audit trail, like drug interaction screening, sanctions compliance checks, or threat modeling where the same input must always produce the same output and you need to show your work.
cruxible.ai · quickstart · docs · kits · skills
Cruxible is a governed state engine for AI agents — an ontology-backed alternative to general-purpose agent memory for claims that must be settled, enforced, and auditable. All humans and agents share one typed model of a real domain: every claim is validated against declared rules, judgment calls route through review, and every computed answer carries its receipt. We call it hard state.
In practice it's a Python daemon with a CLI and an MCP server, storing a typed graph in SQLite. You declare your domain's ontology in a Terraform-like YAML config (entity types, relationships, write rules, queries); humans and agents build the graph through governed writes, and named queries traverse it: blast radius, downstream impact, the multi-hop questions similarity retrieval can't follow.
pip install cruxible— the Quickstart goes install to first query; Get Started below runs a seeded demo world in ~3 minutes, no tokens.
Once the config is declared, every mutation and computed query is a receipted CLI or MCP verb: the walkthrough below runs this loop as the actual commands.
There is no LLM inside the engine. Judgment enters only where you saw it (modeling, proposals, review); everything the engine itself does — validate, refuse, record, answer — is deterministic, works with any agent or harness, and lands in a SQLite file you own.
Work compounds into a durable record of what you've determined to be true. When the expensive question arrives — which assets are exposed? what breaks downstream? is this authority still good law? — the answer is computed over that record, not re-derived each session from a pile of raw context.
pip install cruxible
Model your own domain: hand your agent the authoring skills in
skills/
(prepare-data → create-state → review-state) with your exports
(wiki-to-state converts an existing team wiki or Obsidian vault), or
start from Modeling State
and the config template.
Or run the demo — a seeded supply-chain world, ~3 minutes, no tokens
(sandbox writes attribute to a built-in operator identity):
# shell 1 — local sandbox daemon
CRUXIBLE_SERVER_STATE_DIR="$HOME/.cruxible/sandbox" cruxible server start
# shell 2 — kit bundles are fetched from the release and digest-verified
# (agent-operation is the optional agent-ops layer; domain-only works too)
cruxible --server-url http://127.0.0.1:8100 init --kit agent-operation --kit supply-chain-blast-radius
cruxible context connect --server-url http://127.0.0.1:8100 --instance-id <instance-id>
# deterministic ingest: preview, then commit
cruxible run --workflow build_seed_state && cruxible apply --workflow build_seed_state --from-last-preview
cruxible run --workflow ingest_incidents && cruxible apply --workflow ingest_incidents --from-last-preview
# the incident feed can only PROPOSE impact edges; the judgment is yours, on the record
cruxible propose --workflow propose_incident_impacts_supplier
cruxible group list --status pending_review
cruxible group resolve --group <GRP-id> --action approve \
--rationale "Confirmed against supplier geography" --expected-pending-version 1
# receipted answers through the edges you just admitted
cruxible query run open_incident_impacts --json
cruxible query run incident_impacted_suppliers --param incident_id=INC-TW-RAIL-2026-07 --json
When agents join, identity turns on: restart with CRUXIBLE_SERVER_AUTH=true,
claim the bootstrap credential, and mint each agent its own token — every
write is attributed. Details, permission tiers, and hardening:
Quickstart ·
Runtime Auth And Agent Roles.
An LLM can interpret a policy. Cruxible enforces it. Interpretation is sampling: an LLM's compliance is a probability, drawn fresh on every call, however good the model — and storing the policy in memory doesn't change that; remembered text is still interpreted, not enforced. A rule declared in config is an invariant, run at a chokepoint no writer can skip.
| Prompted | Enforced |
|---|---|
| "The agent knows an exposure can't be closed while unremediated" | The write chokepoint refuses the transition until the remediation claim, with its evidence, is linked |
| "The model says these sources support the claim" | The write is refused unless every reference dereferences to a content-hash-verified source chunk |
| "The agent was told not to accept claims it proposed itself" | The guard compares the acting actor against the creation receipt's recorded actor and refuses, including create-as-accepted |
| "The agent remembers the ingest procedure" | The workflow is declared, previewed, and locked to pinned providers; every run leaves a receipt |
Two enforcement directions, one purpose — keeping the shared state a truth layer the rest of your stack can trust:
gates:
merge-review:
kind: git-pre-push
entity_type: ReviewRequest
match_property: change_head
condition: {status: approved}
adapter: {branch_pattern: refs/heads/main}
The first shipped gate kind holds a git repository to its state: one line
in .git/hooks/pre-push, and a push is refused unless every branch merged
into main is pinned by an approved review — fail closed, and mandatory
once the same check is wired where pushes can't skip it (CI, protected
infrastructure). This repository runs on it: the gate refused our own
0.2.2 release push until the review record was corrected in state. We
fixed the state, not the hook.
Judgment stays with the model; the rules run without it.
Where this section ends up: one reviewed judgment — this incident impacts this supplier — and from it, a query walks a recursive bill of materials to name every exposed shipment, five typed hops downstream, with a receipt. Here is how that truth gets built. A minimal slice of a supply-chain ontology, as authored in a kit config:
entity_types:
Supplier:
properties:
supplier_id: { type: string, primary_key: true }
name: { type: string, indexed: true }
primary_geography: { type: string, optional: true }
Component:
properties:
component_id: { type: string, primary_key: true }
name: { type: string, indexed: true }
criticality: { type: string, optional: true, enum_ref: criticality }
Incident:
properties:
incident_id: { type: string, primary_key: true }
title: { type: string, indexed: true }
severity: { type: string, optional: true, enum_ref: incident_severity }
relationships:
- name: supplier_supplies_component
from: Supplier
to: Component
# Governed judgment: an incident materially impacts a supplier.
- name: incident_impacts_supplier
from: Incident
to: Supplier
named_queries:
# Blast radius: from an incident, traverse impacted suppliers to the
# components they supply.
components_exposed_by_incident:
mode: traversal
entry_point: Incident
returns: Component
traversal:
- relationship: incident_impacts_supplier
direction: outgoing
- relationship: supplier_supplies_component
direction: outgoing
The ontology is only part of the config: the same file declares the enum vocabularies, guards, proposal routing, workflows, and providers, so a domain's model, rules, and procedures ship together as one versioned, composable kit.
Nobody types this state in by hand: it enters through the pathways the config declares, and different state earns different treatment.
Hard facts are deterministic ingest. A BOM workflow pins the export as an artifact and matches its rows into suppliers, components, and supply edges, previewed before it commits:
cruxible run --workflow ingest_bom --input-file ./exports/bom-2026-07.csv # preview
cruxible apply --workflow ingest_bom --from-last-preview # commit
incident_impacts_supplier is a judgment call, so it is governed: every
live direct write is refused — CLI, MCP, batch, at any permission tier
(a direct write can at most stage the edge for review). It
enters only through the governed verbs the config declares, and in this
domain that is proposal and review. The incident feed's workflow records
the incidents themselves as hard facts, but the impact edges it can
only propose. Those candidates land in a review group, each carrying the
signals and evidence that matched it:
cruxible propose --workflow propose_incident_impacts_supplier --input-file ./exports/incidents.json
The judgment itself stays with a human, or with an agent when the trust rules you declared allow it. Approval is what mints the edges into accepted state: attributed, rationale on record.
cruxible group list --status pending_review
cruxible group resolve --group GRP-7f3a --action approve \
--rationale "Confirmed: fab flooding halts board shipments" \
--expected-pending-version 1 # pins the decision to the state the reviewer saw
Notice where the judgment went: exactly one edge — does this incident materially impact this supplier? — passed through review. Everything downstream is computation over settled truth: which components those suppliers supply is ingested fact, so the blast radius is a traversal across the two, not another judgment call. An agent (or app) asks the expensive question without re-deciding anything:
cruxible query run components_exposed_by_incident \
--param incident_id=INC-42 \
--json
Results come back carrying a receipt id — the receipt is the deterministic path from query parameters to traversed edges to returned rows:
{
"items": [
{ "entity_type": "Component", "entity_id": "component-main-board" }
],
"receipt_id": "RCP-2f61a90c84d3"
}
cruxible explain --receipt RCP-2f61a90c84d3 --format json
{
"query_name": "components_exposed_by_incident",
"parameters": { "incident_id": "INC-42" },
"nodes": [
{ "node_type": "query", "detail": { "entry_point": "Incident" } },
{ "node_type": "edge_traversal", "relationship": "incident_impacts_supplier" },
{ "node_type": "edge_traversal", "relationship": "supplier_supplies_component" },
{ "node_type": "result", "entity_type": "Component", "entity_id": "component-main-board" }
]
}
Receipts are not logs — they are typed evidence graphs. Mutation receipts record exactly what a write changed, and governed edges carry a reference back to the receipt of the operation that created them. A receipt doesn't prove a claim is true — it records what state, evidence, and rules produced the result; the same query against the same state reproduces it.
And the cascade keeps going, with a sharp line through it: what gets
judged, and what flows. In the full kit, impact judgments stop at
components and assemblies; product and shipment exposure are never judged
at all. incident_exposed_shipments derives them by traversal — walking
the accepted impacts up a recursive bill of materials (assemblies nest
eight levels deep), into the finished products, out to the shipments
carrying them. Downstream truth is computed from upstream judgment, never
asserted alongside it. Overturn one impact edge in review and every
product and shipment answer downstream moves with it, on the next query,
for free.
To run this end to end on the seeded world — the staged cascade, the review seats, the receipted blast radius — follow the supply chain guide.
This is what a pending review group looks like in the inspection UI: the signal matrix, each proposed edge with the evidence that matched it, and the provenance rail tying the proposal back to its workflow, receipts, and provider traces.
Cruxible separates writing state from accepting it. State enters one of two ways:
| Write mode | Use it for | What happens |
|---|---|---|
| Direct write | Asserting hard state: imports, deterministic relationships, source evidence | Live and queryable at once, with evidence when supplied, but unreviewed until a governed process approves it |
| Governed proposal | Judgment calls: uncertain or interpretive relationships | Pending candidates land in a review group under one thesis, each carrying its matching evidence; the group resolves through declared policy, human approval, or an agent with the permission to judge — acceptance mints attributed state, rejection records why |
Guards are declared in config and enforced at a single write chokepoint. A relationship type can refuse direct writes entirely; a work item can be blocked from closing until an approved review is linked; a write can be required to co-create a linked entity in the same unit of work; a claim can be required to carry source evidence. Evidence requirements are enforced, not decorative: the write is refused unless every reference dereferences to a registered source chunk whose content hash matches.
The agent-operation kit ships these live: a work item cannot close without an approved review linked, and a review verdict must co-write its rationale note in the same unit of work, so the work itself is typed state whose guards enforce review. Each kit README renders its declared guards as a generated table (agent-operation's).
Cruxible is built for many writers out of the box. Every writer,
human or agent, acts under its own minted credential at one of four
cumulative permission tiers (read_only ⊂ governed_write ⊂ graph_write
⊂ admin); give each agent the least tier that does its job. Every write
is attributed to the actor that made it, and roles can be separated by
receipt: a guard can require that the actor who created a record is never
the one to approve it, anchored on the creation receipt rather than
anything a writer can forge.
Humans and agents sit in the same loops under the same rules. An agent with the permission to judge resolves review groups exactly as you would, and its approvals are attributed exactly like yours — while every reader, whatever the agent, model, or session, computes the same answer from the same accepted state. Wiring and hardening: Agent Setup.
We spent fifty years keeping the facts that matter in systems with schemas, constraints, and transactions — then handed agents piles of markdown, because prose was the only interface they spoke. Cruxible models the domain instead of engineering the context: the durable slice of what's true becomes typed, governed state — accepted at a point in time, changed only through explicit lifecycle, read back with a receipt. What changes:
| Markdown · RAG · vector memory | Cruxible |
|---|---|
| A claim is prose; nothing refuses one without a source | Evidence-gated writes refuse references that don't verify against content-hashed sources |
| Edits are reviewed as diffs, not claims | Writes pass typed validation, guards, and review |
| Links live in prose, re-inferred on every read | Typed edges, traversed multi-hop, visibility rules at every hop |
| A rollup is a one-off summary | Counts and joins are deterministic, receipted, re-runnable |
| No record of which answer was settled on | One accepted state; the same query returns the same answer for every agent |
| No record of when a source was captured | Sources are dated and hashed; staleness is queryable |
| A correction is just more text | Feedback attaches to the exact claim; claims mature from proposed to accepted |
| A better model reads the pile better | It can't read what was never written; the record and its derivations don't move when you swap models |
The guarantee is a property of the whole write surface: one chokepoint every write passes through, provenance on every claim, evidence that must dereference wherever you require it, answers that re-run the same way from the same state. Assembled from parts — a schema here, a review queue there, an audit column bolted on — every seam between the parts is a bypass.
This is not a second wiki to tend — the state accumulates through the same
loops that use it. And if the wiki already exists (a team wiki, an
Obsidian vault), the
wiki-to-state
skill converts it: pages become pinned evidence, an agent proposes the
typed claims, you review what gets minted.
Workflows orchestrate reads, providers, shaping, and writes as one declared,
reproducible procedure. Providers — deterministic transforms and data
loaders in Python, over HTTP, or as commands — are pinned, not trusted: the
kit lockfile (cruxible.lock.yaml) records each one's version, content
digest, and declared side effects, and every call leaves an execution trace.
Canonical workflows are preview-first:
cruxible run --workflow build_local_state # executes against a clone, returns an apply digest
cruxible apply --workflow build_local_state --from-last-preview
run never touches live state. apply re-verifies the preview's digest
against the current config, lockfile, and head snapshot before committing.
If anything shifted underneath, it refuses. Workflows that produce governed
proposals run through cruxible propose and land in review instead of in
live state.
Declare → preview → apply, with a receipt at every step.
Cruxible models two kinds of state, strongest together.
Domain state is the durable model of the world an agent reasons about — assets, vulnerabilities, suppliers, cases, controls, risks — answering what is true, proposed, reviewed, or constrained:
Agent operating state is the coordination layer for the work itself — work items, review requests, decisions, risks, open questions, actors — tracking what's active or blocked, why, who reviewed it, and what changed. A domain kit models the thing being worked on; an operating-state kit tracks the work around it; typed edges compose them into one queryable graph. The type map of the composed supply-chain instance above:
The one real cost is the config — the types, rules, and queries that model your domain. You don't write it from scratch: point an agent at your data, or an existing wiki, and it drafts the model; you review what it proposes instead of authoring it. The rules are few, static, and reviewed once; the writes they govern are many and continuous — that asymmetry is the point. And the cost keeps paying: knowledge no longer gets wiped out by a context refresh, a model swap, or a handoff, and three loops keep the state current through the same governed work that uses it:
The LLM can change: swap vendors, upgrade, run several at once. What compounds belongs to you. State, evidence, review history, feedback, outcomes, and the ontology itself accumulate in a database you own, portable down to a single file, not in a vendor's weights or a platform's memory. The work agents do becomes your asset.
A kit packages an ontology with its governance, queries, workflows, and providers as one versioned, composable unit. Standalone kits define a full state model; overlay kits compose local state, proposals, and workflows over an upstream base. All seven ship working providers end to end.
Start with agent-operation — the domain-agnostic operating layer Cruxible itself is developed with (guide). The KEV pair runs the whole loop on real CISA data (guide); supply-chain-blast-radius is the walkthrough above (guide); case-law-monitoring is a governed citator in two acts (guide).
| Kit | Kind | What it models |
|---|---|---|
| agent-operation | Agent operating state | Work items, review requests, decisions, risks, open questions, state notes, actors, lifecycle, and dependency context. |
| project-domain | Domain overlay state | Roadmap items, milestones, release lines, and product areas composed over the agent-operation base — the project state Cruxible itself runs on. |
| agent-release | Domain overlay state | Agent systems, versions, eval suites and runs, with governed certification and promotion gates. |
| kev-reference | Domain reference state | Public known-exploited vulnerability reference data. Consumed as a published state release (state create-overlay); init the kit itself only to build offline or publish your own. |
| kev-triage | Domain overlay state | Local asset exposure, service impact, controls, incidents, findings, remediation, and governed vulnerability triage. |
| supply-chain-blast-radius | Domain state | Suppliers, components, assemblies, products, shipments, and incident blast radius. |
| case-law-monitoring | Domain state | Matter-centered case-law monitoring and authority impact. |
pip install cruxible already includes the Python client
(import cruxible_client); add the [mcp] extra for the cruxible-mcp
entrypoint. Nothing else is needed when the agent shares the daemon's
environment.
Mint each agent its own credential (as in Get Started) so every write is attributed to a token, and for stronger isolation prefer a split environment: the daemon runs in its own environment, and the agent's environment installs only the slim client — no runtime, no direct access to state files:
pip install cruxible-client # agent environment only; ~2 dependencies
CRUXIBLE_REQUIRE_SERVER=1 keeps the agent on the daemon path.CRUXIBLE_SERVER_STATE_DIR lives outside the agent's writable workspace.MCP example:
{
"mcpServers": {
"cruxible": {
"command": "cruxible-mcp",
"env": {
"CRUXIBLE_MODE": "governed_write",
"CRUXIBLE_SERVER_URL": "http://127.0.0.1:8100",
"CRUXIBLE_SERVER_BEARER_TOKEN": "<agent-token>"
}
}
}
}
CRUXIBLE_MODE selects one of four cumulative permission tiers —
read_only, governed_write, graph_write, admin — and denied calls name
the tier they need. Give an agent the lowest tier that does its job:
governed_write (above) can run workflows, propose, and record feedback,
but cannot mutate the raw graph or resolve proposals.
MCP is one door, not the only one: an agent can drive the same daemon through the CLI or the Python client, under the same credentials and tiers — Cruxible develops itself with CLI-driven agents.
Local permission modes are a practical hardening layer, not full sandboxing. If trust levels matter, keep the daemon state outside the agent workspace and expose only the client, HTTP, or MCP surface. See Isolated Deployment.
Getting started
Modeling and authoring
Reference
Operating and deploying
Guides
Agent skills (skills/)
Kit-specific skills ship inside their kits (e.g. kev-start and kev-triage
in kev-triage, review-thread in agent-operation).
Cruxible uses Pydantic for validation, NetworkX for in-memory graph operations, Polars for data operations, SQLite for local durable state, FastAPI for the daemon, and FastMCP for MCP tools.
Apache 2.0
CRUXIBLE_MODEPermission mode: admin (default), graph_write, or read_only
CRUXIBLE_ALLOWED_ROOTSComma-separated absolute paths restricting which directories cruxible_init can access