Three commands handle everything from reclaiming disk space to carrying your
session history across machines. Every destructive operation writes a tar
archive to ~/.cache/tokmeter/backups/ first, and restore auto-remaps paths
when the source and target homedirs differ (different user, different OS).
tokmeter cleanup # interactive stepper: pick projects → dates → confirm
tokmeter snapshot # non-destructive backup (nothing is deleted)
tokmeter restore # list all local backups
tokmeter restore --latest # restore the most recent backup
tokmeter restore --id <backup-id> # restore a specific archive
Interactive cleanup walks you through three steps: pick one or more projects, pick the dates to wipe (or “all”), then confirm. A backup archive is created before anything is deleted; restores replay that archive back into place.
Snapshot is the same machinery without the deletion — use it when you just
want a portable copy of your session data. It drops a .tar.gz plus a
.meta.json beside it; copy both files to another machine’s
~/.cache/tokmeter/backups/ and run tokmeter restore --latest there.
Cross-machine restore works without configuration. The archive records the
source $HOME, username, and platform. On restore, if the target homedir
differs, paths are transparently remapped (e.g. /home/alice/.claude/... →
/Users/bob/.claude/...) and the confirmation prompt shows
Source → Target → Mode so you know exactly what will happen.
UUID collision handling (cross-machine restores): if a restored session would overwrite a session that already exists locally (same UUID from working on both machines), the restored copy gets a freshly-minted UUID instead — propagated consistently across all seven associated paths (transcript, subagents, file-history, tasks, todos, session-env, and the project index entry). Local sessions with the same id stay put; the restored ones land alongside them with new ids. A same-machine restore (same home directory) extracts the archive back to the original paths instead, replacing any file currently at the same path.
Caveat: JSONL-based providers (Claude Code, Codex, OpenCode, Gemini, Kimi, Qwen, etc.) restore end-to-end. SQLite-backed providers (Cursor, VS Code, Roo/Kilo) are backed up at the row level but not re-injected on restore — their data shows up in tokmeter stats once re-indexed, but isn’t written back into the editor’s SQLite DB.
What restore will and won’t write
Snapshots are made to move between machines, so restore treats an archive as untrusted input:
- Entry types are checked first. Only regular files and directories may
come out of a backup. Symlink, hardlink, device and fifo entries, and any
path with a
..segment, are refused before anything is extracted. - Extraction happens in a private temp directory (mode 0700), never at
/. The extracted tree is checked again withlstat: no symlinks, regular files only, no multiply-linked files. The temp directory is always removed. - Files are copied into place only inside an allowlist. The allowlist is
the session paths tokmeter’s own scanner reads, plus the Claude Code side
directories (
file-history,tasks,todos,session-env), tokmeter’saliases.jsonandconfig.json, and the backup’s own SQL-dump directory. The scanner paths come from each provider’ssessionRoots, the same function its scan uses, including anyproviderPathsand custom sources in~/.tokmeter/config.json. A configured path that is$HOMEitself, or one of its parents, is ignored. - A cross-home remap must stay inside
$HOMEand inside that allowlist. Entries outside the source home are ignored, as before. - All or nothing. If any file fails a check, the restore stops before anything is written and reports which entry was refused.
- File modes (without setuid/setgid) and mtimes are kept, as
tar -xkept them. UUID re-minting on cross-home collisions works as described above. - A snapshot whose meta file records another machine’s archive path restores
from the
<id>.tar.gzthat sits next to the meta file.
If a restore you expect to work is refused, the error names the entry. Usually
it’s a file outside every provider’s session path, such as a session directory
you moved and pointed tokmeter at only on the old machine. Add that location
under providerPaths in ~/.tokmeter/config.json, then restore again.
Confirmation and backup: where the gate lives
Cleanup deletes raw session files, so every path has a confirmation step and a pre-delete backup. Where that confirmation comes from depends on how you call cleanup — and agents driving the MCP server over stdio can only preview.
CLI
tokmeter cleanup # interactive: prompts "type DELETE"
tokmeter cleanup --project app --until 2026-10-04 # flag-driven, still prompts
tokmeter cleanup --project app --until 2026-10-04 --dry-run # preview only
tokmeter cleanup --project app --until 2026-10-04 --force # skip the prompt (still needs a terminal)
- Interactive and flag-driven runs both prompt
Type DELETE to confirmbefore deleting.--dry-runpreviews and deletes nothing.--forceskips the prompt (for scripts) — it does not skip the backup. - Backup is always on in the CLI. A
.tar.gzis written to~/.cache/tokmeter/backups/before the first file is removed; there is no--no-backupflag.
MCP (preview only)
An agent calling over stdio never sees a terminal prompt, so the MCP server doesn’t delete or restore anything:
tokmeter_cleanup_previewreports the exact files, bytes, per-project/provider breakdown and partial-file warnings, then tells the user to runtokmeter cleanupwith the same filters. It deletes nothing.tokmeter_backupslists backups. There is no MCP restore; the user runstokmeter restore.- Deleting and restoring always go through a human, at a terminal or in the TUI. See MCP tool reference for what earlier releases exposed.
From 1.15.0, an empty filter is refused, in core, for every caller (CLI,
TUI, daemon HTTP). With no project, no providers and no date range, a cleanup
would match every session of every provider. Name at least one of: project,
providers, since/until, or a today/week/month scope. Provider-only
and date-only cleanups still work. The interactive CLI’s “all” choice is
unaffected, because it passes the explicit list of projects.
Something wrong or out of date? This page is generated from its source on GitHub, at the revision this site was checked against.