Skip to main content

Scheduled encrypted backups for Claude Code memory and similar small directories.

Project description

claude-backup-cron

Scheduled, encrypted backups for small-but-high-value directories — Claude Code's memory/ folder in particular, but anything the shape would fit.

Disclaimer: This is an independent third-party tool. It is not affiliated with, endorsed by, or sponsored by Anthropic. "Claude" and "Claude Code" are trademarks of Anthropic and are used here nominatively to identify the directory layout this tool happens to back up.

What it does

  • Tars each configured source directory into a deterministic artefact.
  • Skips the run entirely if nothing has changed since last time (content hash, not mtime — mtime lies).
  • Optionally encrypts the artefact with age before it ever reaches a destination.
  • Fans out to one or more destinations — a private git remote, an S3 bucket, a spare local drive — with independent success/failure per destination.
  • On any failure, posts a short message to an optional webhook (Discord/Slack shape).
  • Installs itself as a cron job with a one-liner.

Zero runtime dependencies on Python 3.11+; tomli backport on 3.10. External binaries (git, aws, age, crontab) are invoked only when the corresponding feature is actually used.

Why

The default memory-backup.sh approach that ships in many Claude Code setups works well for single-machine, single-destination use — but it intentionally does not cover multi-destination failover, encryption, content-hash change detection, or structured failure reporting. This package adds those features for higher-reliability deployments where the operator is not watching the cron logs every day: strict typing, deterministic artefacts, structured failures, audit-friendly CLI.

Install

pipx install claude-backup-cron

Or in a venv:

python3 -m venv ~/.local/venvs/claude-backup-cron
~/.local/venvs/claude-backup-cron/bin/pip install claude-backup-cron

See docs/INSTALL.md for setup on each destination kind (git remote, S3 bucket, local path).

Configure

Default config location: ~/.config/claude-backup-cron/config.toml. Override with $CLAUDE_BACKUP_CRON_CONFIG.

Minimal example:

[global]
alert_webhook = "https://discord.com/api/webhooks/..."

[[sources]]
id = "claude-memory"
path = "~/.claude/projects/-home-USER/memory"
exclude = [".git/*", "*.swp"]

[[destinations]]
id = "offsite-git"
kind = "git"
remote = "git@github.com:me/claude-memory-backup.git"
branch = "main"
encrypt_to = "age1abc..."   # omit to upload plaintext

Verify it parses:

claude-backup-cron show-config

A fuller example covering all three destination kinds lives in examples/config.toml.

Run

claude-backup-cron run              # do the thing
claude-backup-cron run --dry-run    # package sources but don't upload
claude-backup-cron run --json       # machine-readable report on stdout

Exit codes:

Code Meaning
0 All steps succeeded (or nothing to do).
2 At least one source→destination step failed. Others may have succeeded.
3 Config or encryption setup error — nothing was uploaded.

Schedule

claude-backup-cron install-cron --schedule "0 3 * * *"   # daily 03:00
claude-backup-cron uninstall-cron

The installer manages a single block in your user crontab, marked with # claude-backup-cron managed entry. Re-running install-cron replaces the previous block in place.

Encryption

Set encrypt_to = "age1..." on a destination. The artefact is piped through age --recipient <...> before upload. We refuse to fall back to plaintext on encryption failure — that's exactly the degradation you don't want in a backup tool.

To decrypt later:

age --decrypt -i ~/.ssh/my-age-key claude-memory-abc123.tar.age \
  | tar -xvf -

Library API

from claude_backup_cron import load, run

config = load()
report = run(config, dry_run=False)
if not report.ok:
    for failure in report.failed:
        print(failure.source_id, "→", failure.destination_id, failure.message)

All public types are frozen dataclasses (Config, SourceSpec, DestinationSpec, RunReport, StepResult, Artefact, Upload). Typed Python (py.typed); passes mypy --strict.

