← Back to Catalog

agit

AI-agent version control

Version: 1.24.0
Binaries: 1
Platforms: 0
License: GPL-3.0-only
Homepage: Link ↗

Install:

brew install matt-riley/tools/agit

README

AgenGit

agit is a CLI that records AI-agent coding activity into a local .agit/ store so you can inspect what happened between commits.

Status

Current CLI version: 1.24.0.

The project is usable but still evolving. Command output and on-disk details may change before a long-term stable format is declared.

Today

Shipping today: local .agit/ capture stores, hook installation for Claude Code/OpenAI Codex CLI/Google Gemini CLI/GitHub Copilot CLI/Pi, investigation views including agit timeline, agit show --files/--stat, agit diff, and agit recall, health/recovery tooling including read-only agit fsck, S3-compatible remote agit push / agit pull, generated shell completions, and structured JSON for the commands that advertise it.

Supported hook integrations today:

Agent Installed hooks
Claude Code SessionStart, UserPromptSubmit, PostToolBatch, Stop in ~/.claude/settings.json
OpenAI Codex CLI UserPromptSubmit, PostToolUse, Stop in ~/.codex/hooks.json
Google Gemini CLI BeforeModel, AfterTool, AfterAgent in ~/.gemini/settings.json
GitHub Copilot CLI generated extension ~/.copilot/extensions/agit-recorder/extension.mjs (subscribes to onUserPromptSubmitted, onPostToolUse, onAgentStop)
Pi generated extension ~/.pi/agent/extensions/agit-recorder.js (auto-discovered)

What gets recorded

Each captured step includes agent origin, optional model attribution, session identifiers, messages, tool calls, a workspace snapshot, and a content-addressed object hash. Model attribution is best-effort: Codex exposes an active model in hook payloads, Claude Code currently provides a session-level model hint on SessionStart when available, Gemini provides it through BeforeModel, and Copilot/Pi steps remain origin-only.

In practice: Git tracks commit history, while agit tracks agent execution history.

Install

From release archives

Download from https://github.com/matt-riley/agengit/releases.

Platform Archive
Linux x86_64 agit-x86_64-linux.tar.gz
Linux aarch64 agit-aarch64-linux.tar.gz
macOS arm64 agit-aarch64-macos.tar.gz
macOS x86_64 agit-x86_64-macos.tar.gz
tar -xzf agit-x86_64-linux.tar.gz
sudo mv agit /usr/local/bin/
agit version

Build from source

Requires Zig 0.16.0.

git clone https://github.com/matt-riley/agengit
cd agengit
zig build -Doptimize=ReleaseSafe
./zig-out/bin/agit version

Quick start

From the repository you want to observe:

agit init

agit init discovers supported agent CLIs on PATH and installs hook commands into their user config files or writes generated recorder extensions for agents that expose public extension hooks. JSON config installs create *.agit.bak backups first.

If a target config file exists but contains malformed or non-object JSON, agit init refuses to overwrite it unless you rerun with agit init --force.

Commands

agit init

Set up agit hooks for installed agent CLIs.

Synopsis: agit init [OPTIONS]

# install hooks for available agents
agit init

agit observe

Run an experimental observer source and record newly seen events.

Synopsis: agit observe [OPTIONS] <SOURCE>

# process a JSONL observer file once
agit observe --once jsonl --input observer.jsonl

Notes: Observer sources are explicit and experimental. Current sources run one pass and persist watermarks under .agit/observers/ for duplicate suppression on rerun.

agit uninstall

Remove agit hooks from agent configurations.

Synopsis: agit uninstall [OPTIONS]

# remove all hooks
agit uninstall

agit doctor

Check store health and agent hook configuration.

Synopsis: agit doctor [OPTIONS]

# check store and agent health
agit doctor

agit fsck

Verify object, ref, index, and mutable-area integrity.

Synopsis: agit fsck [OPTIONS]

# run a read-only integrity scan
agit fsck

agit gc

Prune unreachable store data and stale temporary files.

Synopsis: agit gc [OPTIONS]

# prune unreachable store data with the default grace period
agit gc

agit push

Upload reachable objects and session refs to a configured remote.

Synopsis: agit push [OPTIONS]

# push to the only configured remote
agit push

agit pull

Download missing objects and refs from a configured remote.

Synopsis: agit pull [OPTIONS]

# pull from the only configured remote
agit pull

agit export

Write a portable bundle containing selected session refs and reachable objects.

Synopsis: agit export [OPTIONS] <PATH>

# export all recorded sessions into a bundle directory
agit export dist/bundle

agit import

Import a portable bundle after validating hashes and ref conflicts.

Synopsis: agit import [OPTIONS] <PATH>

# import a bundle directory
agit import dist/bundle

agit status

Show the current investigation dashboard for this repository.

Synopsis: agit status [OPTIONS]

# show repository status
agit status

agit timeline

Show recent recorded steps across sessions in reverse chronological order.

Synopsis: agit timeline [OPTIONS]

# show the most recent recorded steps
agit timeline

agit eval

Evaluate captured agent sessions using evidence-based quality signals.

Synopsis: agit eval [OPTIONS]

# evaluate the most recent recorded session
agit eval

Notes: Eval classifications are evidence-based signals from captured history, not proof of code correctness or production success.

agit sessions

List recorded agent sessions from the index.

Synopsis: agit sessions [OPTIONS]

# list all sessions
agit sessions

agit log

Show step history for a session.

Synopsis: agit log [OPTIONS] [SESSION_ID]

# show most recent session steps
agit log

agit restore

Restore captured files from a step snapshot into the working tree. Whole-tree restores require --all; existing files are skipped unless --force is set.

Synopsis: agit restore [OPTIONS] <HASH> [-- <PATH>...]

# restore one captured file
agit restore abc123def -- src/main.zig

agit show

Show details of a recorded step object by its BLAKE3 hash.

Synopsis: agit show [OPTIONS] <HASH>

# show details of a step
agit show abc123def

agit diff

Render a diff for one step, between two steps, or across a session.

Synopsis: agit diff [OPTIONS] (<HASH> [<HASH>] | --session <ID>) [-- <PATH>]

# diff a recorded step against its parent
agit diff abc123def

agit between

Show recorded steps whose captured Git commit falls between two revisions.

Synopsis: agit between [OPTIONS] <FROM> [TO]

# show steps recorded after one commit through HEAD
agit between abc123def

agit recall

Retrieve prior recorded steps to inform the current task.

Synopsis: agit recall [OPTIONS] [QUERY]

# show recent prior work on one file
agit recall --path src/main.zig

Notes: Recall is agent-initiated pull memory. Pass a query, a --path filter, or both.

agit grep

Search recorded messages, tool activity, and captured file content across all sessions.

Synopsis: agit grep [OPTIONS] <QUERY>

# search all recorded sessions for a term
agit grep factorial

agit blame

Show per-line step attribution for a file path.

Synopsis: agit blame [OPTIONS] <FILE>

# show blame for a file
agit blame src/main.zig

Notes: AGIT_MAX_FILE_BYTES sets the default large-file cap and --no-limits disables it for one run.

agit watch

Follow newly recorded steps as they are finalized.

Synopsis: agit watch [OPTIONS]

# follow newly recorded steps
agit watch

Notes: Watch polls the local SQLite index for committed steps and is near-real-time, not event-driven. Use agit timeline for one-shot CI output.

agit stats

Summarize recorded session, step, tool, and file-change activity.

Synopsis: agit stats [OPTIONS]

# show repository-wide analytics
agit stats

Notes: Stats read the SQLite index; run agit reindex if the index has drifted. Most-changed paths are computed from at most 500 steps by default.

agit cat

Print a raw object by its BLAKE3 hash.

Synopsis: agit cat [OPTIONS] <HASH>

# print object content
agit cat abc123def

agit privacy

Scan reachable captured content for sensitive data without printing secret values.

Synopsis: agit privacy scan [OPTIONS]

# scan captured content for sensitive data
agit privacy scan

agit reindex

Rebuild the SQLite index from object/ref truth.

Synopsis: agit reindex [OPTIONS]

# rebuild entire index
agit reindex

agit version

Print agit version information.

Synopsis: agit version [OPTIONS]

# print the current version
agit version

agit completion

Generate shell completion scripts for bash, zsh, fish, or nushell.

Synopsis: agit completion [OPTIONS] <SHELL>

# bash completion script
agit completion bash

Command VHS demos

Command Demo
agit init
agit observe
agit uninstall
agit doctor
agit fsck
agit gc
agit push
agit pull
agit export
agit import
agit status
agit timeline
agit eval
agit sessions
agit log
agit restore
agit show
agit diff
agit between
agit recall
agit grep
agit blame
agit watch
agit stats
agit cat
agit privacy scan
agit reindex
agit version
agit completion

Regenerating command VHS demos

All command demos in this README are generated from .tape sources under docs/vhs/tapes/.

zig build -Doptimize=ReleaseSafe
docs/vhs/render-all.sh

Roadmap

Experimental today: agit observe --once jsonl --input observer.jsonl exercises the observer framework and persists replay checkpoints under .agit/observers/.

Structured CLI output uses the cli-json-v1 envelope documented in docs/format/cli-json-v1.md.

Store layout

agit stores data in .agit/ at repository root:

.agit/
|-- config.json        # repository-local privacy/capture policy
|-- objects/          # loose BLAKE3-addressed blobs, trees, steps, and pack/
|-- refs/
|   `-- sessions/     # latest step pointer per session
|-- log/
|   `-- hook-error.log
|-- tmp/              # staging + temporary writes
`-- index.db          # rebuildable SQLite index

Do not commit .agit/. Canonical history is in objects/; index.db is a query accelerator and can be rebuilt with agit reindex. agit gc may repack reachable loose objects into .agit/objects/pack/ to reduce storage for long-running repositories.

If agit doctor reports that the object index cache is not backfilled after an upgrade, run agit reindex once to repopulate it from .agit/objects/. If doctor reports pending capture files under .agit/tmp, those are top-level staging files from turns that have not finalized yet. Fresh files are usually an active turn; abandoned files older than the grace period are pruned by agit gc. Internal turn-state files under .agit/tmp/turns/ are not counted as pending captures.

Snapshot and privacy notes

By default, snapshots skip .git/, .agit/, common dependency/build/cache directories, symlinks, binary files, files larger than 16 MiB, and common secret-like file patterns. Override the cap with AGIT_MAX_FILE_BYTES=<bytes> when you need to inspect unusually large text files.

Project-specific exclusions can be added via .agitignore using exact paths, directory-prefix rules (trailing slash), and single * glob patterns.

Use .agit/config.json to tune capture levels for prompts, assistant messages, tool arguments/results, and snapshots; disable origins; add custom literal redactions; and make show/cat default to redacted output.

.redacted snapshot capture is best-effort, not a guarantee. For highly sensitive repositories, prefer .metadata_only or .disabled snapshot capture. Current detector coverage includes: bearer tokens, GitHub tokens, AWS access-key IDs, AWS secret-access-key values near access-key IDs, private-key blocks, Slack/Google/Stripe/OpenAI/npm token formats, JWTs, sensitive-key assignments, and custom literals.

Run agit privacy scan before sharing store content. It reports sensitive-data findings without printing the matched secret values and exits non-zero when findings are present.

Remote sync

Use .agit/config.json to define one or more named S3-compatible remotes:

{
  "version": 1,
  "remotes": [
    {
      "name": "backup",
      "endpoint": "https://s3.example.com",
      "bucket": "agit-backups",
      "region": "us-east-1",
      "prefix": "personal/agengit",
      "access_key_env": "AGIT_REMOTE_ACCESS_KEY",
      "secret_key_env": "AGIT_REMOTE_SECRET_KEY",
      "session_token_env": "AGIT_REMOTE_SESSION_TOKEN",
      "encryption_secret_env": "AGIT_REMOTE_ENCRYPTION_SECRET"
    }
  ]
}

Then sync with:

agit push
agit pull

agit push runs a local fsck preflight and refuses plaintext uploads when agit privacy scan finds sensitive content unless the remote config provides encryption_secret_env or you explicitly pass --allow-sensitive. When configured, remote objects are encrypted client-side before upload and verified against their plaintext BLAKE3 hash on pull.

The remote backend is intentionally dumb-server style: objects are stored by hash and refs are stored as plain text. Ref updates are best-effort, so racing writers to the same remote ref can still conflict.

Secret filtering helps reduce risk but is not a hard guarantee. Treat .agit/ as private data unless reviewed.

Failure behavior

Hooks are fail-open: if capture fails, the hook logs the error and exits successfully so the coding agent can continue.

For capture issues:

agit doctor --last-hook-error
cat .agit/log/hook-error.log | jq

Hook payload reads are capped at 16 MiB by default. Override with AGIT_HOOK_MAX_BYTES=<bytes> for unusually large payloads.

Development

zig build
zig build run -- version
zig build docgen
zig build check
zig build check-docgen
zig build test
zig build test-e2e
zig build test-property
zig build fuzz-hooks -- --time=60s
zig build bench-durable
zig build bench-store
zig build bench-resolve-prefix
./scripts/smoke-doctor.sh
zig build fmt
zig build check-fmt
zig build -Dtarget=x86_64-linux-musl -Doptimize=ReleaseSafe

Run zig build check before pushing. It covers formatting, markdown link validation, release metadata validation, and unit tests. Keep zig build test-e2e as the follow-up command when you touch behavior that needs end-to-end coverage.

If you change command help, examples, or public usage specs, run zig build docgen before pushing so the generated README command section stays in sync.

Durability fsync is enabled by default. Use AGIT_FSYNC=0 only in tests or microbenchmarks where you intentionally skip directory fsync.

Lock acquisition timeout defaults to 10 seconds. Override with AGIT_LOCK_TIMEOUT_MS=<milliseconds> for contention diagnostics.

Large-file snapshot limits default to 16 MiB per file. Override with AGIT_MAX_FILE_BYTES=<bytes> when benchmarking or capturing larger text files.

AGIT_CRASH_AFTER=tmp_write is a test-only knob that intentionally crashes mid hook-install/uninstall to exercise ADR 006's atomic config writes; the original config is preserved by design. See .env.example for the full list of environment variables.

Regenerate e2e golden files intentionally:

AGIT_UPDATE_GOLDEN=1 zig build test-e2e

Architecture decisions

Key design rationale is documented under docs/adr/, including:

License

GNU General Public License v3.0. See LICENSE.