Skip to content

Topologies and preservation

Recall runs in one of two topologies. Which one you choose is a preservation decision, not a filesystem-layout decision: the two shapes differ in what survives, not just in where files live. And within either shape, where the local root sits decides whether anything outside your control — a permission fence, a cloud client, a network — can silently stop preservation.

The topology is declared on the scheduler unit line, not in a dotfile: --root names the machine-local root every source syncs into, and --consolidate, when present, names the shared root that per-machine subtrees are mirrored into. See Configuration for the full unit line and Concepts for what the roots contain.

The two topologies

single machine (default)multi-machine (consolidated)
Dataset rootsOne machine-local rootOne machine-local root per machine, plus one shared consolidated root
How data reaches the archiveThe hourly scheduler unit syncs each source into the local rootThe same hourly sync per machine; a separate --consolidate transport step mirrors whole per-machine subtrees into the shared root
WritersThis machine onlyExactly one writer per per-machine subtree; the transport is a one-way, grow-only mirror — never --delete
Cloud involvementNone — no cloud client, no extra tooling, nothing to misconfigureOptional: the consolidated root may be cloud-synced (then the vendor’s client is the replication tool), or replication is delegated to a tool built for it
SurvivesThe source tools’ rotation windowsAlso the loss of any one machine — a dead laptop or a reprovisioned VM

The tiers are opt-in by topology, not doctrine. On a single computer, tier 1 — preserve to the local root — is the whole product: install, local root, done. No consolidation, no cloud, no extra tooling required. Multi-machine setups add tier 2 (--consolidate: single-writer subtrees, grow-only, shared config never carried across) and tier 3 (replication, delegated to a byte-mover such as rclone or the vendor’s own client). An option for fleets; never a requirement.

A single machine needs no consolidated root at all. That is a fully supported steady state, not a degraded one: transcripts accumulate locally and simply never leave the box. Add --consolidate to the unit line later when a second machine joins; the raw archive is never rerouted or renamed by the change. Running with the local root and the consolidated root as the same path remains valid as the degenerate case, but it is not the default.

Why this is a preservation choice, not a path choice

“Store the archive in Dropbox” and “write through the Dropbox mount” are different things. Every fragility Recall is built against lives in the mechanism of writing through a vendor mount, none of it in the storage service itself: macOS TCC can fence launchd and cron off ~/Library/CloudStorage entirely, turning the schedule into a total, silent outage; the cloud client can evict files to dataless placeholder stubs the sync cannot read; client rewrites and conflict copies violate append-only preservation; and when the client is not running, nothing is preserved at all.

This failure class is not hypothetical. Writing straight through a vendor mount took the author’s own fleet dark for weeks in mid-2026, and nothing noticed. The resulting invariant — the preservation path never crosses a cloud mount — is the postmortem. Hence the split: the local root is local, absolutely, and cloud placement belongs to the consolidated root, where the cloud client is demoted from write path to replica-carrier. That is replication’s job, not preservation’s.

The root-placement guard

