Interchange and export¶
To move a brain's compiled graph between systems, pack it into an exchange archive. An archive is a self-checking envelope: it records where the data came from and carries a digest over everything inside, so any change after packing is detected.
Interchange lives in scripts/knowledge_interchange.py and is used from
Python.
Pack an archive¶
import json, sys
sys.path.insert(0, "scripts")
import knowledge_interchange as ki
brain = json.load(open("app/brain.json"))
archive = ki.pack(brain, {"id": "example-brain", "revision": "2026-09-26"})
print(json.dumps(ki.inspect(archive), indent=1))
inspect reports what the archive is and what it is not:
{
"format": "brain-exchange/v1",
"sourceFormat": "compiled-brain/v1",
"origin": { "id": "example-brain", "revision": "2026-09-26" },
"sha256": "…",
"fidelity": "exact-json-value",
"history": "not-present-in-source",
"validation": "transport-only; destination native schema/replay and policy required",
"authority": "none",
"manifest": "absent"
}
The origin needs exactly id and revision. An optional third argument
attaches a manifest, which travels with the archive as a claim of the source,
not as a verified fact.
Two formats exist. brain-exchange/v1 is the default. brain-exchange/v2
computes its digest with RFC 8785 canonical JSON, so other languages can check
it byte for byte:
archive = ki.pack(brain, {"id": "example-brain", "revision": "2026-09-26"},
format=ki.PORTABLE_FORMAT)
Check and unpack¶
validate and unpack recompute the digest. Changing any part of the archive,
including its origin, fails with exchange digest or source format mismatch.
Store it in SQLite¶
ki.write_sqlite("example.exchange.db", archive) # refuses to overwrite
restored = ki.read_sqlite("example.exchange.db")
assert ki.unpack(restored) == brain
The round trip returns exactly the value you packed.
Project to a plain graph¶
Some tools only want nodes and edges. project gives you that graph plus a
report of what the projection leaves out:
result = ki.project(archive)
graph, report = result["graph"], result["report"]
print(report["losses"])
[
{ "path": "/origin", "reason": "exchange origin and revision require the archive" },
{ "path": "/payload/meta", "reason": "compiled envelope metadata requires the archive" }
]
The projected graph is labelled with the conflict-kg/v1 graph format.
What an archive does not do¶
An archive moves data, not permission. Unpacking one grants no access and proves nothing about who may use it: the destination applies its own schema checks and its own read policy. Treat an archive from someone else as input to review, not as trusted knowledge.