Back up & restore projects
Hydrate's backup / restore workflow moves a project's memory between machines without uploading anything. You get one encrypted file, a passphrase, and symmetric CLI commands.
Dehydrate is a separate feature, coming soon — it ingests your
CLAUDE.mdand docs into Hydrate and shrinks them. Backup / restore is about moving an existing Hydrate project between machines. The two don't overlap.
Pro tier only. Free users can still run Hydrate locally and use the blunt whole-DB backup; per-project bundles are the portable-memory feature Pro pays for.
The three commands
hydrate backup --project=<slug> [--passphrase=<pass>] [--out=<path>]
hydrate restore <bundle> [--passphrase=<pass>] [--merge=<strategy>] [--dry-run] [--yes]
hydrate inspect <bundle> hydrate backup
Produces a self-contained, passphrase-encrypted file (AES-256-GCM, Argon2id key derivation). Includes every fact, session summary, and retrieval metric tied to the project — but not your user-scope preferences, licenses, or sync state.
hydrate backup --project=pulse
passphrase:
passphrase (confirm):
backed up 247 facts, 34 sessions, 12 metrics → pulse.hyd.json (2.7 MiB) hydrate inspect
Reads the unencrypted metadata trailer — no passphrase required. Useful to sanity-check a bundle before you restore it.
hydrate inspect pulse.hyd.json
bundle: pulse.hyd.json
magic: HYD1
format_version: 1
exported_at: 2026-04-18T06:15:00Z
project: pulse
facts: 247
session_summaries: 34
metrics: 12
total_size: 2803671 bytes hydrate restore
Decrypts, validates, shows a merge preview, and applies. Everything lands in a single SQLite transaction — a failure mid-restore rolls back to the prior state.
hydrate restore pulse.hyd.json --merge=merge-newer
passphrase:
Import preview for project "pulse" (--merge=merge-newer):
+ 47 new facts
~ 3 facts updated (newer content)
= 18 facts unchanged (duplicates)
+ 5 new session summaries
Apply? [y/N]: y
restored project "pulse" via merge-newer: 47 new, 3 updated, 18 unchanged facts; 5 new, 0 updated sessions; 12 metrics Merge strategies
Pick via --merge=<strategy>. Default is reject, the safest option.
- reject (default) — aborts with "project already exists" if the slug is already on this machine. Zero writes. First use on a new machine, no collisions possible.
- replace — drops the existing project and re-inserts everything from the bundle. Use when the bundle is the authoritative copy (e.g. restoring from an earlier backup).
- merge-newer — for each
(project_id, content_hash)pair, keeps whichever side has the higherupdated_attimestamp. Ties go to the local copy. The day-to-day cross-machine sync strategy. - merge-union — adds any fact whose
content_hashisn't already present locally; skips duplicates without touching local rows. Use when a teammate sends you their bundle and you want to fold in their facts without overwriting yours.
Preview before committing
For merge-newer and merge-union, the preview always runs and you
confirm with y. Pass --yes to skip the prompt (useful in scripts) or
--dry-run to print the preview and exit without writing.
Example: move Pulse from laptop A to laptop B
# On laptop A
hydrate backup --project=pulse
scp pulse.hyd.json laptopB:/tmp/
# On laptop B
hydrate restore /tmp/pulse.hyd.json That's the whole flow. The bundle is passphrase-encrypted, so copying it over an insecure channel (email, USB stick, public Wi-Fi scp) is still safe — brute-forcing Argon2id+AES-GCM is not a weekend project.
Example: teammate shares their facts
# Teammate backs up
hydrate backup --project=pulse --out=alex-pulse.hyd.json
# You restore without overwriting your own work
hydrate restore alex-pulse.hyd.json --merge=merge-union Your facts stay unchanged; any Alex fact that doesn't already exist on your machine lands.
Embedding dimension mismatches
Bundles record the embedding model + dim they were built with. If your local install uses a
different embedder (e.g. bundle used 384-d all-MiniLM-L6-v2, your install uses
1536-d text-embedding-3-small), the restore still succeeds but:
- The fact rows land with their metadata intact.
- Their embeddings are discarded — silently storing mismatched-dim vectors would break retrieval in subtle ways.
- Each such fact is queued for re-embedding with your local embedder.
- A warning line tells you how many facts were queued.
Check the configured dim with hydrate config get embed.dim. Override it for a
restore with HYDRATE_EMBED_DIM=1536 hydrate restore ....
Pre-flight check
hydrate doctor
Runs license / config / embed-dim / store / round-trip checks. Prints READY TO SHIP
when green. Safe to run any time you're unsure a fresh clone is wired up correctly.
Troubleshooting
-
wrong passphrase— GCM authentication failed. Double-check capitalisation and trailing whitespace. -
bundle is corrupted or incomplete— the file was truncated in transit. Re-copy. -
this bundle was exported from a newer Hydrate; please upgrade—format_versionexceeds what this build supports. Upgrade withbrew upgrade hydrate(or run the installer again). -
project 'pulse' already exists— with--merge=reject(the default) collisions abort. Rerun with--merge=replace,merge-newer, ormerge-uniondepending on intent. -
Did you mean `hydrate backup`?— you ran the pre-v0.2 name (hydrate export/hydrate import). The commands were renamed tobackup/restorein v0.2. The bundle format is unchanged. - Free-tier cap reached — Free is capped at 2 active projects. Run
hydrate project deactivate <slug>to make room, or upgrade to Pro for unlimited projects.
What's out of scope
- No cloud sync. Ever. The whole point of per-project bundles is that the user controls the file.
- No incremental / delta bundles in v0.3. Each backup is a full snapshot. Post-launch.
- No team-tier shared memory — separate plan, separate pricing tier.