SDK
One engine, three sockets. The same pipelines the drop box runs, packaged so software can plug in whatever it is written in: a TypeScript library, a CLI for any language that can spawn a process, and a localhost daemon for any runtime that can make an HTTP call. Files are read on your machine and never uploaded; only digests, the committed root document, position records and each file’s sealed recovery entry leave it.
TypeScript
npm install @mikeargento/bitgraph-sdk
import { BitGraph } from "@mikeargento/bitgraph-sdk"; const bg = new BitGraph(); const r = await bg.record("run-042.log", { exportDir: "." }); console.log(r.files[0].proofUrl); // the record's public proof page console.log(r.made?.exports?.owner); // ./bitgraph-<n>.bitgraph.json: keep it with the file
Every call makes one BitGraph: a tree/1, every file one leaf of one Merkle tree under one position, and a single file is a tree of one. Bytes already on record come back "on record" untouched, and a file in an earlier tree is found by its sealed recovery entry before it is called new; a lookup that did not complete refuses the file with the reason, because unknown is not new, unless again asks for a new BitGraph regardless. A BitGraphed file is judged offline from the proof it carries and never minted: the envelope is not the recorded thing, the bytes inside are. Earlier forms (sets, the Frame file) still verify; new recordings are tree/1.
The proof commits only the tree’s root, so each file shows it is in its BitGraph with its export (bitgraph-export/1), written beside the files: the owner’s export holds every leaf and name, a member export holds one file’s leaf and path, and SPEC.md, the text the proof pins, is written beside them. Exports hold no file copies and no anchors. Keep export/1 and SPEC.md with the files. Each file made also gets a sealed recovery entry, stored under a name derived from the file’s hash and encrypted with a key derived from it, so the file alone can find its proof again when the export is lost; recovery: false keeps none but still checks them.
The verbs: record, check, proof, open and seal, verify and verifyExport, ownerExport, memberExport, writeExports, completeExport, bitgraphedFile, complete. verify needs no network: a BitGraphed file argues for itself, and a file with its export is judged one line per claim, each saying what it rests on. The window is stated in the protocol’s units: the floor in time (the Base block fixed when the position opened, or the Ethereum block on earlier proofs), the ceiling in time (the Base block carrying a Merkle root over the record) and the settlement (Ethereum’s record of that Base block through Base’s output root), each once it exists. completeExport adds the floor header, the Base ceiling and the settlement to an export once they exist, each verified first. check is read-only and asks the recovery entries too, so a tree member is reported on record with its leaf and the tree’s proof page.
The position before the work
open holds a position while no work exists; put its commitment string inside the task, then seal the task within the position’s life. The commitment did not exist before the position did, so the task could not have either, and outputs recorded afterwards sit later. A task that does not carry the commitment is refused before the position is spent.
const slot = await bg.open(); const task = prompt + "\n<!-- " + slot.commitment + " -->"; const sealed = await slot.seal(Buffer.from(task)); // slot.fuseVersion is 3 when the boundary returned a Base floor (enclave v10; 2 for an earlier // Ethereum floor): the commitment binds the floor block's hash, so the task could not have been // written before that block existed.
Any language: the CLI
Every command takes --json and prints one JSON document, so anything that can spawn a process is integrated. record <paths...> makes one tree and writes its export/1 beside the files (--out DIR; --exports owner|members|both|none, the owner’s by default; --again records files already on record; --as-is; --no-recovery). verify <file> <export.json> (or --export) judges a file with its export offline, one line per claim, and exits 2 on FALSE or a corrupt block; --eth-rpc and --base-rpc confirm each block against a node, --pcr0 names the enclave images you accept. export complete <export.json> adds the floor header, the Base ceiling and the Ethereum settlement once they exist; export member <owner.json> <file> derives one member’s export. check is read-only. recovery list|flush|keep manage pending recovery entries, saved under $BITGRAPH_HOME/recovery (default ~/.bitgraph). The single-file form: bitgraphed writes the BitGraphed file (carrier/2) beside the original, complete fetches in what has landed since, and ceiling verify checks a ceiling in time.
npx bitgraph record run-042.log --json # one tree; writes ./bitgraph-<n>.bitgraph.json and SPEC.md beside it npx bitgraph verify run-042.log bitgraph-<n>.bitgraph.json # the file with its export, offline, one line per claim npx bitgraph export complete bitgraph-<n>.bitgraph.json # add the floor header, the Base ceiling and the settlement once they exist npx bitgraph export member bitgraph-<n>.bitgraph.json run-042.log # one file's own export, from the owner's npx bitgraph verify photo.bitgraph.jpg --eth-rpc https://ethereum-rpc.publicnode.com --base-rpc https://mainnet.base.org npx bitgraph bitgraphed photo.jpg --wait 30000 npx bitgraph open npx bitgraph seal --token <token> task.txt
Any runtime: the localhost daemon
bitgraph serve puts the same verbs on 127.0.0.1, and only there: the daemon reads local files by path and is never reachable from off the machine. GET / returns the map.
npx bitgraph serve
import requests
requests.post("http://127.0.0.1:8791/record",
json={"paths": ["run.log"]}).json()Agents
AI clients plug in through the MCP server, which runs this same engine: the record, check and proof tools, plus the position-first task flow. One way to make a BitGraph, whichever socket is speaking.
Pointing at a licensed boundary
new BitGraph({ baseUrl, apiKey }), or BITGRAPH_API_URL and BITGRAPH_API_KEY, or --base-url and --api-key. The public boundary is anonymous. Recording is permanent, so record what was asked for and nothing more; verification is free, for anyone, forever.