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 roots | One machine-local root | One machine-local root per machine, plus one shared consolidated root |
| How data reaches the archive | The hourly scheduler unit syncs each source into the local root | The same hourly sync per machine; a separate --consolidate transport step mirrors whole per-machine subtrees into the shared root |
| Writers | This machine only | Exactly one writer per per-machine subtree; the transport is a one-way, grow-only mirror — never --delete |
| Cloud involvement | None — no cloud client, no extra tooling, nothing to misconfigure | Optional: 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 |
| Survives | The source tools’ rotation windows | Also 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/pibmoREFUSED 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 allThe local root must be a plain local path -- a hard rule of thepreservation design. A cloud-synced folder is welcome as the CONSOLIDATEDroot 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/pibmocloud-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:
| Platform | Default 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 |
| WSL | Same 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
| Property | Guaranteed? | Notes |
|---|---|---|
| Append-only preservation | Yes | Appends extend; divergent rewrites fork to a sibling {uuid}.fork-{sha8}.jsonl; regressions are skipped; nothing is deleted. |
| Faithful mirror | Yes | Raw lands exactly as the tools laid it out — no renames, no remapping, no routing. |
| Local write path | Yes | The guard refuses cloud-synced and remote local roots; --force overrides eyes-open with the risks printed. |
| Credential files kept out | Yes | oauth_creds.json, google_accounts.json, and auth.json are excluded by rule and never enter the archive. |
| Loud failure | Yes | Preservation-path code surfaces the underlying error and refuses; the doctor prints an exact remediation per failure. |
| Confidentiality of session content | No | Everything typed or read inside a session is preserved verbatim, in plaintext; placement decides exposure. |
| Encryption at rest | No | Files are stored as the tools wrote them; use disk or destination encryption if you need it. |
| Redaction | No | Append-only is absolute; Recall has no delete and will not remove a pasted secret for you. |
| Verified replication | No | Replication is delegated; the doctor measures heartbeat age at the destination, not the hop itself. |
| Capture of cloud-hosted sessions | No | Only 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
--rootand--consolidateunit line,machines.json, andprojects.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.