01 / architecture

Three columns,
one source of authority

The hub needs no agent of its own; every device runs one local node. The standby catches up in replication sequence row by row, and may take over only after the checks pass; takeover rotates the credential generation, so anything the old hub sends afterwards is rejected outright. Click the blocks below to see what each one actually holds on disk.

Mutual TLS Private network by default Single-use pairing code 5 resident + 4 transcript reads Replicated by sequence 25 formal memory tables
01

Topology: open any cell

Thin lines are data flow; the small bright dots running along them are one unit of data in flight. Select a block and the inspector lays out its actual structure on disk.

edge · edge device
hub · primary
transcript.db memory.db core.db ledger.db keys/ backups/ secrets.enc
standby · backup
Caught up Verified Missing rows ⇒ no takeover
Pairing / ingest Rows / snapshot Replication sequence One unit of data in flight
02

Where the data lands

The hub and the node are each one directory. The ledger never leaves the hub, keys never enter the model, and no backup hides a private key in plaintext — those three rules shape the whole operating posture.

hub · --data-dir Hub
├transcript.dbRaw transcript, append-only; one row per turn, never overwritten
├memory.dbThe memory body: 25 formal core tables + 7 side tables (schema v6): conclusion rows, entity rows, sources and audit
├core.dbThe agent's own encrypted notebook: one per agent, three encrypted tables for body / revisions / notes
├keys/An independent key per core notebook (32 bytes), never exposed through agent tools
├ledger.dbLedger, quota, progress bookmark —never leaves the hub
├backups/Raw transcript, memory and manifest — three pieces, the last 7 sets kept
├hub.keyHub private key; hub key export writes an encrypted archive
└secrets.encSecret box; the passphrase that opens it is stored separately and does not travel with backups
node · data_dir Edge
├device.keyNode private key: the root of pairing and signing
├replica/The read-only replica and search index downloaded in full; this half is read-only and never rewritten
├pending.dbWhat accumulates locally while disconnected; local distillation batches after a full day offline are written here
├dr/Hourly self-backup once detached from the hub (five full days offline); unconfirmed data is never deleted
└node-state.jsonSynced, offline, self-hub — three states recorded here
recollect-nodestatus
sync_state connected self_distill false offline_elapsed_ms 0 pending_turns 0 staging_rows 0 dr_backup_count 0

Readings carry no text and no paths — the ops surface only answers "is anything stuck", and moves no content.

Why ingest is not the core's job Contract > plugin
  • Every vendor keeps changingSession formats, fields and versions move in every agent; hard-coding one vendor into the core means touching the core on every change.
  • Agents ship their own converterSessions are written out as events per the contract; if ingest acceptance fails, the converter changes — the core parses no private format.
  • A new source needs a trial runFour sources have passed acceptance; a new source ships with a trial-run note and is checked against the same ruler.
03

Identity is a hash; position is only a step number

The model sees only [e12] — a short handle. A handle is the number in front of a recall result; holding it gets that memory back. The full locator is left to the program. Each of the seven IDs has one job: which one is the real identity, which is only a serial for humans, and which exists only for machine-to-machine sync.

How to read it: the bar insha256(a | b) means "concatenate, then hash"; a trailing ? means the field is optional.

session_uid
sha256(source_agent | device_id | session_key | agent_instance_id?)
A session's identity; the same session imported on another machine still has it
thread_uid
sha256(session_uid | thread_key)
The conversation thread inside a session; sub-agents stay separate from the main thread
turn_uid
The source turn id, or the event_uid of the first user message in the turn
A turn's identity; when the source has no native turn number, a derived form is used
event_uid
sha256(thread_uid | native_key | content_hash | occurrence)
An event's real identity; it is what points a memory back to the raw text
revision_id
sha256(source_sha256 | adapter_version | ingest_version)
One interpretation version of the same source content
seq
A stable step number assigned at first ingest (append-only)
Used for display and reference only, not an identity
commit_seq
(epoch, commit_seq) hub replication order
Lives only in the replication layer and never enters a memory ID

In one line: the model sees only handles, identity is the hash; the sequence is for humans, the replication sequence for machine sync.

Live composer · a selected field joins the hash
session_uid = sha256( … )
—
Waiting for input
04

Five resident endpoints,four transcript reads

Five write and pairing endpoints stay up; the four transcript reads go only to paired devices; the downstream snapshot appears at publish time. The less we expose, the more precisely we can say what it promises.

hub serve · v1HTTP
EndpointMethodNotes
/v1/pairpostPair a device with a single-use code
/v1/challengepostHave the device sign, proving it is itself
/v1/ingestpostWrite a batch of events with a signature, rejecting duplicate submission
/v1/rowspostSend back rows accumulated offline; the snapshot pull is allowed only once the hub answers 200
/v1/stategetSync progress and hub state
/v1/snapshot/memorygetDownload the full memory snapshot (at publish time)
Transcript reads · paired devices only
/v1/transcript/sessionsgetThe list of every visible session on the hub
/v1/transcript/sessiongetReplay turn text by session, with paging
/v1/transcript/searchgetSearch the hub's full-text index for the words as they were said
/v1/transcript/turngetFetch the target turn and up to 10 turns either side by turn_uid

