Trunkit
The smallest elephant in the room that's not too Coq-y and doesn't Lean too heavily on your system.
Proof-carrying code middleware on PostgreSQL. Trunkit is a self-contained schema stack that attaches verifiable claims to mathematical objects, chains proofs compositionally, and lets consumers re-verify results without trusting the producer — all inside a database you already operate, with no specialist toolchain required.
No 3 GB compiler. No gigabytes of cached proof objects. No new runtime to learn. Just PostgreSQL, Python, and ~1.5 MB of schemas.
Stack
┌──────────────────────────────────────────────────────────────────┐
│ Porter — agent context handoff │
│ Precacher · Sources · close_session() · open_session() │
│ cybernetic DFAs · composite pattern detection │
├──────────────────────────────────────────────────────────────────┤
│ Nerode — deterministic automata engine │
│ DFA construction · minimization · product · session DFAs │
│ sequence cache · cert-signed handoff envelopes │
├──────────────────────────┬───────────────────────────────────────┤
│ cert │ kan │
│ proof-carrying │ category theory meta-layer │
│ attestation │ (monoidal · NTs · Kan · profunctors) │
├──────────────────────────┼───────────────────────────────────────┤
│ curry │ calx │
│ versioned provenance │ integer arithmetic bedrock │
│ + immutable constants │ (primes · CRT · dynamics · OEIS) │
└──────────────────────────┴───────────────────────────────────────┘
Trunkit DB postgresql://trunk:trunk@localhost:5434/trunk
Nerode DB postgresql://nerode:nerode@localhost:5435/nerode
| Layer | Role |
|---|---|
| calx | Dense prime factorisation of ℤ[1..N]; aliquot/derivative dynamics; CRT; OEIS exact + cosine-candidate matching; C-finite/P-finite recurrence certificates |
| curry | Immutable versioned constants and functions; append-only computational provenance |
| kan | Category-structured meta-layer: reflects Postgres FK graphs into objects/morphisms and checks structural invariants (triangle commutativity, product universal property, naturality, epi classification) as re-runnable probes — see the caveat below |
| cert | Proof-carrying attestation: six method tiers, structured witness storage, proof composition DAG, portable bundle export, consumer re-verification; exact-domain shield, recurrence/morphism certificates, holographic (Merkle) commitments, image anchoring, crypto-succinct (arithmetised) claims |
| Nerode | DFA/automata engine on PostgreSQL: construction, minimization, product, session DFAs, sequence cache, certified handoff envelopes |
| Porter | Agent context handoff: pre-pack external data, certify session boundaries, hand verified context to a new model with zero tool calls |
What "kan" does and does not claim. kan performs structural invariant checking, not formal proof. A claim like "the calx → curry functor is faithful" is attested by a SQL probe that checks the current database state (e.g. the morphism map is injective on the rows present) — it is re-runnable evidence, not a machine-checked theorem about all inputs. Real proof lives in external Lean/Agda artifacts (the
formal_externaltier) or in the independentcert_kernelcheckers. Treatstruct_kanas "this categorical invariant holds over the data we have," with the same three-valued honesty (valid/refuted/unverified) as everywhere else.
Why two databases?
Trunkit (calx/curry/kan/cert) and Nerode (automata/porter) run as separate PostgreSQL instances by design, not by accident:
- Failure & trust isolation — the proof ledger (append-only, hash-chained;
see
SECURITY.md) must not share a backend with the automata/agent-handoff workload, which ingests external data and runs untrusted-ish session traces. - Independent lifecycle — Nerode can be reset/rebuilt (it's a cache + DFA workspace) without touching the immutable cert ledger.
- Cross-instance entanglement is by value, not by FK — a Porter envelope
embeds
cert.ledger_root()and the cert side records the envelope hash viacert.anchor_external, so the two are cryptographically linked without a shared transaction (a single physical chain can't span two instances anyway).
The cost is real (two DSNs, two apply targets); the benefit is that a
compromised or wiped Nerode cannot corrupt or rewrite proof history.
Quick start
For Muse and other agent VMs without Docker or system libpq, use the
muse install and external PostgreSQL guide:
python3 -m venv .venv
. .venv/bin/activate
python3 -m pip install --upgrade "trunkit[muse]" # includes MCP and bundled libpq
# Set CALX_DSN and NERODE_DSN to separate PostgreSQL instances first.
trunkit quickstart --no-docker
trunkit generate --limit 10000 --backend pure
From this source checkout, use python3 -m pip install ".[muse]".
From pip with Docker for the bundled databases:
pip install "trunkit[binary]" # includes libpq and both CLIs
trunkit quickstart # writes docker-compose.yml, starts both DBs, applies both schemas
trunkit --dsn postgresql://trunk:trunk@localhost:5434/trunk generate --limit 10000 --backend pure
trunkit --dsn postgresql://trunk:trunk@localhost:5434/trunk standing
The base install depends on pure-Python psycopg, which keeps Trunkit
installable on Termux/ARM and other targets that have no psycopg[binary]
wheel — but it does expect a system libpq. If you don't have one (slim Linux
images, python:*-slim, distroless, most containers), install the binary
runtime instead:
pip install "trunkit[binary]" # bundles libpq; no system PostgreSQL client needed
Install trunkit[mcp] to add the optional trunkit-mcp server, or
trunkit[binary,mcp] for both. CI smoke-tests the [binary], [binary,mcp], and [muse] wheel installs
on Linux, including real stdio calls from an externally managed Python VM.
trunkit quickstart --compose-only just writes the compose file if you'd
rather start the databases yourself. Existing instances are selected through
CALX_DSN / NERODE_DSN, or trunkit --dsn TRUNK_DSN quickstart --nerode-dsn NERODE_DSN.
Quickstart starts only containers without an explicit connection; when both
connections are supplied, Docker is optional. It prints follow-up commands
using the same connections. Other Trunkit commands use CALX_DSN or their
native default on port 5432, so keep the printed --dsn option when using
the generated container on port 5434.
From a repo checkout:
# 1. Start both PostgreSQL instances
docker compose up -d db-trunkit db-nerode
# 2. Apply all schemas (idempotent)
make apply
# 3. Check exact arithmetic, DFA execution, and a Porter handoff
make check
# 4. Populate integers with the bundled pure-Python backend
trunkit --dsn postgresql://trunk:trunk@localhost:5434/trunk generate --limit 10000 --backend pure
The smoke checks are also shipped in the wheel and require no network sources:
python -m calx.smoke --trunk-dsn TRUNK_DSN --nerode-dsn NERODE_DSN.
They verify a cached brief survives a certified close/open handoff, then roll
back the demo transactions. Set CALX_DSN / NERODE_DSN to reuse these connections
without passing options.
CLI
Trunkit ships a dual-surface CLI. Consumer commands are read-only and safe for LLM use.
Prover commands require --write to record; they dry-run without it.
Consumer — read-only
trunkit verify <claim_id>
# Re-verifies a claim without inserting. Replays the stored witness or
# re-runs the probe SQL in a subtransaction. Exits 0 if valid.
trunkit standing [--method M] [--status S]
# Lists all claims with their latest attestation status.
# Filter by method (comp_sql, struct_kan, formal_external,
# empirical_corpus, witness_carry) or status (valid, refuted, unverified).
trunkit export <id> [<id> ...]
# Emits a self-contained JSONB bundle to stdout:
# claims + certificates + witnesses + derivations.
# Portable — consumers can re-verify without a Trunkit install.
trunkit verify --bundle FILE [--offline]
# Consumer side of export: re-verifies a received bundle.
# Replays each embedded probe in a bounded read-only transaction, checks
# supported witness kernels, artifact hashes, lifecycle, and every premise.
# --offline skips SQL replay; supported witnesses still verify independently.
# Unknown witness schemas remain UNVERIFIED. Artifact identity alone is not proof.
# Three-valued per claim: VALID / REFUTED / UNVERIFIED. Exits 0 iff all valid.
$ trunkit standing
[✓] # 1 comp_sql valid 2026-05-19 14:32 28 is a perfect number: σ(28) − 28 = 28
[✓] # 2 witness_carry valid 2026-05-19 14:32 12 has p-adic stratification {2:2, 3:1}
[✓] # 3 struct_kan valid 2026-05-19 14:33 calx → curry functor is faithful
[?] # 4 formal_external unverified — σ(28) = 56 (external Python proof)
$ trunkit verify 2
[✓] claim 2 → VALID
evidence : {
"v2": 2,
"v3": 1
}
witness : {
"kind": "term",
"levels": {"prime_2": 2, "prime_3": 1},
"reconstruction": "2^2 * 3^1 = 12"
}
Prover — require --write
trunkit check <claim_id> [--write]
# Dry-run: shows what the claim would attest as (via cert.verify).
# With --write: runs cert.check() and records a certificate.
trunkit attest [--write]
# Dry-run: reports formal-tier claims that would be attested.
# With --write: runs cert_formal.py and records all formal-tier certificates.
trunkit close [--write]
# Dry-run: reports intent without side effects.
# With --write: computes reflexive closure — curry fixed points
# (primitive eigenforms) + kan Perron-Frobenius attractor — and
# records eigenform claims.
trunkit revoke <claim_id> --reason TEXT [--write]
# Revoke the claim's latest certificate: an append-only event, never a
# mutation. Standing reads 'revoked'; witnesses riding on the revoked
# certificate stop counting in verify. Re-attest to issue a fresh one.
trunkit witness <claim_id> --kind KIND --body JSON [--write]
# Attach a structured proof witness to a claim.
# KIND: term | trace | counterexample | hash_chain | kan_diagram | quote_span
trunkit register-lean <claim_id> --root DIR --decl Module.thm [--write]
# Register a Lean (Lake) project + declaration as a formal_external artifact.
# Re-checked by tools/lean_check.sh: lake build + axiom / `sorry` audit.
calx data
trunkit init # apply schema DDL
trunkit generate --limit N # populate integers 1..N
trunkit validate [--limit N] # compare ω/Ω against OEIS
trunkit reset # drop all calx tables
trunkit oeis-load [--family F] # fetch curated OEIS b-files
trunkit oeis-match [--orbit-id ID | --all]
trunkit compose-match
trunkit oeis-cosine --seq-id A000045 # scale-invariant growth-shape candidates, confirmed by exact prefix
Porter — model-to-model context handoff
Porter carries verified handoffs: the next session receives the work and rechecks its certificate before acting. Long-term memory tools can supply a payload inside that handoff; Porter preserves the evidence for a particular session boundary.
The v2 protocol and MCP guide adds immutable payload
snapshots, per-key SHA-256 manifests, bounded read-only opens, optional atomic
claim leases, and a carried-ledger first-action gate with prior-session health.
porter_open is read-only; porter_close, porter_claim, porter_release, and
porter_open_and_gate require TRUNKIT_ALLOW_WRITE=1. The original v1
Precacher interface below remains available.
Each model session starts with no memory of what the previous session fetched, proved,
or decided. Porter pre-packs that context — external data, DFA states, proof certificates
— into an envelope before the session closes. The next model calls
Precacher.open(envelope, session_id) and has everything ready, cert verified, with
zero tool calls.
from datetime import date
from nerode.precache import Precacher
from nerode.sources import WeatherSource, TickerSource, HNSource
today = date.today().isoformat()
# Model A — fetch and pack before closing
with Precacher(f"brief-{today}") as pc:
pc.fetch(f"weather:london:{today}", WeatherSource(51.5, -0.1, label="London"))
pc.fetch(f"ticker:AAPL:{today}", TickerSource("AAPL"))
pc.fetch(f"news:hn:top5:{today}", HNSource(5))
# __exit__ calls close_session(); pc.envelope is now set
# Model B — open the envelope in a separate process/connection
ctx = Precacher.open(pc.envelope, "model-b-001")
resolved = ctx["resolved"] # {"weather:london:…": {…}, "ticker:AAPL:…": {…}, …}
cert_ok = ctx["prior_session"]["cert_valid"] # True
Cybernetic monitoring
Porter includes DFA-based pattern detectors that fire over metric and control streams:
| DFA | Pattern | Meaning |
|---|---|---|
metric_rise_3 |
U{3,} |
3+ consecutive rises |
metric_oscillate |
(UD){3,} |
oscillation / gain too high |
dead_time_5/10/20 |
A_{k,} |
action without response in k steps |
homeostasis_alarm_5 |
O{5,} |
5+ steps outside target band |
dead_time_5_x_metric_oscillate |
composite | oscillating AND unresponsive |
# Log a paired (metric, control) event and scan all relevant DFAs
conn.execute(
"SELECT nerode.log_cybernetic(%s, 'metric_x_control', %s)",
(session_id, "UA") # metric rose (U), action taken (A)
)
# pg_notify('nerode_control_warn', ...) fires if any pattern matches
cert method tiers
| Method | Trust root | Use |
|---|---|---|
comp_sql |
In-DB probe | Computational facts about integers or categorical counts |
struct_kan |
Existing kan invariant | Naturality, triangle identities, faithfulness checks |
formal_external |
SHA256-pinned external artifact | Python/Lean/Agda proof scripts |
empirical_corpus |
Provenance only | Corpus document assertions |
witness_carry |
In-DB witness term | Structured proof terms stored alongside certificates; consumer-replayable |
crypto_succinct |
Pinned verifying key + external verifier | Succinct (optionally zero-knowledge) proofs over arithmetised first-order claims (calx.arith); the prover stays outside the package |
Exactness shield. Every claim also carries a
domaintag (exact_int/rational/algebraic/interval/float_heuristic). A ledger trigger guarantees afloat_heuristicclaim can never record avalidcertificate — onlyunverified. Heuristics (e.g. cosine similarity) propose; exact probes decide.
Attestable structures (calx / cert)
Finite combinatorial certificates
comb stores graphs, hypergraphs, set systems, and exact point configurations.
Portable comb.v1 certificates now check immutable instances independently:
colourings, independent sets, isomorphisms, cliques, odd cycles, matchings, covers,
set-family properties, and exact chromatic/matching/cover optima. Checked
relabeling and disjoint-union rules carry their premises and vertex maps.
trunkit comb demo --output c5.json
trunkit verify --bundle c5.json --offline # proves chi(C5) = 3
trunkit comb import graph.json
trunkit comb search graph.json --colours 3 --max-steps 100000
trunkit dfa count dfa.json --length 30 --bundle --output counts.json
Claims identify the exact instance digest and typed predicate their witnesses prove. Legacy untyped witnesses remain unverified as evidence of arbitrary claim text. Best-known bound metadata alone does not establish mathematical optimality. Negative graph-colouring certificates use a checked, pinned RUP encoding; unsuccessful bounded search remains unknown. Exact Euclidean checks currently support rational and validated real quadratic coordinates.
The DFA certificates count all accepted words by length, check recurrence identities against the transfer matrix, and certify finite-horizon integer-weighted optima with Bellman inequalities and attaining words. Synchronous products have explicit state and transition budgets.
See combinatorial workflows and automata certificates for Python, SQL, CLI, and MCP interfaces and supported proof formats.
Beyond integer-fact and categorical claims, cert ships re-checkable, exact certificate families:
- Recurrence certificates — a C-finite/P-finite recurrence (coefficients + initial terms) regenerates a sequence;
cert.recurrence_*verifies it exactly and refuses non-exact division. - Sequence morphisms —
cert.morphism_*proves an exact map (scale / affine / index-shift) between two sequences — the structural relation a cosine candidate only hints at. - OEIS cosine candidates —
calx.oeis_cosine_candidatessurfaces scale-invariant growth-shape neighbours, each confirmed by exact prefix agreement. - Image anchoring + similarity —
cert.image_*anchors a figure by sha256 and scores perceptual cosine similarity (pure-SQL; the[image]extra is only for decoding). - Holographic commitments —
cert.merkle_root/cert.claim_commitmentcommit an arbitrarily long trace to a 32-byte root (coresha256).
PCC properties
| Property | Mechanism |
|---|---|
| Proof travels with code | cert.witness stores structured proof terms alongside every certificate |
| Proofs compose | cert.derivation tracks premise dependencies; typed combinatorial kernels additionally check the construction rules and transported witnesses |
| Consumer re-verifies | cert.verify(claim_id) replays without INSERTing — safe for untrusted callers |
| Bundle is portable | cert.export_bundle(ids[]) emits self-contained JSONB: claims + certs + witnesses + derivations |
| Certificates have a lifecycle | cert.revoke[_claim] appends a revocation (never mutates); SET trunkit.cert_ttl stamps a validity window inside the hash-committed valid_under; SET trunkit.signer binds an identity. cert.standing.effective_status reads revoked / expired; revocation is loss of trust, not refutation |
| Certificates bind exact claim versions | New certificates carry a semantic claim digest in valid_under; cert.claim_version retains immutable snapshots. Consumers detect changed statements, subjects, methods, probes, or domains. Existing certificates remain explicitly unbound; a digest does not authenticate its producer |
Bundle size
| Component | Files | Size |
|---|---|---|
| SQL (calx 00–98 + nerode 00–C0) | ~117 | ~711 KB |
Python packages (src/: calx + nerode + trunkit_mcp) |
~25 | ~183 KB |
| Python tools | ~17 | ~188 KB |
| Proof scripts | 6 | ~42 KB |
| Tests | ~45 | ~296 KB |
| Total (no virtualenv) | ~210 | ~1.4 MB |
For scale only (not a capability comparison): a Lean 4 toolchain is ≈ 2.9 GB per version and a compiled Mathlib ≈ 4–10 GB per project. Trunkit is not a substitute for a proof assistant — Lean/Mathlib verify arbitrary human-authored theorems, whereas Trunkit re-checks a fixed, small set of certificate schemas (factorization, CRT, Egyptian fractions, matrix words, recurrence & morphism certificates, image / OEIS cosine candidates) plus re-runnable in-DB probes. The size figures say only that Trunkit fits in a database you already run; they do not imply equivalent verification power.
Repository layout
src/
calx/ — Trunkit Python package (calx + kan + curry + cert)
+ leanbridge.py · imagefeatures.py · recurrence.py
nerode/ — Nerode/Porter Python package
sql/ — 38 idempotent SQL schema files (00_bootstrap → C0_verify),
incl. quantitative EHA/WFFA (A0–A6) + Porter policy gate (B0–B4, C0)
precache.py — Precacher context manager (Porter API)
sources.py — WeatherSource, TickerSource, HNSource, TickerHistorySource
adapters.py — HttpSource, CallableSource, resolve(), with_retry()
db.py — connection utilities + SCHEMA_FILES list
trunkit_mcp/ — MCP server (`trunkit-mcp`): consumer verify/export tools always
on; prover tools gated behind TRUNKIT_ALLOW_WRITE=1
scripts/
morning_brief_demo.py — end-to-end Porter demo
tests/
test_sources.py — network tests (pytest -m network)
test_cybernetic.py — cybernetic DFA tests
test_composite_dfa.py — paired-alphabet composite DFA tests
test_dead_time_factory.py
test_*.py — unit tests for all schema layers
proofs/
*.py — Trunkit proof scripts
tools/
cert_formal.py — formal-tier harness (python + lean checkers)
lean_check.sh, AxiomAudit.lean — Lean bridge driver + axiom/`sorry` auditor
image_features.py, figure_extract.py — vision tools ([image] extra)
oeis_loader.py, oeis_match.py, compose_match.py — OEIS workflows
License
MIT
Metadata
Release files for trunkit 0.5.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| trunkit-0.5.1.tar.gz | 2.0 MB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| trunkit-0.5.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 2.6 MB
Release files / trunkit-0.5.1.tar.gz
| Download URL | trunkit-0.5.1.tar.gz |
|---|---|
| Size | 2.0 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8786511350e365e33f6672493f9e676d997a5406711a8e6ebe72b29e499d5a60
|
|
BLAKE2b-256 checksum How to use checksums |
13fd5b6d89040eee56e3cd2a2d9d6ecd4d3c9223425893ee47318848f8b20d70
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.
Transparency logRelease files / trunkit-0.5.1-py3-none-any.whl
| Download URL | trunkit-0.5.1-py3-none-any.whl |
|---|---|
| Size | 609.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1e004333bf0d20ae846aa59327cf9de9fbdbe4841b0a5f67335c445621801dfa
|
|
BLAKE2b-256 checksum How to use checksums |
e4686f184dee67f45c94422a27c6315d2fe0245a68c5806b268a086ae8cd9a38
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.
Transparency logSecurity for trunkit 0.5.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for trunkit-0.5.1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.