mcp server
aivault
Versioned backup, full-text search and disk hygiene for the local state of every AI CLI (Claude, Gemini, Copilot, Continue, Cursor, aichat).
Set up
Runs on your computer. Pick your agent and operating system.
Before you start
- uv (`curl -LsSf https://astral.sh/uv/install.sh | sh`)
{
"mcpServers": {
"aivault": {
"command": "uvx",
"args": [
"aivault"
]
}
}
}same format Cursor, GitHub Copilot CLI, Junie, JetBrains AI Assistant, Augment (Auggie CLI), Factory Droid, Kiro, Devin CLI +12
Values in angle brackets are placeholders. Restart Claude Desktop after editing its config.Claude Desktop docs
README
synced Oct 27, 2026aivault
One vault for the local state of every AI CLI on your machine.
Versioned backup · full-text search · disk hygiene — for Claude Code, Gemini, Copilot, Continue, Cursor, and aichat, from a single command.
Why
Every AI CLI you run scatters state across your home directory: durable config and memory you'd hate to lose, thousands of past session transcripts, secrets that must never leave the box, and gigabytes of regenerable cache. None of these tools talk to each other, none give you a real backup, and none let you search what you did last week.
aivault treats all of them uniformly:
- Back up each tool's state as versioned, deduplicated snapshots — locally and, optionally, to your own encrypted cloud remote.
- Restore any snapshot, whole or file-by-file — recover a deleted session or undo a bad config change.
- Search & recall across every past session (SQLite FTS5) — from the CLI, or from Claude itself via a read-only MCP server.
- Reclaim disk by clearing regenerable junk and pruning stale sessions — always snapshot-first, dry-run by default.
Secrets never leave your machine: a global denylist (credentials, OAuth tokens,
*.key, account files, daemon state) is applied to every tool on every
operation.
Supported tools
Each tool is one adapter. Adapters whose root directory doesn't exist are simply inactive — aivault only manages what's installed.
| Tool | Root | What's captured |
|---|---|---|
| Claude Code | ~/.claude | CLAUDE.md, settings, memory, skills, commands, agents, projects/sessions |
| Gemini CLI | ~/.gemini | GEMINI.md, settings, commands, history/state |
| Copilot CLI | ~/.copilot | config, session-state, command history |
| Continue | ~/.continue | config, sessions |
| Cursor | ~/.cursor | argv/config |
| aichat | ~/.config/aichat | config, roles, macros, sessions |
Install
Requires Python 3.10+ and (for cloud mirroring) rclone.
git clone https://github.com/KaulikMakwana/aivault.git
cd aivault
python3 -m venv .venv
./.venv/bin/pip install -e .
# put the launcher on your PATH so plain `aivault` works:
ln -sf "$PWD/.venv/bin/aivault" ~/.local/bin/aivault
rehash # zsh: refresh the command cache (or open a new terminal)
Without the symlink, call it by its full path (./.venv/bin/aivault …).
Quick start
aivault init # detect tools, pick a cloud remote (or local-only)
aivault status # what's installed, snapshot/index/cloud state
aivault backup # snapshot every tool (+ mirror to your remote)
aivault index # build the search index
aivault search "kerberoast" # find it across all sessions
aivault hygiene # show reclaimable junk (dry-run)
aivault hygiene --clear-caches --apply # actually reclaim it
Concepts
Adapters & categories. Each adapter classifies its files into three buckets:
- durable — config, memory, skills, commands you'd want on a fresh machine.
- sessions — chat/transcript history (searchable, exportable).
- junk — caches, temp, embeddings indexes; regenerable, safe to delete.
Backup captures durable + sessions (never junk, never secrets). kit captures
durable only. hygiene targets junk.
Snapshots (hardlink dedup). Each backup writes
~/.aivault/snapshots/<tool>/<UTC-timestamp>/ plus a manifest.json (sha256 per
file). Files unchanged since the previous snapshot are hardlinked (shared
inode), so many snapshots of mostly-static state cost roughly one copy on disk —
no repo bloat, trivial partial restore.
Search index. A local SQLite FTS5 index (~/.aivault/index.db) extracts
(tool, session, role, text) from every session, updated incrementally by file
mtime. search ranks hits, recall returns top-k chunks, export renders a whole
session to Markdown.
The mirror. If you choose a cloud remote, the snapshot store is mirrored with
rclone sync — the remote is an exact mirror of local, so deletions propagate.
Self-contained. aivault's own state lives at ~/.aivault/, outside every tool's
root, so it never backs up or indexes itself.
Command reference
| Command | What it does |
|---|---|
init | create state, detect tools, choose a cloud remote, seed the secrets filter |
status | tools detected, sizes, snapshot/index/cloud/trigger state |
backup [--tool T] [--label L] [--no-push] | versioned snapshot of each tool (+ cloud mirror) |
versions [--tool T] | list snapshots |
restore <id> [--dry-run] | restore a snapshot back into a tool's root |
pull [--tool T] [--dry-run] | hydrate the local store from the cloud (second machine) |
session list [--tool T] [--filter REF] | list live sessions (optionally narrowed) |
session backup [ref] [--tool T] [--label L] [--no-push] | scoped snapshot of one session/project (omit ref → picker) |
session restore [ref] [--tool T] [--dry-run] | restore one session from its backups (omit ref → picker) |
session delete [ref] [--tool T] [--live] [--dry-run] | delete a session's backups (and, with --live, the transcript) |
delete <id> [--local-only] [--remote-only] [--dry-run] | delete a specific snapshot |
prune [--tool T] [--keep-n N] [--keep-days D] [--dry-run] | apply retention |
index [--tool T] [--rebuild] | (re)build the FTS5 search index (optionally for one tool) |
search QUERY [--phrase] [--command] [--tool T] [--limit N] | full-text search over all sessions |
recall QUERY [-k N] [--tool T] | top-k context chunks for a query |
export <session_id> [--out FILE] | render a session to Markdown (accepts an id prefix) |
pick [--out DIR] | interactive picker → export selected sessions |
kit export <tool> [--out FILE] | bundle a tool's durable config (secrets stripped) |
kit apply <archive> --tool T [--apply] | restore a kit on a fresh box (dry-run default) |
hygiene [--tool T] [--clear-caches] [--prune-sessions] [--apply] | reclaim junk / prune (dry-run default) |
mcp | run the read-only MCP server (stdio) |
install-triggers / uninstall-triggers | Claude SessionEnd auto-backup |
--version / --update | print version / update to latest (git pull + reinstall) |
--uninstall [--purge-state] [--yes] | remove aivault from this box (keeps backups unless --purge-state) |
Search: words vs phrase
search QUERY matches messages containing all the words, anywhere (best recall).
Add --phrase to require the exact, adjacent phrase:
aivault search "cli application" # both words, anywhere in a message
aivault search "cli application" --phrase # only where they appear together
The Session column in results is shortened for readability — export accepts that
shortened id (or any unique prefix), so you can copy what you see.
Searching commands the AI ran
--command narrows a search to the shell commands your AI tools actually
executed, each paired with its captured output — so you can find what a tool
did, not just what was said about it:
aivault search "git push" --command --tool claude # commands, with their output
Command rows are extracted from Claude's structured tool calls (other CLIs are
best-effort). Because output routinely prints tokens and keys, captured output is
redacted before it's indexed (Authorization: Bearer …, api_key/token/…=…,
AWS keys, PEM blocks, long base64/hex blobs → «redacted»). Run aivault index --rebuild once after upgrading to backfill command rows for existing sessions.
Scoping to one tool
--tool NAME restricts an operation to a single AI CLI instead of all of them.
Available on backup, versions, search, recall, prune, and hygiene:
aivault backup --tool claude
aivault search "oauth" --tool gemini
aivault hygiene --tool gemini --clear-caches --apply
Deleting snapshots
Because the remote mirrors local, delete <id> removes a snapshot from both by
default. --local-only / --remote-only scope it, but the mirror reconciles on the
next backup (a local-only delete also drops the remote copy next sync; a
remote-only delete gets re-uploaded). Destructive — confirms by default; use
--dry-run to preview. Deleting a tool's last snapshot leaves no empty directory
behind, and purging a remote copy that is already gone is treated as success.
One session at a time
backup snapshots a whole tool root. When you only want one session or project —
say the sessions under ~/Desktop — the session group targets it directly, by
project path or by session id (the value search shows):
aivault session list --tool claude # see every session, per-project
aivault session backup ~/Desktop # scoped snapshot: just that project's transcripts
aivault session restore ~/Desktop --dry-run # restore only those files
aivault session delete 4cf4897e # delete that session's backups
aivault session delete ~/Desktop --live # ALSO erase the real transcript (gated)
Or just pick. Omit the ref and session backup/restore/delete open an interactive
menu (like pick) — no path or id to type. --tool pre-filters the list:
aivault session backup # menu of live sessions → check some → scoped backup
aivault session restore # menu of backed-up sessions → restore
aivault session delete --live # menu of live sessions → erase (gated)
The ref form stays fully scriptable; off a terminal (piped/cron) a missing ref errors instead of hanging.
A scoped backup copies only the matching transcript(s), not the whole 300 MB+ root, so
saving a single session is cheap. session delete removes the session's own scoped
backups by default; --live additionally erases the real transcript from the tool and
drops it from the search index. Full snapshots are immutable point-in-time images and
are never edited by session delete.
Second machine: pull from the cloud
backup pushes the encrypted store up. On another box, pull brings it down so
restore has something to work with:
aivault init --remote-path NAME:aivault # same remote as machine A
aivault pull # hydrate the local store (additive, no deletes)
aivault versions # now populated from the cloud
aivault restore latest:claude # or `session restore <ref>`
aivault index also self-heals: sessions you deleted on disk are pruned from the search
index on the next run, so search never returns a transcript that no longer exists.
Let Claude search its own history (MCP)
claude mcp add aivault -- /absolute/path/to/aivault/.venv/bin/aivault mcp
Exposes read-only tools — aivault_search, aivault_recall,
aivault_get_session, aivault_list_snapshots. No backup, restore, delete, or any
write is reachable over MCP, by design.
Auto-backup on Claude session end
aivault install-triggers # adds a SessionEnd hook to ~/.claude/settings.json
Each time a Claude Code session ends, aivault snapshots Claude's state in the
background (non-blocking, output to its log). The hook is merged into your existing
settings — other hooks are preserved — and uninstall-triggers removes only what it
added.
Security & privacy
- Secrets never leave the box. A global denylist (
*credentials*,*token*,*oauth*,*.key,*.pem,*_accounts.json,daemon*, …) plus each adapter's own secret rules is applied to every snapshot, every index, and every cloud push. - Cloud is opt-in and encrypted. No remote is configured by default; on
inityou pick one of your own rclone remotes (use an encryptedcryptremote) or stay local-only. aivault never ships a default remote. - The MCP server is strictly read-only.
- Destructive ops are gated —
restore,delete,prune, andhygienedefault to dry-run / confirmation, and hygiene snapshots before deleting.
Where state lives
~/.aivault/
config.json # your settings (remote, retention, update-check)
snapshots/<tool>/<ts>/ # versioned snapshots + manifest.json
index.db # FTS5 search index
filters/secrets.txt # rclone safety filter
aivault.log # operation log
Updating
aivault --update # git pull --ff-only on your clone + reinstall
On interactive commands aivault checks its origin for newer commits at most once a
day and prints a one-line notice when an update is available — never on the mcp or
piped paths. Opt out with AIVAULT_NO_UPDATE_CHECK=1, or set check_updates: false
in ~/.aivault/config.json.
Uninstalling
aivault --uninstall # remove aivault, KEEP local backups
aivault --uninstall --purge-state # also delete ~/.aivault (backups + index)
--uninstall prints exactly what it will do, then (after confirmation) removes the
Claude auto-backup trigger, the MCP registration (claude mcp remove aivault), the
~/.local/bin/aivault symlink, and the pip package. Your backups at ~/.aivault
are kept unless you pass --purge-state (which asks a second time), and the
cloud remote is never touched. It finishes by printing the one manual step it
won't do for you — rm -rf on the source clone/venv it's running from. Use --yes
to skip the prompts in non-interactive contexts.
Development
./.venv/bin/pip install -e '.[test]'
./.venv/bin/pytest -q
Tests run against a fully isolated temporary HOME with planted fake secrets, and assert the security spine (secrets reach no snapshot, no index) plus backup/restore round-trips. No real state is touched.
License
Apache-2.0.