Why Quipu
This page holds the long form that used to open the README: sharing, a tour, the comparison, the full feature list, the architecture and the feature matrix. The README now leads with installing it and a three-command first success (the caboodle-stack README standard).
Sharing & Federation
A Quipu store can hand its knowledge to another store, and compose another store’s knowledge, without either one having to trust the other by default. Every step is explicit, hash-verified, and labelled with where it came from — so you never absorb someone else’s knowledge by accident.
Before exporting, load an identifier-policy catalogue and the shapes governing your data. Outward sharing is the default: a missing block-tier catalogue refuses with exit 2; a matched identifier refuses with exit 1.
quipu share --output ./share # a git-native bundle: facts + shapes + lineage
quipu import ./their-share # verifies hashes, lands in QUARANTINE, not ROOT
quipu import promote <share-id> # a named operator's explicit act
quipu status ./share && quipu merge ./share # diverged? three-way; conflict exits 2
Quipu does not merge on receipt, and it does not take a peer’s word for how
trustworthy that peer is: trust is declared by the local operator, never read from
the member itself. Federated rows carry _provider, _trust and _freshness, and
a partial answer is reported as partial rather than arriving as a short one.
SPARQL SERVICE is supported, restricted to endpoints the operator has configured —
variable endpoints are refused and unconfigured hosts are unreachable. That is narrower
than SPARQL 1.1’s open federation by design, and Quipu makes no SERVICE conformance
claim.
→ Sharing & Federation — the primitive in full, every claim citing the command or symbol that proves it.
Explore this repository’s graph, in your browser
Every release ships a knowledge pack of this repository — its modules, symbols, documents and sections as RDF — and the book has a page that opens it with Quipu itself compiled to WebAssembly. GitHub cannot run scripts in a README, so here is a picture; the page is one click away.
scbrown.github.io/quipu/explore — 61k triples imported and queried in a tab. No server.
It is the receiving half of the sharing story above, running rather than described:
the manifest is verified against the exact payload bytes, the bundled shapes are
adopted as a deliberate act, and the graph is staged and then promoted — the same
share_transport → share_import → promote path quipu import takes, because it is
that code, compiled for a different target. Then you get a SPARQL box, a module and
document browser, a type distribution and a neighbourhood graph, all of it derived from
queries the page will show you. It takes any Quipu pack, not just this one.
And it is not read-only. Add, change or retract facts on any node — through the real
tool_set / tool_retract / tool_episode, the same functions the REST API exposes,
with the closed-vocabulary gate still enforcing what the sender’s shapes allow. The views
update as you go, and you can take the result with you: the edited store exports as a
genuine .qpack.tar.gz, built by the same share_payload the CLI uses and declaring the
pack it came from as its parent. Import it directly with
quipu import <archive> --db your.db to stage it against your database’s loaded shapes;
promotion is a separate step. Without --db, archive verification stays in memory. Or download
export.nt and diff it — it is line-oriented and canonically ordered, so a change is a
reviewable diff.
The bundle is a release asset (quipu-<tag>-wasm.tar.gz), so nothing here is committed
and the Pages build needs no Rust.
See It In Action
The built-in explorer at /ui — the whole graph in one request, drawn on canvas.
Run it yourself with just demo (examples/demo-graph).
$ quipu knot infrastructure.ttl --shapes aegis-schema.ttl --db ops.db
Ingested 847 triples in transaction 1 (SHACL: 0 violations)
$ quipu read "SELECT ?svc ?host WHERE {
?svc a <http://example.org/WebApplication> ;
<http://example.org/runsOn> ?host .
}" --db ops.db
| svc | host |
|-----------|--------|
| gateway | host-a |
| git | host-b |
| metrics | host-a |
3 results
$ quipu episode - --db ops.db <<'JSON'
{"name": "host-b-rebuild", "source": "ops/agent",
"nodes": [{"name": "host-b", "type": "ComputeNode",
"properties": {"status": "recovered"}}],
"edges": [{"source": "host-b", "target": "host-a", "relation": "rebuilt_on"}]}
JSON
Ingested 6 triples in transaction 2
$ quipu unravel --valid-at "2026-03-15T00:00:00Z" --db ops.db
# See the world as it was two weeks ago
$ quipu stats --db ops.db
Facts: 853 | Entities: 127 | Predicates: 34
Why Quipu?
This comparison is a self-assessment, not a measurement. Some cells are contestable (Jena, for example, ships a rule reasoner). For measured numbers, see SPARQL 1.1 conformance, where quipu and other stores are scored by the same harness.
| Jena/Stardog | Graphiti/Mem0 | Quipu | |
|---|---|---|---|
| Strict schema (SHACL) | ✅ | ❌ | ✅ |
| Bitemporal time-travel | ❌ | ❌ | ✅ |
| SPARQL 1.1 | ✅ | ❌ | ✅ |
| Datalog reasoner | ❌ | ❌ | ✅ |
| Counterfactual queries | ❌ | ❌ | ✅ |
| Vector similarity search | ❌ | ✅ | ✅ |
| LanceDB ANN + pushdown | ❌ | ❌ | ✅ |
| Agent-friendly feedback | ❌ | ❌ | ✅ |
| Episode provenance | ❌ | ✅ | ✅ |
| Graph algorithms | ❌ | ❌ | ✅ |
| Built-in web UI | ❌ | ❌ | ✅ |
| Embeddable (no server) | ❌ | ❌ | ✅ |
| SQLite-backed | ❌ | ❌ | ✅ |
| Rust / zero dependencies | ❌ | ❌ | ✅ |
Traditional RDF stores demand too much ceremony. AI-native stores have no structure. Quipu’s thesis: start strict, use agents to bear the cost of strictness.
Features
🏛️ Knowledge Graph Core
- Immutable bitemporal fact log — every fact has transaction time and valid time. Time-travel to any point. Full audit trail. Contradiction detection.
- RDF data model — IRIs, blank nodes, typed literals via oxrdf. Import/export Turtle, N-Triples, JSON-LD, RDF/XML. Exports are stably ordered and can be scoped to ROOT, one named graph, an episode provenance group, or a SPARQL CONSTRUCT result; server exports use the read pool rather than blocking writers.
- Git-native knowledge shares —
quipu sharewrites canonicalexport.nt,shapes.ttl, and a lineage-awaremanifest.json; unchanged graph state produces byte-identical files and stable hashes for meaningful git diffs. Remote consumers use read-onlyPOST /shareto receive that exact manifest and file set without access to the server filesystem. When the store carries block-tierInternalIdentifierPatternrules, the producer refuses matching outbound bytes before publishing anything and never rewrites entity IRIs. - Shape-aware reconnect —
quipu statuspreviews base/ROOT/incoming divergence, whilequipu mergeunions multi-valued RDF and emits structured decisions forsh:maxCountconflicts before any write. - SPARQL 1.1 — SELECT, ASK, CONSTRUCT, DESCRIBE. BGP, JOIN, UNION, FILTER, OPTIONAL, VALUES, ORDER BY, GROUP BY, aggregates, HAVING, property paths,
IN/NOT IN, RDFS subclass inference, and named-graph scoping (GRAPH,FROM,FROM NAMED). - SHACL validation — strict schema enforcement at write time. Structured feedback with severity, focus node, component, path, and message.
- Graph labels & kinds — graphs carry declared labels on five axes (freshness, trust, policy, durability,
dataKind); datasets compose them without ever widening, and every query answer reports the composed label. Opt-in floors can refuse queries that fall below a declared bar. - Deep freeze — relocate a graph’s full history into a verified read-only archive pack (
quipu graph freeze). The graph keeps its IRI and stays queryable — by name, via theurn:quipu:dataset:frozendataset, or byinclude_kinds: ["archive"]on a query;quipu graph thawrestores it for writes.GET /graphslists every registered graph with kind and lifecycle.
🤖 AI-Native Features
- Episode ingestion — structured write path for agent-extracted knowledge. Typed nodes, edges, and provenance tracking (
prov:wasGeneratedBy). A node name may appear only once per episode: repeated entries are rejected before any triples are written, since merging them would silently append a second description to the same entity. - Hybrid search — SPARQL filters candidates, vector similarity ranks them. Combine structured queries with semantic meaning in one call. Type constraints are pushed down into the vector index for O(log n) filtered search with LanceDB.
- Dual vector backends — default SQLite (brute-force cosine similarity), plus a LanceDB backend (ANN with predicate pushdown, Arrow columnar storage) behind
--features lancedb.vector.backendin config selects it in-binary: the CLI and server install the configured backend at open, so choosing LanceDB no longer requires an embedder to callStore::set_local_vector_backendby hand. - Context pipeline — unified knowledge context shaped for agent consumption. Text search + link expansion with configurable depth and budget.
- Agent-friendly feedback — validation errors include what failed, where, why, and what the valid alternatives are.
🧠 Reasoning Engine
- Datalog over EAVT — forward-chaining rules in Turtle DSL, evaluated by
datafrogwith semi-naive fixpoint. Supports stratified negation-as-failure; variables in negated atoms must be bound by positive atoms, and negation cycles are rejected. Derived facts are first-class triples with provenance. - Reactive evaluation —
TransactObserverre-runs affected rules on every write. Delta-aware: only changed predicates trigger re-evaluation. Behind the non-defaultreactive-reasonerfeature;reason --reactiveerrors without it. - Counterfactual queries —
Store::speculate()forks a hypothetical view via SQLite SAVEPOINT. Answer “what if we remove X?” without mutation. - Impact analysis — BFS walk over entity edges with configurable depth and predicate filters. CLI (
quipu impact), REST (POST /impact), and MCP tool.
⚙️ Infrastructure
-
Git-native composition —
quipu import <share-dir>verifies the v1 manifest and payload hashes, resolves exact entity matches, surfaces fuzzy candidates for review, validates against local SHACL shapes, and stages each source in a named graph. Off-vocabulary or non-conforming shares remain quarantined; onlyquipu import promote <share-id>explicitly admits an eligible graph to ROOT. -
Graph projection — materialize subgraphs into petgraph for centrality, connected components, shortest path algorithms.
-
Federation — a
GraphProvidertrait for multi-source queries, with aRemoteProvider(behind theremotefeature) built fromfederation.remotesconfig. The server health-checks every configured remote at startup, andPOST /querywith"federated": truefans out through the federated provider, reporting which members answered. Remotes carry declared trust labels at the federation edge, so a federated answer composes the labels of every member that contributed rather than silently inheriting the caller’s. Federation config is read-side only: adding a remote never turns it into an outbound replication target or bypasses the share scrub/import boundary. -
Graph explorer — the web UI draws the whole node-link view from a single
POST /graphpayload (nodes plus index-addressed edges), laid out with a Barnes-Hut force simulation on canvas. No CDN, so it renders on an air-gapped deploy. -
Four interfaces — Rust crate (embed), CLI (
quipu), REST API (quipu-server), and built-in web UI with embeddable web components. Plus 46 MCP tools for agent integration (48 with theowlfeature). -
“SQLite energy” — single process, no server required, inspect with
sqlite3, back up withcp. -
Automated releases — release-plz bumps versions from conventional commits, generates changelogs via git-cliff, and creates GitHub releases. Version discovery is
git_only = true: the baseline comes from this repository’s tags, never the unrelatedquipucrate on crates.io. CI runs fmt, clippy, tests, and markdown lint on every push./versionalso reports the deployed git SHA, which matters because a deployment can legitimately sit AHEAD of the newest tag — the SHA, not the version string, identifies what is actually running.
Tour: the library, the CLI, the server and the reasoner
As a Rust Library
[dependencies]
quipu = { git = "https://github.com/scbrown/quipu" }
#![allow(unused)]
fn main() {
use quipu::store::Store;
use quipu::rdf::ingest_rdf;
use quipu::sparql;
use oxrdfio::RdfFormat;
let mut store = Store::open_in_memory()?;
let turtle = r#"
@prefix ex: <http://example.org/> .
ex:alice a ex:Person ; ex:name "Alice" ; ex:knows ex:bob .
ex:bob a ex:Person ; ex:name "Bob" .
"#;
ingest_rdf(&mut store, turtle.as_bytes(), RdfFormat::Turtle,
None, "2026-04-04", None, None)?;
let result = sparql::query(&store,
"SELECT ?name WHERE { ?s a <http://example.org/Person> . ?s <http://example.org/name> ?name }")?;
}
From the Command Line
git clone https://github.com/scbrown/quipu && cd quipu
cargo build --release
# Load, query, explore
quipu knot data.ttl --db my.db
quipu read "SELECT ?s ?p ?o WHERE { ?s ?p ?o } LIMIT 10" --db my.db
quipu repl --db my.db
# Governance: check an agent's enforcement trace against the policy set
quipu audit trace.jsonl --db my.db # T ⊨ Σ — exits 1 on a violation
quipu audit inventory --db my.db # which tool classes are ungoverned
quipu audit namespace --db my.db # which minted predicates no shape mentions
quipu audit replay trace.jsonl --db my.db # advise → enforce readiness, per rule
REST API & Web UI
# quipu-server needs `onnx` (the embedding runtime) AND `server` (axum/tokio —
# the HTTP stack is feature-gated so the library does not carry a web server).
# Neither is on by default, and an unmet required-feature SKIPS the binary
# silently rather than erroring, so build the `full` bundle releases ship:
cargo build --release --features full
quipu-server --db my.db --bind 0.0.0.0:3030
# Open the interactive graph explorer in your browser
open http://localhost:3030
# Or use the REST API directly
curl localhost:3030/query -X POST \
-H "Content-Type: application/json" \
-d '{"query": "SELECT ?s ?p ?o WHERE { ?s ?p ?o } LIMIT 5"}'
The built-in web UI provides:
- Graph Explorer — force-directed visualization with type-based coloring, entity search, and detail panel
- SPARQL Workbench — syntax-highlighted editor with time-travel parameters and tabular/JSON results
- Episode Timeline — chronological view of ingested episodes with extracted entities
- Schema Inspector — type distribution, SHACL shape browser, and validation runner
Embeddable web components (<quipu-graph>, <quipu-sparql>, <quipu-entity>, <quipu-timeline>, <quipu-schema>) let you drop Quipu panels into any page:
<script src="http://localhost:3030/quipu-components.js"></script>
<quipu-graph endpoint="http://localhost:3030"></quipu-graph>
Semantic Web APIs for interoperability:
- Spotlight — entity recognition/disambiguation (
POST /spotlight) - Triple Pattern Fragments — LDF-compatible pagination (
GET /fragments) - OpenRefine Reconciliation — data cleaning integration (
POST /reconcile) - Content Negotiation —
GET /entity/{iri}returns JSON-LD, Turtle, or HTML based on Accept header
Reasoner
# Impact analysis — what depends on this entity?
quipu impact http://example.org/gateway --db ops.db
# Counterfactual — what breaks if we remove it?
quipu impact http://example.org/gateway --remove --db ops.db
# Run Datalog rules over the fact log
quipu reason --rules rules.ttl --db ops.db
The reasoner adds forward-chaining inference over the EAVT fact log:
- Datalog rule engine — rules written in Turtle DSL, evaluated with semi-naive
datafrog. Supports stratified negation-as-failure over materialized facts, including derived predicates from lower strata; unsafe negation and negation cycles are rejected. Derived facts written back viaStore::transact()with full provenance. - Reactive evaluation —
TransactObserverkeeps derived facts fresh as base facts change. Delta-aware: only affected rules re-run. Optionalreactive-reasonerfeature. - Counterfactual queries —
Store::speculate()forks a view (SQLite SAVEPOINT) to answer “what if?” without mutation. - Impact analysis — BFS walk over entity edges with configurable hop depth and predicate filters. Available as CLI, REST endpoint (
POST /impact), and MCP tool.
Architecture
┌──────────────────────────────┐
│ Agent / CLI / Bobbin │
└──────────┬───────────────────┘
│
┌────────────────┼────────────────┐
│ │ │
┌─────┴─────┐ ┌─────┴─────┐ ┌──────┴──────┐
│ MCP Tools │ │ REST API │ │ Rust API │
│ (46 tools) │ │ + Web UI │ │ (crate) │
└─────┬─────┘ └─────┬─────┘ └──────┬──────┘
└────────────────┼────────────────┘
│
┌─────────────────────────┼─────────────────────────┐
│ │ │
┌────┴────┐ ┌────┴─────┐ ┌──┴───────┐ ┌──────────────┴──────────────┐
│ SPARQL │ │ SHACL │ │ Reasoner │ │ KnowledgeVectorStore │
│ Engine │ │ Validator│ │ (Datalog)│ │ (trait) │
└────┬────┘ └────┬─────┘ └──┬───────┘ └──────┬─────────┬───────────┘
│ │ │ │ │
└─────┬───────┴───────────┘ ┌──────┴───┐ ┌───┴──────┐
│ │ SQLite │ │ LanceDB │
│ │ (default)│ │(optional)│
┌─────┴──────────────┐ └──────────┘ └──────────┘
│ EAVT Fact Log │
│ (SQLite) │
│ │
│ facts + terms + │
│ shapes + rules │
└────────────────────┘
Bobbin Integration
Quipu is designed as a Bobbin subsystem. Bobbin holds the thread (code context); Quipu ties knots of structured meaning into it.
When running as a Bobbin subsystem, agents get 46 MCP tools (48 with the
owl feature). The two most
commonly used for knowledge-aware context:
quipu_context — unified knowledge discovery. Bobbin merges the result
with its own code search to give agents both code and knowledge in one response.
{
"tool": "quipu_context",
"input": { "query": "gateway reverse proxy", "max_entities": 10 }
}
// Returns ranked entities with facts, types, and relevance scores
quipu_episode — save agent-extracted structured knowledge with full
provenance tracking.
{
"tool": "quipu_episode",
"input": {
"name": "deploy-v3",
"source": "aegis/ellie",
"nodes": [{"name": "gateway", "type": "WebApplication",
"properties": {"version": "3.0"}}],
"edges": [{"source": "gateway", "target": "host-a", "relation": "runs_on"}]
}
}
Embeddings are shared: Bobbin’s ONNX pipeline (all-MiniLM-L6-v2) provides
384-dimensional vectors to both its code search and Quipu’s knowledge search,
enabling hybrid queries that span both domains.
Agent access
When Quipu MCP tools are configured, agents should use them first so structured
inputs, validation feedback, and provenance stay in the tool contract. Use the
native quipu CLI second for local databases and offline work. Raw HTTP is the
portability fallback; endpoint shapes and authentication are in the
REST API reference.
Named graphs are first-class query scopes, and named datasets are reusable sets
of graphs. ROOT remains the default until a caller explicitly selects a graph or
dataset with SPARQL FROM / FROM NAMED, the query graph field, or
the query tool’s graph field. This permits an application to ground a request in
one declared plane without silently widening into every graph. See
Named Graphs for the registration,
write, and trust-label rules.
Feature Matrix
Legend: ✅ available in the shipped quipu CLI / quipu-server · 🔩 library
primitive only, not reachable from the shipped binaries · 🔜 planned.
| Feature | Status | Notes |
|---|---|---|
| Core | ||
| EAVT bitemporal fact log | ✅ | Immutable, time-travel queries |
| RDF data model (oxrdf) | ✅ | Turtle, N-Triples, JSON-LD, RDF/XML |
| SQLite storage | ✅ | Single-file, embeddable |
| Retraction with valid-time closure | ✅ | |
| Graph labels (5-axis lattice + floors) | ✅ | freshness / trust / policy / durability / dataKind; composition never widens |
Graph kinds + include_kinds widening | ✅ | GET /graphs listing; fetch-time opt-in for composing cold graphs |
| Deep freeze / thaw | ✅ | quipu graph freeze|thaw|list — full-history read-only archive packs, auto-attached on open |
| SPARQL 1.1 | ||
| SELECT / ASK / CONSTRUCT / DESCRIBE | ✅ | |
| BGP, JOIN, UNION, FILTER, OPTIONAL | ✅ | |
| ORDER BY, GROUP BY, HAVING | ✅ | |
| Aggregates (COUNT, SUM, AVG, MIN, MAX) | ✅ | |
| BIND / Extend | ✅ | |
| Property paths | ✅ | ROOT default graph only; fails loud inside a named GRAPH |
VALUES inline relations | ✅ | Multi-column and UNDEF |
FILTER ... IN / NOT IN | ✅ | |
| Temporal queries (valid_at, as_of_tx) | ✅ | |
| RDFS subclass inference | ✅ | |
| SPARQL UPDATE | 🔜 | Planned |
Named graphs (GRAPH/FROM/FROM NAMED) | ✅ | Query side; writes go via overlays or /episode. See named-graphs.md |
| Full SPARQL federation (SERVICE) | 🔜 | Planned |
| Schema & Validation | ||
| SHACL write-time validation | ✅ | Optional shacl feature |
| Persistent shape storage | ✅ | |
| Aegis ontology shapes | ✅ | Infrastructure entities |
| Code entity shapes | ✅ | CodeModule, CodeSymbol, etc. |
| OWL reasoning | ✅ | Optional owl feature |
| Governance (SARC conformance) | ||
aegis:Policy write-time gate | ✅ | Class-aware effects, evaluated before commit |
| Constraint metadata (class, verification point, θ, τ_rev) | ✅ | shapes/governance.ttl |
Tripwire path-boundary policies (aegis:appliesTo) | ✅ | shapes/policies/tripwire.ttl; deny hard @ PAG, throttle soft @ PAA |
| Class ↔ placement conformance | ✅ | Refused at write; a soft constraint cannot be placed at the gate |
| Signed verdicts (ed25519) | ✅ | Evidence-hash-bound, verified against a human-authored root of trust |
| Escalation router with a bounded window | ✅ | Default-deny past τ_rev; records the request, does not deliver it |
| Authority intersection over named graphs | ✅ | Off by default; a delegate can only narrow |
T ⊨ Σ audit checker | ✅ | quipu audit; four passes, deterministic, never an LLM call |
| Dispatch-graph inventory (I7) | ✅ | quipu audit inventory; ungoverned classes are data, not prose |
| Namespace-drift report | ✅ | quipu audit namespace; report-only, never refuses a write |
| Replay / promotion readiness | ✅ | quipu audit replay; counts blocks, cannot label false positives |
| Attribution tree, constraint inheritance | ✅ | quipu audit tree / inheritance — reconstructed from principal chains |
| Trust predicate over imported state | 🔜 | The boundary is declared and reported; nothing evaluates the content |
Escalation queue metrics (W_q < τ_rev) | 🔜 | Needs a server behind the queue; unmeasured today |
| AI-Native | ||
| Episode ingestion (Graphiti-compatible) | ✅ | Typed nodes, edges, provenance |
| SQLite vector search (cosine) | ✅ | Default backend |
| LanceDB ANN + predicate pushdown | 🔩 | lancedb feature; embedder-only — not selectable via config in the CLI/server |
| LanceDB full-text search (BM25) | 🔜 | Library path exists but is unreachable from the shipped CLI/server; /context uses the SPARQL CONTAINS fallback |
| Hybrid SPARQL + vector search | ✅ | |
| Auto-embed on write | ✅ | Knot/episode hooks |
| ONNX embedding pipeline | ✅ | Shared with Bobbin |
| Context pipeline | ✅ | Text search + link expansion |
| Reasoner | ||
| Impact analysis (BFS) | ✅ | CLI, REST, MCP tool |
| Datalog rule engine (datafrog) | ✅ | Turtle DSL; stratified negation-as-failure with safe variable binding; negation cycles rejected |
| Reactive evaluation | ✅ | TransactObserver, delta-aware. Optional reactive-reasoner feature; reason --reactive errors without it |
| Counterfactual queries | ✅ | speculate() via SQLite SAVEPOINT |
| Incremental truth maintenance | 🔜 | Planned (Phase 5) |
| Interfaces | ||
| Rust crate (embed) | ✅ | |
CLI (quipu) | ✅ | knot, read, repl, episode, impact, reason, audit |
REST API (quipu-server) | ✅ | Axum-based |
| Web UI | ✅ | Explorer, workbench, timeline, schema |
| Graph explorer | ✅ | Canvas + Barnes-Hut layout, one POST /graph payload, no CDN |
| Web components | ✅ | Embeddable <quipu-*> elements |
| Semantic Web APIs | ✅ | Spotlight, TPF, OpenRefine reconciliation |
MCP tools (46; 48 with owl) | ✅ | Agent integration |
| Python bindings | ✅ | quipu-client under python/ — REST client, stdlib-only |
| Infrastructure | ||
| Graph projection (petgraph) | ✅ | Centrality, shortest path, etc. |
| GraphProvider federation trait | ✅ | RemoteProvider, startup health checks, federated: true on /query |
| Bobbin integration | ✅ | Namespace, IRI patterns, search |
| Automated releases (release-plz) | ✅ | |
| Clustering / replication | 🔜 | Planned |
