Hard state for AI agents: typed, governed, durable state with deterministic queries, governed writes, and receipts.
Project description
Cruxible
Cruxible is hard state for AI agents — a typed, verifiable state layer that teams of agents and humans operate together. Work compounds into a record of what you've determined to be true: every claim reviewed and linked to its evidence. When the expensive question arrives (which assets are exposed? what breaks downstream? is this authority still good law?), the answer is computed over established truth, not guessed from a pile of context.
You model your domain in a Terraform-like config: entity and relationship types, deterministic workflows, write rules. The runtime enforces it.
-
State enters deterministically. Exports and tables from real systems are pinned as artifacts and matched row by row into proposals; model judgment is injected only where your pinned domain logic can't decide.
-
Writes are governed. Governed relationships can only be written through a proposal flow that requires declared evidence, auto-resolves only under trust rules you set, and routes everything else to human review. Every accepted claim is attributed and carries a receipt.
-
The model is executable. Recurring procedures are declared workflows in the same config: previewed before they apply, locked to the exact provider code and artifacts they compile against, replayable from receipts. State accumulates as the exhaust of governed work, and the model improves iteratively: feedback and outcomes are recorded in state, and the config evolves like code.
-
Reads are reproducible. Same query, same state, same result, with a receipt explaining how it was derived. Queries express structure that retrieval can't: multi-hop traversals, review status, staleness against cited sources.
-
The core is deterministic. No LLM inside, no hidden API calls. It works with any agent or harness, points at your existing systems, and mints into state only the claims worth coordinating around.
Get Started
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 CLAUDE.md pile 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
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.
Why Not Markdown, RAG, Or Vector Memory?
Markdown, retrieval, and vector memory hand a model raw text, so every session it reconstructs what's true from scratch. For drafts, exploration, and one-off questions, that's fine — but for the claims that are recurring, shared, and expensive to get wrong, every fresh read re-rolls the reconstruction, and a better model reads better, but it cannot certify its own output. Cruxible's answer is to model the domain instead of engineering the context: the durable slice of what's true becomes typed, governed state, read instead of reconstructed. What changes:
| Markdown · RAG · vector memory | Cruxible |
|---|---|
| A claim is just text: no source, no review state | Claims carry provenance and review state; evidence-gated writes refuse references that don't dereference to content-hash-verified source chunks |
| Anything can be edited; nothing enforces what may change | Writes pass typed validation, guards, review, and lifecycle rules |
| Retrieval returns similar chunks; it can't follow exact links | Multi-hop traversal over typed relationships, with visibility rules applied at every hop |
| Counts and rollups are approximate summaries | Exact, repeatable counts and joins as deterministic workflow steps |
| Each read is fresh and can disagree with the last | One accepted state: the same answer for every agent and app |
| Freshness is unknowable: nothing says which chunks have gone stale | Claims cite dated, content-hashed sources; staleness is a queryable property, not a vibe |
| A correction is just more text; nothing ties it to the claim it corrects | Feedback and outcomes attach to the specific claim, decision, or workflow result as typed, queryable signal |
| Static text that doesn't improve from use | Claims mature from proposed to accepted; the ontology iterates with use |
| A better model reads better, but can't certify its own output | Guarantees come from a deterministic layer outside the model |
Markdown and retrieval remain the right tools for most text, and Cruxible
itself cites markdown chunks as source evidence. Version control narrows the
gap less than it seems: git reviews the diff, not the claim — nothing types
what a changed line asserts or refuses an edit that drops its evidence. And
nobody hand-tends this state: it accumulates as the exhaust of governed
work, not as a wiki someone has to maintain. If you already have the wiki
(a pile of CLAUDE.md files, a memory bank, an Obsidian vault), the
wiki-to-state
skill converts it: pages become pinned evidence, an agent proposes the typed
claims, and you review what gets minted. The wiki survives as the source of
record; the graph becomes accountable to it.
What A Governed Domain Looks Like
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: nothing
may write it directly, not even a workflow. 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 --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
With the facts ingested and the impact claim approved, an agent (or app) can ask for the blast radius of the incident (the components exposed through its impacted suppliers) without scanning spreadsheets or tracing the bill of materials by hand:
cruxible query run components_exposed_by_incident \
--param incident_id=INC-42 \
--json
Results come back with a receipt: the deterministic path from query parameters to traversed edges to returned rows.
{
"items": [
{ "entity_type": "Component", "entity_id": "component-main-board" }
],
"receipt_id": "RCP-...",
"receipt": {
"operation_type": "query",
"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.
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.
Governance
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 | Candidates are grouped under one thesis with signal evidence and routed to a human or auto-resolution policy; approval writes accepted state with provenance, 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, gated on review. Each kit README renders its declared guards as a generated table (agent-operation's).
Workflows And Pinned Providers
Workflows orchestrate reads, providers, shaping, and writes as one declared,
reproducible procedure. Providers are the building blocks workflows call:
deterministic transforms and data loaders in Python, over HTTP, or as
commands. They are pinned, not trusted. The kit lockfile
(cruxible.lock.yaml) records each provider's version, content digest, and
declared side effects, and every call leaves an execution trace, so runs
replay deterministically.
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.
Domain State And Operating State
Cruxible models two kinds of state, strongest together.
Domain state is the durable model of the world an agent reasons about: assets, vulnerabilities, suppliers, products, cases, controls, policies, risks. It answers what is true, proposed, reviewed, or constrained. Which assets are exposed to a known exploited vulnerability? Which supplier incident affects which products and shipments?
Agent operating state is the durable coordination layer for the work itself: work items, review requests, decisions, open questions, risks, actors, dependencies, lineage. It tracks 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, decisions, and reviews around it. Typed operation-to-domain edges
(or SubjectRefs across instances) compose them into one queryable graph.
This is the type map of the supply-chain instance from the walkthrough above
— the agent-operation base layer composed under the domain overlay, every
relationship type carrying its live edge count:
State That Compounds
Knowledge shouldn't be wiped out by a context refresh, a model swap, or a handoff. Three loops make the state improve with use:
- Feedback and outcomes. Corrections, missing context, and policy gaps are recorded as feedback; outcomes record whether a decision or workflow result was later correct, incorrect, partial, or unknown. Repeated bad outcomes generate trust-demotion suggestions on the paths that produced them.
- Governed proposals. Uncertain relationships are proposed, reviewed, and accepted or rejected with provenance; resolution paths carry an explicit trust status.
- Config iteration. The ontology itself is refined as it's used (new entity types, relationships, guards, and queries), so the model of the domain matures alongside the data.
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.
Kits
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. The KEV pair runs the whole loop on real CISA data (KEV guide); supply-chain-blast-radius is the walkthrough above.
| 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. |
Agent Setup
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=1keeps the agent on the daemon path.CRUXIBLE_SERVER_STATE_DIRlives 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.
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.
Documentation
Getting started
- Quickstart — install to first query
- Concepts — architecture and primitives
Modeling and authoring
- Modeling State — designing an ontology (entities, relationships, gates vs flags)
- Config Reference — the YAML config schema
- Kit Authoring — kit manifest, structure, and packaging
- Kit Walkthroughs — building standalone and overlay kits
- Common Providers And Dataflow Steps — provider and workflow building blocks
Reference
- CLI Reference — terminal commands
- MCP Tools Reference — agent tool surface
- AI Agent Guide — orchestration patterns
Operating and deploying
- Inspection UI — the read-only console in the screenshots above: state graph, review groups, workflows, traces, receipts
- Local State And Backups — SQLite, daemon state, and portability
- Runtime Auth And Agent Roles — credentials, permission tiers, and bootstrap
- State Resolution And Maintenance — proposal resolution, trust grading, and maintenance signals
- Publishing And Subscribing To States — build, publish, and track reference state releases
- Isolated Deployment — running the daemon with only the client/MCP surface exposed
- Hosted Runtime Image — the runtime container image
Guides
- KEV Guide — subscribe to the vulnerability reference, judge your exposures, work the queue
Agent skills (skills/)
- prepare-data — profile and ready raw exports before modeling
- create-state — staged graph, workflow, query, and review-loop design from your data
- review-state — audit and harden a drafted state model
- overlay-and-fit — compose and adapt overlay kits
- wiki-to-state — convert a CLAUDE.md pile or Obsidian vault into governed state
- classification-at-scale — classify a catalog against a taxonomy with signals, batch review, and a trust flywheel
Kit-specific skills ship inside their kits (e.g. kev-start and kev-triage
in kev-triage, review-thread in agent-operation).
Technology
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.
License
Apache 2.0
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cruxible-0.2.0.tar.gz.
File metadata
- Download URL: cruxible-0.2.0.tar.gz
- Upload date:
- Size: 7.6 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cc3bc4f7dbbefa6efea347aa52286e71e4f51dcad585066692f44192f40b9ab4
|
|
| MD5 |
5a2d6817ed4a06d816730d0b1a55e4ac
|
|
| BLAKE2b-256 |
6d102241aad5f1e64ca8bc429f87b9c8db86b454df203f521f2e717a89ce2026
|
Provenance
The following attestation bundles were made for cruxible-0.2.0.tar.gz:
Publisher:
publish.yml on cruxible-ai/cruxible
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cruxible-0.2.0.tar.gz -
Subject digest:
cc3bc4f7dbbefa6efea347aa52286e71e4f51dcad585066692f44192f40b9ab4 - Sigstore transparency entry: 2116559645
- Sigstore integration time:
-
Permalink:
cruxible-ai/cruxible@2f84ee6286d4d9973c00c3a8ead30c6fb84ac8c4 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/cruxible-ai
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2f84ee6286d4d9973c00c3a8ead30c6fb84ac8c4 -
Trigger Event:
push
-
Statement type:
File details
Details for the file cruxible-0.2.0-py3-none-any.whl.
File metadata
- Download URL: cruxible-0.2.0-py3-none-any.whl
- Upload date:
- Size: 625.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
08ad836e70b09838ec4f757878898e1983c632957b63dc93e8960876d39a51f3
|
|
| MD5 |
c338c1e3481e9ed9af8f0b08f0c44240
|
|
| BLAKE2b-256 |
5b8d72e6532670a97433f3d87393191abe6346224a63167a0f6b54366cc441b3
|
Provenance
The following attestation bundles were made for cruxible-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on cruxible-ai/cruxible
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cruxible-0.2.0-py3-none-any.whl -
Subject digest:
08ad836e70b09838ec4f757878898e1983c632957b63dc93e8960876d39a51f3 - Sigstore transparency entry: 2116559708
- Sigstore integration time:
-
Permalink:
cruxible-ai/cruxible@2f84ee6286d4d9973c00c3a8ead30c6fb84ac8c4 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/cruxible-ai
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2f84ee6286d4d9973c00c3a8ead30c6fb84ac8c4 -
Trigger Event:
push
-
Statement type: