README
¶
locsnap
locsnap is a Go CLI that continuously snapshots a codebase while agents or tools modify it. It observes the filesystem from the outside, writes snapshots to an isolated .locsnap/ store, and never touches the repository's normal Git index, refs, or history.
Status: Stable for local timeline capture and recovery. Debouncing captures states that persist through the configured quiet period, not every transient write. Keep an independent off-device backup for protection from disk loss, repository deletion, or host compromise.
Features
- Recursive filesystem watching with
fsnotify - Debounced snapshots for bursty writes and atomic-save workflows
- Periodic reconciliation scans that recover persistent changes after missed watcher events
- One serialized writer per stream, with streams running in parallel
- Cross-process writer and maintenance locking to prevent competing writers and GC/read races
- Durable object and ref writes using file and directory synchronization
- Crash-safe commit ordering with rebuildable indexes
- Persistent health reporting for watcher and snapshot failures
- Isolated
.locsnap/Git-style object store - Git-compatible blobs, nested trees, commits, and stream refs
- Content-addressed deduplication
- Optional alternates pointing at
.git/objects - bbolt
index.dbfor fast timeline and metadata queries - Gitignore-compatible ignore matching
- Built-in ignores for
.locsnap,.git,node_modules,.venv,dist,build, and.next - Large-file skip threshold
- Snapshot restore to a target directory
- Basic retention and unreachable-object GC
Install
Install the latest release with curl:
curl -fsSL https://raw.githubusercontent.com/patriceckhart/locsnap/main/install.sh | sh
By default this installs locsnap to $HOME/.local/bin. To choose another directory:
curl -fsSL https://raw.githubusercontent.com/patriceckhart/locsnap/main/install.sh | LOCSNAP_INSTALL_DIR=/usr/local/bin sh
Install a specific release:
curl -fsSL https://raw.githubusercontent.com/patriceckhart/locsnap/main/install.sh | LOCSNAP_VERSION=0.1.0 sh
You can also install with Go:
go install github.com/patriceckhart/locsnap@latest
For local development:
go build -o locsnap .
Quick start
locsnap init
locsnap watch
In another terminal, edit files in the repository. locsnap watch will create snapshots whenever the tree reaches a stable state.
View status:
locsnap status
List snapshots:
locsnap log main
Inspect a snapshot:
locsnap show <snapshot>
Restore a snapshot:
locsnap restore <snapshot> --to /tmp/restored-tree
If the target directory already exists and is not empty, pass --force. This merges the snapshot into the directory and leaves unrelated existing files in place:
locsnap restore <snapshot> --to /tmp/restored-tree --force
Commands
locsnap init
Creates .locsnap/, initializes the object store, writes .locsnap/config, sets up alternates when .git/objects exists, creates the bbolt index, and adds .locsnap/ to .gitignore.
locsnap add <dir> [--stream <id>]
Registers a watch root as a stream. Each watch root maps to one stream.
locsnap add . --stream main
locsnap add worktrees/agent-1 --stream agent-1
locsnap watch
Starts watchers for all configured streams. Each stream has its own serialized writer queue, while streams run in parallel.
locsnap status
Shows configured streams, their latest snapshots, latest snapshot time, store size, and the latest persisted health report. It can run while locsnap watch is active. Failures are also appended to .locsnap/errors.log so a later success cannot erase the failure history.
locsnap log [stream]
Lists snapshots in reverse chronological order. Defaults to main.
locsnap show <snapshot>
Shows snapshot metadata, a diff summary versus the parent snapshot when available, and the files in the snapshot.
locsnap restore <snapshot> --to <dir> [--force]
Materializes a snapshot into a target directory. The target must be empty unless --force is provided.
locsnap gc
Applies retention policy and removes unreachable objects from .locsnap/objects. GC performs a full integrity preflight and aborts without pruning if any reachable object is missing or corrupt.
locsnap version
Prints the release version, commit, and build date.
Configuration
Configuration lives in .locsnap/config.
Example:
[core]
repositoryformatversion = 0
filemode = true
bare = true
[locsnap]
debounce-ms = 200
scan-interval-ms = 5000
max-file-size = 10485760
use-alternates = true
self-copy-blobs = true
[stream "main"]
root = "."
[stream "agent-1"]
root = "worktrees/agent-1"
[retention]
keep-full-hours = 24
thin-to = "hourly"
max-store-bytes = 2147483648
Options
debounce-ms: quiet period after filesystem events before snapshotting.scan-interval-ms: periodic full reconciliation interval.max-file-size: files larger than this are skipped.0disables the limit.use-alternates: read existing objects from.git/objectswhen available.self-copy-blobs: always write blob copies into.locsnap/objects, even if found through alternates. New stores default totrueso snapshots remain durable if the repository's Git objects are pruned.keep-full-hours: keep all snapshots for this many hours before thinning.thin-to: currently supportshourlythinning.max-store-bytes: store-size cap used by retention.
Storage layout
.locsnap/
objects/ Git loose object store
objects/info/alternates Optional pointer to ../../.git/objects
refs/locsnap/streams/<id> Stream heads
index.db bbolt query index
lock.db cross-process writer lock
maintenance.db GC and read-operation exclusion lock
health.json latest operation or watcher health report
errors.log durable append-only failure history
config locsnap config plus Git-compatible core config
Git compatibility
Snapshots are Git commit objects stored in .locsnap/objects. You can inspect them with Git plumbing:
git --git-dir .locsnap cat-file -t <snapshot>
git --git-dir .locsnap ls-tree -r <snapshot>
locsnap does not use or modify the repository's normal Git index, branches, refs, or history.
Current limitations
- Symlinks and other non-regular files are skipped.
- Files larger than
max-file-sizeare omitted from snapshots. - Debouncing can coalesce transient intermediate states.
restore --forcemerges into its target rather than deleting unrelated files.- Retention can rewrite commit ancestry, so snapshot IDs removed or rewritten by
locsnap gcshould not be treated as permanent identifiers. - The shell installer supports Linux and macOS. Windows users can use
go installor a release archive.
Development
Run tests:
go test ./...
Format code:
gofmt -w .
Build:
go build -o locsnap .
License
MIT
Documentation
¶
There is no documentation for this package.