Two more exist: the backup replication surface /v1/replicate* , and the endpoint read only during pairing /v1/identity; both are used only at takeover or pairing, not on the day-to-day device path.

recollect-hub cycle onceone extraction cycle
# seats come from --llm-config or repeated --replies # neither given → exit 3, the error names both flags $ recollect-hub import --data-dir ./data \ fixtures/exchange/synthetic_basic.json imported 1 session · 1 revision $ recollect-hub cycle once --data-dir ./data --llm-config ./llm.toml cycle seats=1 batches=1 committed=1 $ recollect-hub index status --data-dir ./data memory_version 6 rows · watermark advanced

The above is an illustrative call sequence; for real readings trust this machine's --help and index status instead.

05

On the LAN, or half a country away

Same device, same LAN, remote site — three ways to connect over the same pieces, with no second service deployed for "remote". It runs inside a trusted private network by default: for a remote site, pull both machines into one private network with a tunnel or mesh, and never expose the port to the public internet.

01 / This machine
One machine is the hub

Runs with no remote at all: ingest, extraction and recall all happen here.

02 / LAN
Connect to one address

One LAN address in the device address book; the node tries them in order and goes with the first that connects.

03 / Remote site
Over a tunnel or mesh

Add one more entry to the address book; the last successful one goes first, so changing networks does not wait out a dead path.

  • Trust the machine, not the addressEach device signs with its own private key, and the hub pins the public key in advance. A signature is not tied to an IP, so changing networks needs no re-pairing; but without that private key, holding the same IP still fails to sign.
  • One port onlyAll external traffic goes over one encrypted port, device and hub authenticating each other; there is no separate management or debug port.
  • Pairing is used onceA single-use pairing code trades for a device identity; after that, signatures carry the trust, not passwords.
  • Transcript reads check the device tooThe four transcript read routes are open only to paired devices; each read leaves one audit row recording who read which session, never the text.
  • Keys never enter the modelKeys come in only through a pipe, never into the model or the argument table; each agent's notebook uses its own key.
  • The ledger never leaves the hubQuota and progress stay on the hub and are absent from backups; a private key never enters a backup in plaintext.
06

Many devices, many agents: who sees whom

The default is a trusted agent environment: paired devices on the same LAN count as insiders. World memory is shared; core stays per agent.

World memory

Shared across agents

Agents under the same owner hand their sessions into this one store, and extraction runs on the hub; everyone can query it, keep building on it, and pick up on another device.

core

One key only

Each agent's encrypted notebook has its own key; core_* opens only to that one agent identity, and no other agent can reach it.

Raw session text

Memory holds only pointers

Raw text stays on the agent side and the hub; shared memory stores a turn_uid pointer, not the raw text. recollect_turn fetches that turn by pointer (up to 10 turns either side), recollect_session replays a session; both pass through the same visibility gate.

Reading across machines

Hub first, local fallback Trusted LAN

The edge asks the hub's four transcript routes first; only when the hub is unreachable does it read locally, marking the receipt with source=local + degraded — never pretending the hub had zero hits.

Default premise: paired devices on the same LAN are trusted — if it can pair in, it can read hub sessions, with no further split by owner. This LAN trust applies only to transcript reads; world memory and core keep their original gates. Do not pair in untrusted devices, and do not expose the hub to the public internet; for a remote site, use a tunnel or mesh to pull the machines into one private network.

GlossaryEleven terms; come back when another page stalls
Handle
The [1] in front of a recall result. Holding it gets that memory back.
Pointer
The number by which a memory points at one turn, one passage, in the raw transcript. As long as the raw text stays put, the pointer does not go stale.
Progress bookmark
A mark of how far processing got. It advances only on success; on failure it stops there and picks up next time.
Gate
An automatic check. Fail it and nothing moves forward, with the reason written down; no one has to watch.
Local distillation
When the hub is unreachable, the node keeps extracting over locally staged data instead of waiting for the network.
Merge-back
Once the network returns, locally accumulated data goes back to the hub in a fixed order, no step skipped.
Anchor
The fixed identity in the store for a person, a project, a machine; memories about it hang from that anchor.
Idempotent
The same thing sent twice counts once and is never written twice.
Takeover
The standby is promoted once it has caught up and passed the check; the old hub is blocked right after and can no longer write.
Snapshot
A copy of the whole memory at one moment; handed to nodes at publish time, synced by delta in between.
Transcript read
Fetching raw words from the hub by session or turn_uid; the four read-only routes are open only to paired devices.