CLI reference
Pibmo Recall has no single binary. It is a set of Python entry points run
straight from the repo checkout — nothing is installed into ~/.claude or
~/.pibmo, and updating is git pull (the scheduler unit points at the
checkout, so the next hourly tick runs the new code). This page documents every
command and flag, its default, whether it is required, and shows real output
for each. The examples assume the checkout at ~/code/pibmo-recall and shorten home
paths to /Users/alice; the outputs themselves are reproduced from real runs
against a scratch dataset root.
For the concepts these commands operate on — dataset roots, machines, faithful mirrors, appends and forks, process-time projects — see Concepts.
Synopsis
bash install.sh [--force]python3 scripts/sync/sync-transcripts.py --root ROOT [options]python3 scripts/sync/doctor.py --root ROOT [options]python3 scripts/sync/scheduler.py (--print | --write | --check) --root ROOT --machine NAME [options]python3 scripts/sync/rootcheck.py (--print-default | --check-local-root PATH | --describe PATH)/usr/bin/python3 scripts/process/process_root.py --root ROOT [options]python3 scripts/process/propose_consolidation.py --root ROOT [--apply]python3 scripts/sync/import_legacy.py --root ROOT --legacy PATH [options]python3 scripts/probe/session_names.py [--root DIR] [--check | --json]Every Python command answers -h/--help. There is no --version flag; the
version of a command is the git commit of the checkout it runs from.
Interpreters. The sync layer (sync-transcripts.py, doctor.py,
scheduler.py, rootcheck.py, import_legacy.py) is pure Python stdlib —
any python3 >= 3.9 works. The processing layer (process_root.py) needs
PyYAML; on macOS run it with /usr/bin/python3, which ships it.
The dataset root
Commands that touch the archive resolve the root in this order, first hit
wins: the --root flag, then the PIBMO_ROOT environment variable. There is
no config file to consult — the root is the only machine-local configuration
and it travels on the scheduler unit / cron line. If neither
resolves, the command fails with an error naming both options and exits 1.
The platform-default local root contains a space
(~/Library/Application Support/pibmo/recall on macOS), so the examples quote
it:
$ ROOT="$HOME/Library/Application Support/pibmo/recall"The sync additionally requires the machine to be registered: it refuses to run
against a root whose machines.json does not map this machine’s hardware UUID
to a friendly name. Registration is install.sh’s job — there is no
auto-created machine folder and no silent fallback.
Exit codes
| Code | Meaning |
|---|---|
0 | Success. Also returned by no-op cases: a sync skipped by the single-writer lock, scheduler.py --check with current units, doctor.py with warnings but no failure, and rootcheck.py --describe in every case. |
1 | Operational error: no resolvable root, an unregistered machine, a missing legacy archive, a corrupt projects.json. The message is printed to stderr, prefixed Error:. Also: doctor.py with any FAIL row, scheduler.py --check with a stale unit, rootcheck.py --check-local-root refusing a path, and session_names.py --check detecting drift. |
2 | Usage error from argument parsing: an unknown flag or a missing required flag. Also install.sh with an unknown argument, and session_names.py when its --root does not exist. |
Write conventions
- Append-only is enforced at write time. A transcript is never
overwritten, shrunk, or deleted. The engine classifies every
changed file and the verbose output uses that vocabulary: JSONL files are
new,extend,identical,fork(a divergent rewrite, kept as a sibling{uuid}.fork-{sha8}.jsonl), orskip-regression(a shrunken source, not copied); binary files and SQLite databases arenewornew-version(content-addressed versions, logical-hash-gated for SQLite). - One writer per root. The sync and the legacy importer take the same
lock. A second concurrent sync prints
[2026-07-22 15:00] sync skipped (already running)and exits 0; an unwritable lock directory is a loud error, never a silent skip. - Credentials never enter the archive. The sync excludes
~/.gemini/oauth_creds.json,google_accounts.jsonand Antigravity’s OAuth token,~/.codex/auth.json, and caches/binaries/ephemera (extensions/,browser_recordings/,bin/,.tmp/,tmp/for Codex,cache/) at write time. - Each machine writes only its own subtree. Raw data lands under
{root}/{machine}/...; the top-level shared config (machines.json,projects.json,profiles.json) is read but never rerouted, and it never crosses during consolidation — the destination’s copies are authoritative. - Every run leaves provenance. Sync runs, per-file observations, and JSONL
schema evolution are recorded in
{root}/{machine}/pibmo.db. The doctor’s heartbeat check reads exactly this.
install.sh
Per-machine setup: propose a local dataset root, register the machine, seed the shared config, and write the native scheduler unit. Interactive by default; every prompt can be pre-filled for headless installs. It never edits your crontab and writes nothing outside the dataset root and the unit file.
bash install.sh [--force]| Flag | Type | Default | Required | Meaning |
|---|---|---|---|---|
--force | flag | off | no | Accept a cloud-synced or remote local root that rootcheck.py would refuse, eyes open. |
Any other argument prints Usage: bash install.sh [--force] and exits 2.
Prompts, in order, with their environment pre-fills:
| Prompt | Pre-fill | Default |
|---|---|---|
| Local dataset root | PIBMO_ROOT | the platform default from rootcheck.py --print-default |
| Friendly machine name | PIBMO_MACHINE | hostname -s, lowercased |
| Multi-machine setup? | implied y when either pre-fill below is set | n |
| Consolidated root (optional) | PIBMO_CONSOLIDATE | blank (skip) |
| Secondary mirror (optional) | PIBMO_SECONDARY | blank (skip) |
On a single computer the install is the first two prompts and Enter — consolidation never comes up. A cloud-synced local root is refused (see rootcheck.py); a cloud-synced consolidated root is permitted eyes-open with a note naming the vendor client as the replication tool.
What it writes: this machine’s entry in {root}/machines.json (idempotent —
re-running with a new name updates the entry), the {root}/{machine}/logs/
skeleton, projects.json and profiles.json seeded from the repo’s
*.example.json templates (an existing file is never overwritten), and the
scheduler unit via scheduler.py --write, whose activation commands it
prints. Registration output, reproduced:
machines.json: registered BE79A1C2... as 'mymac' projects.json: seeded from projects.example.json profiles.json: seeded from profiles.example.jsonIt ends by printing the manual first-sync command, the doctor command, and the crontab fallback line for those who prefer plain cron (never schedule both):
0 * * * * /usr/bin/python3 "/Users/alice/code/pibmo-recall/scripts/sync/sync-transcripts.py" --root "/Users/alice/Library/Application Support/pibmo/recall" >> "/Users/alice/Library/Application Support/pibmo/recall/mymac/logs/cron.log" 2>&1Archiving scope is deliberately narrow: the installing user’s ~/.claude
(plus ~/.gemini, ~/.codex) only. A machine-wide multi-user sweep is a
separate, explicit opt-in — it is never switched on silently.
sync-transcripts.py
The scheduled entry point: archive this machine’s Claude Code, Gemini (CLI + Antigravity), and Codex session data into the dataset root, faithfully and append-only. Safe to run by hand at any time; concurrent runs exit immediately via the lock.
python3 scripts/sync/sync-transcripts.py --root ROOT [--secondary DIR] [--consolidate DIR] [-v] [--dry-run]| Flag | Type | Default | Required | Meaning |
|---|---|---|---|---|
--root | path | $PIBMO_ROOT | yes* | Dataset root. |
--secondary | path | $PIBMO_SECONDARY | no | Accumulate-only DR mirror of the whole root (a local second disk). |
--consolidate | path | $PIBMO_CONSOLIDATE | no | Consolidated root to push this machine’s subtree into, accumulate-only transport. |
-v, --verbose | flag | off | no | Print every non-identical action. |
--dry-run | flag | off | no | Classify and report without writing anything. |
* Required as either the flag or the environment variable.
A run executes stages in order: mirror ~/.claude/projects/, ~/.gemini/,
and ~/.codex/ through the preservation engine (with the credential and
ephemera exclusions above); auto-append newly seen encoded paths to
{root}/projects.json (rows default to process: false — for the
converter’s benefit, never used for routing); write
{root}/{machine}/machine.json; record the schema manifest and run heartbeat
in pibmo.db; then, last, the optional --secondary and --consolidate
mirrors — so a failed transport (cloud offline) can lag replication but never
cost an archive write.
Previewing, then a first real run:
$ python3 ~/code/pibmo-recall/scripts/sync/sync-transcripts.py --root "$ROOT" --dry-run=== Pibmo Recall sync [dry run] — 2026-07-22 15:00 === machine: mymac root: /Users/alice/Library/Application Support/pibmo/recall [dry] would add new project to projects.json: -Users-alice-code-myapp
Done. 3 file action(s): {"claude": {"new": 1}, "gemini": {"new-version": 1}, "codex": {"new": 1}}
$ python3 ~/code/pibmo-recall/scripts/sync/sync-transcripts.py --root "$ROOT" -v=== Pibmo Recall sync — 2026-07-22 15:00 === machine: mymac root: /Users/alice/Library/Application Support/pibmo/recallClaude: new -Users-alice-code-myapp/3f2c9d41-6a77-4e02-9b1c-8d5e0a2f4c66.jsonlGemini: new-version tmp/myapp/logs.jsonCodex: new sessions/rollout-demo.jsonl adding new project to projects.json: -Users-alice-code-myapp
Done. 3 file action(s): {"claude": {"new": 1}, "gemini": {"new-version": 1}, "codex": {"new": 1}}A scheduled tick without -v logs two lines; a session that only grew is an
extend:
[2026-07-22 16:00] sync started[2026-07-22 16:00] sync completeA divergent rewrite of a transcript — compaction is the common cause — is never merged and never lost: the previous lineage survives as a sibling fork file. Reproduced:
$ python3 ~/code/pibmo-recall/scripts/sync/sync-transcripts.py --root "$ROOT" -v=== Pibmo Recall sync — 2026-07-22 17:00 === machine: mymac root: /Users/alice/Library/Application Support/pibmo/recallClaude: fork -Users-alice-code-myapp/3f2c9d41-6a77-4e02-9b1c-8d5e0a2f4c66.jsonlGemini:Codex: schema change detected in claude
Done. 1 file action(s): {"claude": {"fork": 1}, "gemini": {}, "codex": {}}
$ ls "$ROOT/mymac/claude/projects/-Users-alice-code-myapp/"3f2c9d41-6a77-4e02-9b1c-8d5e0a2f4c66.fork-cea3cb99.jsonl3f2c9d41-6a77-4e02-9b1c-8d5e0a2f4c66.jsonl(The schema change detected line is stage 6 noticing a JSONL event type it
had not recorded before — the manifest in pibmo.db tracks the tools’ schema
evolution as a side effect of reading the lines anyway.)
Missing root and unregistered machine:
$ python3 ~/code/pibmo-recall/scripts/sync/sync-transcripts.pyError: no dataset root. Pass --root /path/to/dataset (or set PIBMO_ROOT). The installer prints the exact cron line.
$ python3 ~/code/pibmo-recall/scripts/sync/sync-transcripts.py --root /tmp/not-a-rootError: /tmp/not-a-root/machines.json not found.Run install.sh first to register this machine and seed the shared config.Both exit 1.
doctor.py
Is this machine actually archiving? Checks registration, root reachability, a
write canary, the scheduler unit (existence, byte-match against a fresh
render, and whether its embedded interpreter and script still exist — the
moved-repo class), the sync heartbeat in pibmo.db, log recency, and — when
a consolidated root is named — per-machine replication lag there. Every
failure prints its exact fix. Read-only except one write-and-delete canary
under {root}/{machine}/logs/; the raw archive is never touched.
python3 scripts/sync/doctor.py --root ROOT [--machine NAME] [--python PY] [--repo PATH] [--secondary DIR] [--consolidate DIR] [--max-age-hours N] [--platform P]| Flag | Type | Default | Required | Meaning |
|---|---|---|---|---|
--root | path | $PIBMO_ROOT | yes* | Local dataset root. |
--machine | string | resolved via hardware UUID | no | Friendly machine name. |
--python | path | /usr/bin/python3 | no | Interpreter expected in the unit. |
--repo | path | derived from the script’s location | no | Repo checkout expected in the unit. |
--secondary | path | "" | no | --secondary value expected in the unit. |
--consolidate | path | "" | no | Consolidated root to measure replication against (also expected in the unit). |
--max-age-hours | float | 26 | no | Heartbeat age that still counts as healthy (hourly schedule + a slept-through laptop day). |
--platform | enum | auto | no | One of auto, darwin, linux, wsl. |
* Required as either the flag or the environment variable.
The unit check renders a fresh unit from the flags above and compares
byte-for-byte, so pass the same --python/--repo/--secondary/
--consolidate values the installer used — a mismatch is reported as a stale
unit, which is exactly what it means. Exit 0 when everything passes (warnings
allowed), 1 on any FAIL.
A healthy machine shortly after install (the log warning clears after the first scheduled tick):
$ python3 ~/code/pibmo-recall/scripts/sync/doctor.py --root "$ROOT" --machine mymacPibmo Recall doctor -- machine 'mymac', root /Users/alice/Library/Application Support/pibmo/recall OK root /Users/alice/Library/Application Support/pibmo/recall/machines.json readable (1 machine(s) registered) OK identity BE79A1C2... OK registered 'mymac' OK writable canary ok under mymac/logs/ OK unit 1 unit file(s) current OK unit-cmd embedded interpreter and script exist OK heartbeat last completed sync 2026-07-22T14:00:03.512208+00:00 (0.4h ago) WARN log no /Users/alice/Library/Application Support/pibmo/recall/mymac/logs/cron.log yet fix: expected after the first scheduled run; manual -v runs print to the terminal insteadSummary: 7 ok, 1 warn, 0 failA failure carries its remediation inline — here the unit file is missing:
FAIL unit not installed: /Users/alice/Library/LaunchAgents/com.pibmo.recall.sync.plist fix: re-run install.sh (or scheduler.py --write), then: Activate (idempotent; bootout first when re-writing an active unit): launchctl bootout gui/$UID com.pibmo.recall.sync 2>/dev/null || true launchctl bootstrap gui/$UID "/Users/alice/Library/LaunchAgents/com.pibmo.recall.sync.plist" If a sync destination crosses a vendor cloud mount (e.g. a consolidated root under ~/Library/CloudStorage), the first launchd run may raise ONE macOS consent prompt for python3 -- grant it once. (using the crontab fallback instead? verify: crontab -l | grep sync-transcripts)...Summary: 5 ok, 1 warn, 1 failExit 1. Two failure signatures get dedicated diagnoses: a fresh log next to a
stale heartbeat means the scheduler fires but every run dies early (the fix
says to read the log), and with --consolidate the doctor also lists every
peer machine’s replicated heartbeat at the destination, flagging any that has
gone dark past 48 hours. On WSL the unit check degrades to a warning —
Windows Task Scheduler is not verifiable from inside the distro, so the
heartbeat is the ground truth.
scheduler.py
Generate, install, and verify the native scheduler unit for the hourly sync: a
launchd LaunchAgent on macOS, a systemd user service + timer on Linux. Units
are deterministic — same inputs, byte-identical files — so --check can
verify the installed unit against a fresh render, exactly like the doctor
does.
python3 scripts/sync/scheduler.py (--print | --write | --check) --root ROOT --machine NAME [--python PY] [--repo PATH] [--secondary DIR] [--consolidate DIR] [--platform P]| Flag | Type | Default | Required | Meaning |
|---|---|---|---|---|
--print / --write / --check | flag | — | yes (exactly one) | Render to stdout / write and print activation commands / exit 1 unless installed units byte-match a fresh render. |
--root | path | — | yes | Dataset root to embed in the unit. |
--machine | string | — | yes | This machine’s friendly name (log path). |
--python | path | /usr/bin/python3 | no | Interpreter to embed. |
--repo | path | derived from the script’s location | no | Repo checkout to embed. |
--secondary | path | "" | no | Optional --secondary destination to embed. |
--consolidate | path | "" | no | Optional consolidated root to embed. |
--platform | enum | auto | no | One of auto, darwin, linux, wsl. |
The macOS unit, rendered. StartCalendarInterval fires at minute 0 and
launchd coalesces ticks missed while the Mac slept into one run on wake;
RunAtLoad adds a catch-up run at login (extra runs are no-ops):
$ python3 ~/code/pibmo-recall/scripts/sync/scheduler.py --print --root "$ROOT" --machine mymac# ==> /Users/alice/Library/LaunchAgents/com.pibmo.recall.sync.plist<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict> <key>Label</key> <string>com.pibmo.recall.sync</string> <key>ProgramArguments</key> <array> <string>/usr/bin/python3</string> <string>/Users/alice/code/pibmo-recall/scripts/sync/sync-transcripts.py</string> <string>--root</string> <string>/Users/alice/Library/Application Support/pibmo/recall</string> </array> <key>StartCalendarInterval</key> <dict> <key>Minute</key> <integer>0</integer> </dict> <key>RunAtLoad</key> <true/> <key>StandardOutPath</key> <string>/Users/alice/Library/Application Support/pibmo/recall/mymac/logs/cron.log</string> <key>StandardErrorPath</key> <string>/Users/alice/Library/Application Support/pibmo/recall/mymac/logs/cron.log</string></dict></plist>On Linux the same command renders a oneshot service plus an hourly timer
(Persistent=true catches up missed ticks; RandomizedDelaySec=120 spreads
fleet load) into ~/.config/systemd/user/pibmo-recall-sync.{service,timer}.
--write writes the file(s) and prints the activation commands; --check
verifies:
$ python3 ~/code/pibmo-recall/scripts/sync/scheduler.py --check --root "$ROOT" --machine mymacOK: 1 unit file(s) current
$ python3 ~/code/pibmo-recall/scripts/sync/scheduler.py --check --root "$ROOT" --machine mymac \ --python /opt/homebrew/bin/python3STALE: /Users/alice/Library/LaunchAgents/com.pibmo.recall.sync.plist: differs from a fresh renderThe first exits 0, the second 1. On WSL no file is written in any mode — the Windows Task Scheduler cannot be configured from inside the distro, so the command to schedule on the Windows side is printed instead (exit 0).
rootcheck.py
Dataset-root placement rules for the installer. Preservation is local-first:
the machine-local root must never sit on a cloud-synced or remote path, so
this tool classifies paths and the installer refuses accordingly. Detection is
heuristic by design (custom cloud-folder locations are not all detectable),
which is why the refusal pairs with install.sh --force rather than
pretending certainty. Symlinks are resolved before classification.
python3 scripts/sync/rootcheck.py (--print-default | --check-local-root PATH | --describe PATH) [--platform P]| Mode | Output | Exit |
|---|---|---|
--print-default | The platform-default local root. | 0 |
--check-local-root PATH | Nothing when PATH looks local; the refusal with reasons and risks when it looks cloud-synced or remote. | 0 local, 1 refused |
--describe PATH | One line: local, or cloud-or-remote: <reasons>. Used to name a vendor-mount consolidation target, permitted eyes-open. | always 0 |
$ python3 ~/code/pibmo-recall/scripts/sync/rootcheck.py --print-default/Users/alice/Library/Application Support/pibmo/recall
$ python3 ~/code/pibmo-recall/scripts/sync/rootcheck.py --describe '~/Dropbox/Datasets/pibmo'cloud-or-remote: path component 'Dropbox' looks cloud-synced (dropbox)
$ 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 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.The last exits 1. On Linux/WSL it additionally checks /proc/mounts for
network filesystems (NFS, CIFS, sshfs, rclone, and friends) and, on WSL,
refuses /mnt/* — a Windows drive crosses drvfs/9P and may be cloud-synced
on the Windows side where WSL cannot tell.
process_root.py
The deterministic processing layer: project the faithful archive into merged
per-project Markdown under {root}/processed/{key}/{profile}/. Groups encoded
paths into logical projects via {root}/projects.json at process time
(consolidate_into chains resolved transitively — consolidation happens
here, never in the sync), dedupes the same session synced from several
machines by superset, and stamps every emitted file with source_machine /
source_encoded_path frontmatter so provenance survives the merge. No LLM is
involved anywhere.
/usr/bin/python3 scripts/process/process_root.py --root ROOT [--key KEY ...] [--projects FILE] [--profiles-config FILE] [--respect-process-flag] [-v]| Flag | Type | Default | Required | Meaning |
|---|---|---|---|---|
--root | path | $PIBMO_ROOT | yes* | Dataset root. |
--key | string | all | no | Only process this logical project; repeatable. Matches the post-consolidation key or the raw encoded folder name. |
--projects | path | {root}/projects.json | no | Override the projects map. A missing file falls back to raw encoded names; a corrupt file is an error, not a silent fallback. |
--profiles-config | path | {root}/profiles.json | no | Override the profiles config, merged over the built-in faithful and dialogue defaults (denylist semantics). |
--respect-process-flag | flag | off | no | Skip rows marked process: false (legacy semantic; the default processes everything, since auto-appended rows all carry process: false). |
-v, --verbose | flag | off | no | Print the resolved machines, keys, and profiles before converting. |
* Required as either the flag or the environment variable.
$ /usr/bin/python3 ~/code/pibmo-recall/scripts/process/process_root.py --root "$ROOT" -vroot: /Users/alice/Library/Application Support/pibmo/recallmachines: mymacprojects: 1 logical key(s) from 1 raw folder(s)profiles: faithful, dialoguekeys=1 profiles=2 wrote=6 unchanged=0 superset_dupes=0
$ find "$ROOT/processed" -type f | sed "s|$ROOT/||"processed/-Users-alice-code-myapp/faithful/2026-07-21_3f2c9d41.fork-cea3cb99.mdprocessed/-Users-alice-code-myapp/faithful/2026-07-21_3f2c9d41.mdprocessed/-Users-alice-code-myapp/faithful/index.yamlprocessed/-Users-alice-code-myapp/dialogue/2026-07-21_3f2c9d41.fork-cea3cb99.mdprocessed/-Users-alice-code-myapp/dialogue/2026-07-21_3f2c9d41.mdprocessed/-Users-alice-code-myapp/dialogue/index.yamlRe-running over an unchanged archive reports wrote=0 unchanged=6 — the
converter is idempotent. Note the fork transcript is emitted alongside the
main lineage, and each profile folder carries an index.yaml of its sessions.
propose_consolidation.py
Authoring helper for projects.json: propose consolidate_into groupings
from git remotes, so ~100 auto-appended rows need no hand-editing. For each
row it recovers the project’s true working directory from the archive itself
(the first cwd field in any transcript — encoded names cannot be reversed
reliably), reads that repo’s origin URL when it exists locally, and groups
rows sharing a remote. It only proposes: nothing is written without
--apply, an existing different consolidate_into is never overwritten
(warned instead), and the converter never depends on this tool.
python3 scripts/process/propose_consolidation.py --root ROOT [--apply] [-v]| Flag | Type | Default | Required | Meaning |
|---|---|---|---|---|
--root | path | $PIBMO_ROOT | yes* | Dataset root. |
--apply | flag | off | no | Write the proposals into {root}/projects.json. Default is a dry run. |
-v, --verbose | flag | off | no | Explain every skipped row. |
* Required as either the flag or the environment variable.
$ python3 ~/code/pibmo-recall/scripts/process/propose_consolidation.py --root "$ROOT" -v skip -Users-alice-code-myapp (/Users/alice/code/myapp is not a local git repo with an origin)No new consolidation proposals.When there are proposals, each prints as
<key> -> consolidate_into: <target> (the canonical row of a group is the
curated one when present, else the shortest key), the dry run ends with
Dry run — re-run with --apply to write these into <path>, and --apply
confirms with Applied N proposal(s) to <path>.
import_legacy.py
One-time import of a pre-reset keyed archive into the faithful single-root
layout. Resolves each legacy project folder back to its encoded path (via the
reverse map in projects.json and the cwd fields inside the transcripts),
routes every file through the same preservation engine as the sync, and takes
the same root lock — an import cannot race the hourly tick. Anything it
cannot place is listed as UNRESOLVED rather than silently dropped.
python3 scripts/sync/import_legacy.py --root ROOT --legacy PATH [--machine NAME ...] [-v] [--dry-run]| Flag | Type | Default | Required | Meaning |
|---|---|---|---|---|
--root | path | — | yes | New dataset root (must already be installed). |
--legacy | path | — | yes | The renamed pre-reset archive. Must be disjoint from --root. |
--machine | string | all | no | Only import this legacy machine folder; repeatable. |
-v, --verbose | flag | off | no | Print every file action. |
--dry-run | flag | off | no | Classify and report without writing. |
$ python3 ~/code/pibmo-recall/scripts/sync/import_legacy.py --root "$ROOT" \ --legacy ~/Datasets/pibmo-legacy --dry-run -vImporting legacy machine 'oldmac'... new legacy:oldmac/-Users-alice-code-myapp/7be14a90-2c33-47d1-b5aa-90e2f1c7d301.jsonl → -Users-alice-code-myapp/7be14a90-2c33-47d1-b5aa-90e2f1c7d301.jsonl {"new": 1}
=== Import summary ==={ "oldmac": { "new": 1 }}Importing a file that already exists in the root classifies exactly like the
sync would (identical, extend, fork) — the append-only rules hold for
imports too.
session_names.py
Read-only probe over a Claude Code data directory: extract every session’s
display name (custom /rename titles and auto titles), and audit the
name-bearing JSONL structures against the documented schema baseline so
format drift is caught before it bites the converter. It writes nothing,
anywhere.
python3 scripts/probe/session_names.py [--root DIR] [--project NAME] [--json | --check]| Flag | Type | Default | Required | Meaning |
|---|---|---|---|---|
--root | path | ~/.claude | no | Claude Code data dir to scan. May also point at an archive’s per-machine dir, e.g. {root}/{machine}/claude. |
--project | string | all | no | Limit to a single encoded project dir name. |
--json | flag | off | no | Emit a machine-readable snapshot (for periodic diffing). |
--check | flag | off | no | Audit only: print drift anomalies and exit non-zero if any. |
$ python3 ~/code/pibmo-recall/scripts/probe/session_names.py --root "$ROOT/mymac/claude" --checkOK: name-bearing structures match the 2026-05-29 baseline (2 transcript(s), 0 pointer(s)).Exit 0. On drift it prints DRIFT: N anomaly(ies) vs baseline <date>: with
one ! line per anomaly and exits 1; a missing --root exits 2. The default
human report additionally lists live session pointers, resolved --resume
names per project, and the earliest Claude Code version each event type was
seen in.
Related pages
- Overview — what Recall is and is not.
- Getting started — from nothing to an archiving machine.
- Guided install — the agent-driven setup.
- Concepts — the model these commands operate on.
- Configuration —
machines.json,projects.json,profiles.json, environment variables. - Topologies — one machine vs a consolidated fleet.
- Host integration — the session-start banner.
- How it works — the preservation engine and the sync stages.
- Troubleshooting — when a machine stops archiving.
- FAQ — privacy, credentials, replication.
- v1 on-disk contract — the dataset-root format.