The installer makes the dangerous placement refuse. The guard evaluates only the local root; the consolidated root is never refused — a cloud-synced folder is welcome there. It classifies the proposed path against known cloud and remote markers: ~/Library/CloudStorage and ~/Library/Mobile Documents (the macOS provider mounts and iCloud Drive), path components containing dropbox, onedrive, googledrive, or icloud, /mnt/* on WSL (a Windows drive over drvfs/9P, not ext4), and network filesystems (NFS, CIFS, sshfs, rclone and friends) read from /proc/mounts on Linux and WSL. Symlinks are resolved before classification, so a local-looking alias into a cloud folder is still caught.

The refusal fires at install time, before anything is written. Output reproduced as printed:

$ python3 ~/code/pibmo-recall/scripts/sync/rootcheck.py --check-local-root ~/Dropbox/Datasets/pibmo
REFUSED as the local dataset root: ~/Dropbox/Datasets/pibmo
- path component 'Dropbox' looks cloud-synced (dropbox)
Risks of a cloud-synced local root (the 2026-06/07 fleet outage class):
- schedulers can be permission-fenced off the path (macOS TCC denies
launchd and cron access to ~/Library/CloudStorage) -> total, silent outage
- the cloud client can evict files to dataless placeholder stubs the
sync cannot read
- client rewrites and conflict copies violate append-only preservation
- when the client is not running, nothing is preserved at all
The local root must be a plain local path -- a hard rule of the
preservation design. A cloud-synced folder is welcome as the CONSOLIDATED
root instead -- that is replication's job, not preservation's.
Detection is heuristic: re-run with --force to override eyes-open.

Detection is heuristic by design — custom cloud-folder locations and some macOS network mounts are not all detectable — so the refusal is paired with an escape hatch: bash install.sh --force accepts the flagged path anyway, with the risks printed. A hard wall would teach users to disguise paths, which is worse than an informed override.

The same module also names a vendor mount chosen as the consolidation target, which is permitted eyes-open — that configuration simply means “the vendor’s own client is the replication tool”:

$ python3 ~/code/pibmo-recall/scripts/sync/rootcheck.py --describe ~/Dropbox/Datasets/pibmo
cloud-or-remote: path component 'Dropbox' looks cloud-synced (dropbox)

A plain local path passes silently and installs normally. The installer proposes the platform default, chosen to be free of permission gates:

PlatformDefault local root
macOS~/Library/Application Support/pibmo/recall — TCC-free even under launchd; Desktop, Documents, and Downloads are gated and are never defaulted
Linux${XDG_DATA_HOME:-~/.local/share}/pibmo/recall
WSLSame as Linux, explicitly on ext4 — a Windows-side folder belongs as the consolidated root, written by the transport step

Placement is checked when it is chosen, not re-litigated on every tick. After install, the doctor watches outcomes instead: is the unit firing, how old is this machine’s heartbeat, how far behind is each replication hop — every failure with its exact remediation. See Troubleshooting.

Threat model

Be precise about what Recall guarantees, because a faithful archive holds every session in plaintext, indefinitely.

Recall provides preservation and provenance. It does not provide confidentiality of what it preserves. Appends extend a transcript; a divergent rewrite (such as a compaction) is kept as a sibling {uuid}.fork-{sha8}.jsonl; regressions are skipped; nothing is ever deleted or overwritten. Raw data lands exactly as the tools laid it out, and each machine records its sync runs, per-file observations, and schema evolution in its own pibmo.db.

The sync excludes the tools’ credential files by rule — Gemini’s oauth_creds.json and google_accounts.json, Codex’s auth.json — so credentials never enter the archive. The remaining exclusions are app code, media, and caches, not content. That is where the exclusion ends: everything you or your agent typed or read inside a session is preserved verbatim. A secret pasted into a session is in the archive, in plaintext, and append-only cuts both ways — Recall has no redaction feature and will never delete it for you. Treat the archive with the same care as the sessions themselves.

Placement decides exposure. There is no encryption at rest: files are stored as the tools wrote them. A local root is protected by whatever protects the disk. A cloud-synced consolidated root shares every transcript with that provider, and a replication destination inherits its own access control. Replication itself is delegated permanently — Recall never speaks a cloud API and never bundles a cloud client — with the honest consequence that Recall cannot verify a replication hop it does not perform. The doctor bounds the damage by measuring outcomes, not mechanisms: each machine’s heartbeat travels with its consolidated subtree, so staleness per hop is observable.

Capture scope is this machine’s disk. The sync reads local source trees — ~/.claude-shaped, ~/.gemini (Gemini CLI and Antigravity), ~/.codex — whoever wrote them. claude.ai web chats and cloud-hosted coding environments never touch a user’s disk and are an import problem, not a sync problem. And preservation starts when the unit starts: anything a tool rotated away before Recall was installed is already gone, and no tool can bring it back.

What is and is not guaranteed

PropertyGuaranteed?Notes
Append-only preservationYesAppends extend; divergent rewrites fork to a sibling {uuid}.fork-{sha8}.jsonl; regressions are skipped; nothing is deleted.
Faithful mirrorYesRaw lands exactly as the tools laid it out — no renames, no remapping, no routing.
Local write pathYesThe guard refuses cloud-synced and remote local roots; --force overrides eyes-open with the risks printed.
Credential files kept outYesoauth_creds.json, google_accounts.json, and auth.json are excluded by rule and never enter the archive.
Loud failureYesPreservation-path code surfaces the underlying error and refuses; the doctor prints an exact remediation per failure.
Confidentiality of session contentNoEverything typed or read inside a session is preserved verbatim, in plaintext; placement decides exposure.
Encryption at restNoFiles are stored as the tools wrote them; use disk or destination encryption if you need it.
RedactionNoAppend-only is absolute; Recall has no delete and will not remove a pasted secret for you.
Verified replicationNoReplication is delegated; the doctor measures heartbeat age at the destination, not the hop itself.
Capture of cloud-hosted sessionsNoOnly sources on this machine’s disk are synced; web chats and hosted environments are an import problem, not a sync problem.

See also

  • Configuration — the --root and --consolidate unit line, machines.json, and projects.json.
  • Concepts — what the dataset root holds and how transcripts are preserved.
  • Getting started — installing a machine.
  • Guided install — the agent-driven setup that writes the scheduler unit.
  • How it works — the sync engine and the invariants it enforces.
  • Troubleshooting — the doctor and recovering a machine that stopped archiving.