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_tois set andageis 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
Metadata
Release files for claude-backup-cron 0.1.6
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| claude_backup_cron-0.1.6.tar.gz | 38.6 kB | With provenance | Details for claude_backup_cron-0.1.6.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| claude_backup_cron-0.1.6-py3-none-any.whl | Python 3 | none | any | Details for claude_backup_cron-0.1.6-py3-none-any.whl |
Total release size: 69.0 kB
Release files / claude_backup_cron-0.1.6.tar.gz
| Download URL | claude_backup_cron-0.1.6.tar.gz |
|---|---|
| Size | 38.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
80dcc605f4538abb2fb9754dd3bacdab5d4f42db336fb82202e1a3c6b03d7719
|
|
BLAKE2b-256 checksum How to use checksums |
008e2ed8706c8afb6061c06a064a9e05cbfefb9a058ea1e602719a039d7bdaf2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 19, 2026.
Transparency logRelease files / claude_backup_cron-0.1.6-py3-none-any.whl
| Download URL | claude_backup_cron-0.1.6-py3-none-any.whl |
|---|---|
| Size | 30.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
222f24bddf8cd147d626a72cd2c0e39a788aff93eab948c1b7beff7a55714666
|
|
BLAKE2b-256 checksum How to use checksums |
9ef44aa9bf63f053b7d220aaba1d483a27cb6b8359ba29c37581f6c63676a85c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 19, 2026.
Transparency logSecurity for claude-backup-cron 0.1.6
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for claude_backup_cron-0.1.6.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 19, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.