Design commitments

  • Never silently downgrade encryption. If encrypt_to is set and age is missing, the destination fails — it does not upload plaintext.
  • Independent destination failures. A dead S3 bucket must not prevent the git push that follows.
  • Deterministic artefacts. The same tree produces the same tarball bytes (mtime/uid/gid zeroed) so destinations can no-op when nothing has changed.
  • Zero telemetry. No phone-home, no metrics. A backup tool that beacons is a backup tool that will be firewalled off.

Picking a destination kind

Quick rule of thumb:

Kind Good for Avoid when
git Small sources (< ~100 MB), full version history matters The source is large and churns; every run adds a blob to .git/objects that is never deleted.
s3 Offsite durability with a lifecycle rule for rotation You don't have (or don't want) an AWS-shaped account.
local Spare drive, second machine on LAN, bounded retention (retain = N) You need the backup to survive the laptop being stolen.

Mix and match — having one git destination for history and one local destination for recent rollback is a common shape.

Threat model & non-goals

  • In scope: accidental data loss (mistaken rm, disk failure, lost laptop, revoked cloud account). The remote copies let you rebuild.
  • Out of scope: targeted attack by someone with root on the host. If the attacker can read your config and your age identity file, they can already read your unencrypted source — this is a backup tool, not a sealing room.
  • Out of scope: real-time sync. The minimum meaningful schedule is whatever cron runs; continuous replication is a different product.

See SECURITY.md for the vulnerability reporting process.

Verification (sigstore)

Releases from v_next_ (released after 2026-05-16) include a sigstore keyless signature bundle (.sigstore per artifact) attached to the GitHub Release.

Verify a PyPI install

pip download <pkg-name>==<version> --no-deps -d ./verify
python -m sigstore verify github \
    --cert-identity 'https://github.com/hinanohart/claude-backup-cron/.github/workflows/release.yml@refs/tags/v<version>' \
    --cert-oidc-issuer 'https://token.actions.githubusercontent.com' \
    ./verify/*.whl ./verify/*.tar.gz

The corresponding .sigstore bundles can be downloaded from the GitHub Release page.

Historic releases (pre-2026-05-16)

Earlier releases were published without sigstore bundles. Re-installing those versions provides no cryptographic provenance — pin to a current release if assurance matters.

License

MIT. See LICENSE and NOTICE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

claude_backup_cron-0.1.6.tar.gz (38.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

claude_backup_cron-0.1.6-py3-none-any.whl (30.4 kB view details)

Uploaded Python 3

File details

Details for the file claude_backup_cron-0.1.6.tar.gz.

File metadata

  • Download URL: claude_backup_cron-0.1.6.tar.gz
  • Upload date:
  • Size: 38.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for claude_backup_cron-0.1.6.tar.gz
Algorithm Hash digest
SHA256 80dcc605f4538abb2fb9754dd3bacdab5d4f42db336fb82202e1a3c6b03d7719
MD5 af25aa922cdfab371a9669016ddfb52e
BLAKE2b-256 008e2ed8706c8afb6061c06a064a9e05cbfefb9a058ea1e602719a039d7bdaf2

See more details on using hashes here.

Provenance

The following attestation bundles were made for claude_backup_cron-0.1.6.tar.gz:

Publisher: release.yml on hinanohart/claude-backup-cron

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file claude_backup_cron-0.1.6-py3-none-any.whl.

File metadata

File hashes

Hashes for claude_backup_cron-0.1.6-py3-none-any.whl
Algorithm Hash digest
SHA256 222f24bddf8cd147d626a72cd2c0e39a788aff93eab948c1b7beff7a55714666
MD5 436b0c1d42738bb4589f3e8dbe7f3161
BLAKE2b-256 9ef44aa9bf63f053b7d220aaba1d483a27cb6b8359ba29c37581f6c63676a85c

See more details on using hashes here.

Provenance

The following attestation bundles were made for claude_backup_cron-0.1.6-py3-none-any.whl:

Publisher: release.yml on hinanohart/claude-backup-cron

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page