undo-anything

module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 15, 2026 License: MIT

README

⏪ undo-anything

A universal local time machine for any folder — with one-key restore.

undo-anything quietly snapshots your folder on every save — content-addressed, deduplicated, and fully local — so you can restore any file, or the whole tree, to any point in time. Including the sweeping edit your AI agent made and you already accepted. Never lose work again.

CI Release Go Reference Go Report Card


Try it in one line — no signup, no config, no network:

go run github.com/agenticraptor/undo-anything/cmd/ua@latest init

That starts tracking the current folder and captures a baseline you can already restore to. Then ua daemon start to snapshot on every save.

⏪ undo-anything timeline   142 snapshots · .../code/api

╭────────────────────────────────────╮ ╭──────────────────────────────────────╮
│ ● 92ac1bd72b54  just now            │ │ Snapshot 92ac1bd72b54                 │
│   4 files                           │ │ taken  2026-06-15 23:13:15 (just now) │
│ ● c12288b7b17a  4m ago              │ │ kind   watch                          │
│   before restore to bd304373        │ │ files  4 (98 B)                       │
│ ● 056d1f13143a  1h ago              │ │                                       │
│   refactor: extract retry client    │ │ Changes vs parent                     │
│ ● bd304373c46f  3h ago              │ │ + internal/retry/retry.go             │
│   initial snapshot                  │ │ ~ internal/payments/client.go         │
│                                     │ │ - internal/payments/old_client.go     │
╰────────────────────────────────────╯ ╰──────────────────────────────────────╯
 ↑/↓ move · r restore · pgup/pgdn scroll · q quit

The problem

