Skip to content

Federation

Mehmet Nuraydın edited this page Jul 19, 2026 · 1 revision

Federation

Cross-vault federation is read-only: a live reference, never a copy. When vault A has an out/both connection to a shareable vault B, A's recall (the default memory recall and the per-prompt recall hook) runs crossVaultRecall across A plus B's corpus live at query time, excludes federated docs (transitive-leak guard), and returns merged BM25 hits tagged by vault. Nothing is written into A; B stays the single source of truth for its own knowledge. The only knobs are direction, status (stale), shareable consent, and topics — there is no when-X-read-Y trigger.

Full-size diagram: public/image/diagram-federation.pdf. Board source: _dream_context/knowledge/diagrams/federation.board.cjs (regenerated by npm run diagrams).

Note: the rendered image still depicts the older PUSH/PULL model (copy-based sync) and is pending regeneration for the read-only pivot — federation now only does the live PULL half described below.

One project rarely lives alone. You have a backend, a marketing site, an internal tool — each its own _dream_context/, each accumulating decisions, and each blind to the others. A decision made in the API repo ("we standardized on cursor pagination") is exactly the kind of thing the dashboard repo's agent should know, but copy-pasting context between projects is the manual re-discovery problem all over again, one directory up.

Federation is the answer, and it is built on the same principle as everything else: opt-in, local, and human-auditable. No server, no account, no background daemon reaching across your machine.

The vault registry

Federation starts with a global registry of vaults — a vault is just a registered _dream_context/ project, addressable by name. The registry (src/lib/vaults.ts) lives in your home directory, not in any one repo, so it is the one shared index every project and the desktop app read from.

dreamcontext vaults discover ~/projects --register

vaults discover walks a directory tree (ignoring node_modules), finds every _dream_context/, and — with --register — adds the new ones idempotently. The desktop app's launcher is a GUI over this same registry: every window it opens is a vault by name.

Cross-vault recall

Once vaults are registered, recall can span them. The same BM25 ranker that searches one corpus searches several, and every hit is tagged with the vault it came from:

  • --vault <name> — also search a specific named vault (repeatable).
  • --connected — span this vault plus the peers it has an outbound connection to.
  • --all-vaults — span this vault plus every vault marked shareable.

The gate is consent: a vault is only reachable from another if its owner ran config shareable on. Recall silently skips vaults that are not shareable or no longer exist on disk, rather than erroring — the same "a missing source is a non-event, not a failure" posture as the version nudge.

Connections are read edges — nothing is copied

You connect two vaults with a direction (out, in, or both); out/both means "this vault may read that peer." There is no per-situation "when to read" rule — a connection is a standing "may read" agreement that resolves live at recall time.

dreamcontext connect api-backend --direction out --topics auth,pagination

Live read is the default, not a flag. Plain memory recall already spans connected, shareable peers (memory.tsresolveConnectedVaultscrossVaultRecall), and the per-prompt UserPromptSubmit recall hook now does too — surfacing each peer's canonical docs (a — Connected peers (live read) — block, namespaced vault::path). It builds the peer corpus at query time and writes nothing; the cost is zero when you have no connections (the path short-circuits). The transitive-leak guard drops federated: true docs from cross-vault serving, so a third vault never sees what merely passed through this one.

dreamcontext federation peers         # Compact summary of readable peers (ambient awareness)
dreamcontext federation status        # Connections + any leftover federated copies
dreamcontext federation purge --all   # Remove leftover federated:true copies from the old sync path

The desktop launcher's federation network view draws every vault as a card and lets you wire a single relationship by clicking source → target: a violet reads wire — out/both + the target's Readable gate, meaning "A reads B's canonical memory live." A per-node panel and an always-on connections list render the stored directions back as plain sentences ("X reads Y live"), each removable in one click — a direct, auditable window onto the .connections.json direction model.

Copy-based sync is parked on the roadmap

Earlier builds had a push half: during sleep, a sleep-federation specialist pushed a recall-filtered, lossy digest of each vault into its consenting peers' inboxes (federation sync), and the receiver ingested those as federated: true copies (federation drain). That broke single-source-of-truth — the copies were truncated, went stale the instant the source changed, and a re-edit produced a duplicate plus a false conflict-note instead of refreshing. So it is disabled: federation sync/drain are inert no-ops, the sleep-federation specialist is no longer dispatched, and sleep copies nothing across vaults. The one thing live read structurally can't do is survive a peer going offline; a redesigned, explicitly opt-in offline-mirror mode may return for that case, but only after a proper design.

Read-only by construction

The security model mirrors the dashboard's loopback-and-CSRF posture. The browser-reachable route (POST /api/federation/sync) is dry-run by construction — it returns deltas with a constant dryRun: true, and no file under src/server/routes/ may import a federation write function, so a crafted loopback request cannot write into a peer vault. The destructive federation purge is CLI-only and guarded: it requires an explicit --all/--vault flag and, before any unlinkSync, resolves symlinks and rejects anything that escapes the vault's knowledge/ directory. .connections.json writes are atomic (temp-file + rename with a per-write nonce) so concurrent CLI/launcher writers never clobber a direction. Dead or unreachable peers are skipped (warned once), so a deleted sibling never stalls recall.


Part of the dreamcontext deep dive — Home · README

Clone this wiki locally