You're coding with an AI agent. It makes a big, mostly-good change across a dozen files. You accept it. Ten minutes later you realize it quietly rewrote a function you needed — and it's not in git (you hadn't committed), not in your editor's undo (you reopened the file), and not in any diff you can find.

Existing safety nets don't cover this gap:

Tool Why it falls short
git Manual, commit-scoped, repo-only. The work you lose is usually the uncommitted work.
Time Machine macOS-only, not open source, hourly, slow, not per-folder or scriptable.
Editor "local history" Locked inside one editor; gone if you switch tools or work outside it.

undo-anything fills it: a tiny, zero-config daemon that snapshots any folder the instant a file changes, and lets you jump back to any second — one command, fully local.

Why you'll like it

  • ⏱️ Restore any file to any moment. ua restore <id> path/to/file — or the whole tree. Time travel for folders.
  • 🛟 Every restore is itself undoable. Before any restore, undo-anything captures an automatic safety snapshot. Restored the wrong thing? Undo the undo.
  • 🤖 Built for the AI-agent era. Snapshots run independently of git and your editor, so the edits you "accepted and forgot" are always recoverable.
  • 🪶 Tiny and deduplicated. Identical content is stored once and compressed. Hundreds of snapshots typically cost a few MB — see the savings figure in ua status.
  • 🔒 100% local. No accounts, no telemetry, no network. Your code never leaves your machine. (See for yourself.)
  • 🖥️ A gorgeous timeline TUI. Scrub history and restore with one key.
  • 📦 One static binary. Zero config to start; sensible defaults everywhere.

Install

go install
go install github.com/agenticraptor/undo-anything/cmd/ua@latest
Pre-built binaries

Grab a binary for your OS/arch from the Releases page (Linux, macOS, Windows · amd64/arm64).

Homebrew (macOS / Linux)
brew install agenticraptor/tap/ua

Available once the Homebrew tap is published — see the note in .goreleaser.yaml to enable it.

From source
git clone https://github.com/agenticraptor/undo-anything
cd undo-anything
make install

Quickstart

# 1. Start tracking a folder (creates .undo/ and a baseline snapshot)
cd ~/code/my-project
ua init

# 2. Snapshot automatically on every save, in the background
ua daemon start
#    …now just work. Edit files, let your agent run, whatever.

# 3. Oops — get a single file back to an earlier state
ua log                       # find the snapshot you want
ua restore 056d1f13 internal/payments/client.go

# 4. Or roll the WHOLE folder back, then change your mind and undo that too
ua restore 056d1f13 --clean
ua restore <safety-id-it-printed>

# 5. Browse everything visually and restore with one key
ua timeline

Prefer it to start on login? Install it as a service:

ua daemon install     # launchd on macOS, a systemd user unit on Linux

Usage

ua init [dir]                 Start tracking a folder (+ baseline snapshot)
ua watch [dir]                Watch & snapshot in the foreground (Ctrl-C to stop)
ua snapshot [dir] -m "msg"    Capture a snapshot right now
ua log [dir]                  List snapshots, newest first
ua timeline [dir]             Interactive TUI: browse + one-key restore
ua show <id>                  Show a snapshot's details and its diff
ua diff [<from> [<to>]]       Diff two snapshots (defaults to latest vs parent)
ua restore <id> [path...]     Restore files or the whole tree to a snapshot
ua status [dir]               Watcher status + store statistics
ua prune [dir]                Thin old snapshots and reclaim space
ua daemon start|stop|status|install|uninstall
ua doctor [dir]               Check environment & store health
ua version

Selected flags:

Command Flag Description
restore --clean Remove tracked files not present in the snapshot (whole-tree only)
restore --no-safety Skip the automatic pre-restore safety snapshot
restore -y, --yes Don't prompt for confirmation
log -n, --limit Max snapshots to show (0 = all)
log --oneline Compact, script-friendly output
snapshot -m, --message Label the snapshot
watch --debounce Quiet period before a snapshot (overrides config)
prune --dry-run Show what would be removed without changing anything

How it works

            file changes
                 │
        fsnotify (debounced)                  ┌──────────────────────────────┐
                 │                            │            .undo/             │
                 ▼                            │                              │
   walk tree (skipping ignored) ─┐           │  objects/   content-addressed │
                 │               ├─ hash ───►│             deduped + zlib     │
        read each file ──────────┘   each    │  snapshots/ immutable manifests│
                 │               file        │  timeline.log  append-only idx │
                 ▼                            └──────────────────────────────┘
      snapshot = manifest of {path → sha256, mode, size}
                 │
   identical tree? → collapse to the same snapshot id (a no-op)
                 │
                 ▼
         ua restore  ──►  (safety snapshot first)  ──►  rewrite files atomically

Each unique file content is stored once, keyed by its SHA-256 and compressed. A snapshot is just a small manifest of pointers, so "snapshot on every save" stays cheap — only changed blobs are ever written. Read docs/architecture.md for the full design.

Data safety

undo-anything is something you trust with unsaved work, so safety is the headline feature, not an afterthought:

  • Atomic everything. Objects and manifests are written to a temp file and renamed into place. An interrupted snapshot can't corrupt history.
  • Verified on read. Objects are checked against their content hash when restored; corruption is detected, never silently served.
  • Undo the undo. Every restore takes a pre-restore safety snapshot by default and prints its ID, so you can always go back.
  • Ignored files are untouchable. --clean only ever removes tracked files — your node_modules/, build output, and ignored paths are never deleted.

See SECURITY.md for the full policy and how to report issues.

Configuration

Zero config required. To customize, edit .undo/config.toml (created by ua init):

[watch]
debounce_ms = 1500        # coalesce rapid saves into one snapshot
max_file_size_mb = 50     # skip files larger than this

[ignore]
patterns = ["*.bin", "secrets/"]   # extra .gitignore-style rules
use_gitignore = true               # also honour the folder's .gitignore

[retention]
keep_hours = 48           # keep every snapshot within this window
keep_daily = 30           # then one per day for this many days
max_snapshots = 2000      # hard cap (newest always kept)

You can also drop a .uaignore file (same syntax as .gitignore) in the folder. The store directory, .git/, node_modules/, and common build output are ignored by default. Full reference: docs/configuration.md.

Privacy

undo-anything runs entirely on your machine and makes no network connections — there's no telemetry and no account. You can confirm it yourself:

# macOS: should show no outbound connections
sudo lsof -i -nP | grep ua || echo "no network — as promised"

Snapshots live in .undo/ next to your files (deduplicated and compressed, but not encrypted) — treat that directory as sensitively as the files it protects, and exclude secrets via .uaignore if you don't want them retained.

FAQ

A few quick ones — see docs/faq.md for more.

  • Does this replace git? No. git is for intentional, shared history; undo-anything is a personal, automatic safety net for the uncommitted moments in between.
  • Will it bloat my disk? Rarely — identical content is stored once and compressed. ua status shows exactly how much you're saving, and ua prune thins old history.
  • What about huge files / build output? Files over max_file_size_mb and anything ignored are skipped automatically.

Contributing

Contributions are very welcome — see CONTRIBUTING.md. Good first issues include an interactive restore picker, line-level diffs in ua show, and Windows service installation. Please also read our Code of Conduct.

License

MIT © undo-anything contributors.

Directories

Path Synopsis
cmd
ua command
Command ua is the undo-anything CLI: a universal local time machine for any folder.
Command ua is the undo-anything CLI: a universal local time machine for any folder.
internal
buildinfo
Package buildinfo exposes version metadata stamped in at build time via -ldflags.
Package buildinfo exposes version metadata stamped in at build time via -ldflags.
cli
Package cli wires together the undo-anything command-line interface on top of cobra.
Package cli wires together the undo-anything command-line interface on top of cobra.
config
Package config loads and saves a store's TOML configuration, which lives at .undo/config.toml.
Package config loads and saves a store's TOML configuration, which lives at .undo/config.toml.
daemon
Package daemon manages the background watcher process: starting it detached, tracking it via a pidfile, stopping it, and installing it as an OS service (launchd on macOS, a systemd user unit on Linux).
Package daemon manages the background watcher process: starting it detached, tracking it via a pidfile, stopping it, and installing it as an OS service (launchd on macOS, a systemd user unit on Linux).
humanize
Package humanize formats sizes, counts, and durations for friendly CLI output.
Package humanize formats sizes, counts, and durations for friendly CLI output.
ignore
Package ignore implements gitignore-style path matching used to decide which files undo-anything tracks.
Package ignore implements gitignore-style path matching used to decide which files undo-anything tracks.
prune
Package prune translates a retention policy into the concrete set of snapshots to keep, then drives the store's garbage collector.
Package prune translates a retention policy into the concrete set of snapshots to keep, then drives the store's garbage collector.
restore
Package restore rehydrates files and whole trees from snapshots back onto the filesystem.
Package restore rehydrates files and whole trees from snapshots back onto the filesystem.
snapshot
Package snapshot turns a working directory into immutable, content-addressed snapshots in the store, and compares snapshots against each other.
Package snapshot turns a working directory into immutable, content-addressed snapshots in the store, and compares snapshots against each other.
store
Package store implements undo-anything's on-disk, content-addressed object store.
Package store implements undo-anything's on-disk, content-addressed object store.
timeline
Package timeline implements the interactive `ua timeline` TUI: a scrollable list of snapshots on the left, details and a diff on the right, and one-key restore.
Package timeline implements the interactive `ua timeline` TUI: a scrollable list of snapshots on the left, details and a diff on the right, and one-key restore.
watch
Package watch implements the recursive, debounced file watcher that powers the undo-anything daemon.
Package watch implements the recursive, debounced file watcher that powers the undo-anything daemon.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL