{"id":51542592,"url":"https://github.com/suzuke/agentic-git","last_synced_at":"2026-07-09T15:01:09.187Z","repository":{"id":369321014,"uuid":"1289196756","full_name":"suzuke/agentic-git","owner":"suzuke","description":"A guarded, transparent git for AI coding agents — PATH shim with per-agent worktree routing, deny guardrails, commit provenance, and audited bypass","archived":false,"fork":false,"pushed_at":"2026-07-04T18:08:04.000Z","size":472,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-04T18:10:50.069Z","etag":null,"topics":["ai-agents","claude-code","coding-agents","git","guardrails","rust","shim"],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/suzuke.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":"NOTICE","maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-07-04T12:50:05.000Z","updated_at":"2026-07-04T18:08:08.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/suzuke/agentic-git","commit_stats":null,"previous_names":["suzuke/agentic-git"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/suzuke/agentic-git","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/suzuke%2Fagentic-git","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/suzuke%2Fagentic-git/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/suzuke%2Fagentic-git/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/suzuke%2Fagentic-git/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/suzuke","download_url":"https://codeload.github.com/suzuke/agentic-git/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/suzuke%2Fagentic-git/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35303292,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-09T02:00:07.329Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-agents","claude-code","coding-agents","git","guardrails","rust","shim"],"created_at":"2026-07-09T15:01:08.215Z","updated_at":"2026-07-09T15:01:09.165Z","avatar_url":"https://github.com/suzuke.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# agentic-git\n\n[![ci](https://github.com/suzuke/agentic-git/actions/workflows/ci.yml/badge.svg)](https://github.com/suzuke/agentic-git/actions/workflows/ci.yml)\n\n**A guarded, transparent `git` for AI coding agents.**\n\n`agentic-git` is a small Rust binary that masquerades as `git` on an agent's\n`PATH`. The agent keeps speaking the git it already knows — the shim is\ninvisible until the moment it matters:\n\n- **routes** every mutating command into the worktree the agent is *bound* to,\n- **denies** the operations that wreck multi-agent setups (with an actionable,\n  LLM-readable explanation of what to do instead),\n- **recovers** — snapshots the worktree before any destructive op, so *one*\n  command (`agentic-git snapshots restore`) puts back what a `reset --hard`\n  or `clean -fd` just erased. Plain git has no undo for that,\n- **attributes** every commit to the agent that made it, and\n- lets the operator **bypass** any of it, deliberately and audited.\n\nIt was extracted from [agend-terminal](https://github.com/suzuke/agend-terminal),\nwhere it has been running a production fleet of coding agents (Claude Code,\nCodex, and friends) sharing real repositories on one machine. The full commit\nhistory of the shim came along.\n\n\u003e **Honest positioning:** this is a seatbelt, not a cage. It is a same-uid\n\u003e userspace shim aimed at *semi-trusted, accident-prone* agents — a\n\u003e prompt-injected or buggy agent is stopped from trashing your checkout by\n\u003e habit or mistake; a determined adversary calling `/usr/bin/git` directly is\n\u003e not. For a hard boundary you want kernel-level isolation (containers,\n\u003e Landlock, sandbox-exec) *underneath* this.\n\n## Why\n\nCoding agents make mistakes at machine speed, and stock git amplifies them:\n\n| Agent habit | Blast radius without a guard |\n|---|---|\n| `git reset --hard` / `clean -fd` with uncommitted work | the work is gone — plain git keeps no copy to restore from |\n| `git checkout main` / `git switch \u003cother-branch\u003e` | tramples the branch another agent (or you) is working on |\n| `git worktree add/remove` on its own | corrupts the worktree layout your orchestrator manages |\n| running git *in your canonical checkout* | detaches or moves **your** HEAD (this really happened; it is why this tool exists) |\n| `git push` with a force-added secret | your HMAC key / audit logs leave the machine, irreversibly |\n| commits from six agents on one repo | no way to tell who did what |\n\n`agentic-git` enforces the answers at the git layer, instead of hoping every\nagent's system prompt says \"please be careful\".\n\n## How it works\n\n```\nagent runs `git \u003cargs\u003e`\n        │  (PATH: \u003chome\u003e/bin/git → agentic-git)\n        ▼\nclassify(argv, cwd, binding)          binding = HMAC-signed\n        │                             agent → branch → worktree\n        ├─ passthrough      read-only / safe → exec real git as-is\n        ├─ chdir-pass       mutating + bound → exec real git -C \u003cbound worktree\u003e\n        ├─ silent-exempt    known tool noise (e.g. gh post-merge) → exit 0\n        └─ deny             exit 1 + reason + literal next step for the agent\n```\n\n- **Binding:** the orchestrator writes `runtime/\u003cagent\u003e/binding.json`\n  (+ `.sig`, HMAC-SHA256 over an operator-owned key). Signature invalid or\n  missing → the agent is *unbound* and every mutating command is denied,\n  with guidance on how to get a worktree. Fail-closed.\n- **Deny matrix** (the interesting cases): `git worktree *` (worktree\n  lifecycle belongs to the orchestrator) · `checkout`/`switch` to a different\n  or protected branch (`main`/`master` by default, extendable via\n  `policy.toml`) · any mutation while unbound (including plumbing:\n  `read-tree`, `update-index`, `apply`) · agent git in a canonical-rooted\n  repo (protects *your* checkout) · **push ranges carrying trust-root files**\n  (`.config-integrity-key`, `policy.toml`, `fleet.yaml`, audit `*.jsonl`) —\n  the one place the shim blocks on *content*, because that mistake is\n  irreversible.\n- **Provenance:** a `prepare-commit-msg` hook (installed per-worktree by the\n  orchestrator) appends `Agentic-Agent`, `Agentic-Branch`, `Agentic-Task`,\n  `Agentic-Issued-At` trailers, idempotently. A `reference-transaction` hook\n  journals every ref move with the agent's identity.\n- **Bypass, audited:** `AGENTIC_GIT_BYPASS=1` (one-shot) ·\n  `AGENTIC_GIT_BYPASS_AGENT=\u003cname\u003e` (per-agent) ·\n  `AGENTIC_GIT_BYPASS_UNTIL=\u003cepoch\u003e` (time-boxed). Bypassed mutations are\n  logged to the fleet event log. The deny messages themselves tell the agent\n  these exist — transparency over obscurity.\n- **Robustness:** recursion guard (a mis-resolved `git` can't spawn-storm\n  itself), target-override stripping (a caller's own `-C`/`--git-dir` can't\n  out-vote the binding), Unix `exec()` process replacement, Windows\n  `status()`+exit.\n\n## Quickstart\n\nInstall, then launch your agent inside a guarded session. **One command**\nprovisions a worktree, a signed binding, and the hooks — the agent just runs\nthe `git` it already knows:\n\n```sh\ncargo install agentic-git          # or: cargo build --release\n\n# Launch ANY agent command in a guarded session on its own branch:\nagentic-git run --agent my-agent --branch my-agent/work -- \\\n    claude --dangerously-skip-permissions     # …or codex, or a shell, or make\n```\n\nInside the session the agent's `git` is the shim:\n\n```\ngit status          → passthrough\ngit checkout main   → denied, with the reason and the way out\ngit reset --hard    → runs, but the worktree is snapshotted first\n```\n\nIf the agent erases uncommitted work, put it back with **one command** — no\nsnapshot ref, no git internals (the session prints its worktree path on exit):\n\n```sh\nagentic-git snapshots restore --repo \u003cthe session's worktree\u003e\n```\n\nSee the whole thing end-to-end — an agent wipes real work, one command brings\nit back — in **[`demo/recovery-demo.sh`](demo/recovery-demo.sh)**. It asserts\nevery step, so it also doubles as a cold-start acceptance check on your machine.\n\n### Embedding it in your own orchestrator\n\nAlready running a fleet and want the shim *without* `run`'s provisioning? Put\nthe binary on the agent's `PATH` as `git` and write the binding yourself:\n\n```sh\nexport AGENTIC_GIT_HOME=$HOME/.agentic-git\nmkdir -p \"$AGENTIC_GIT_HOME/bin\"\nln -sf \"$(command -v agentic-git)\" \"$AGENTIC_GIT_HOME/bin/git\"\n\n# In the agent's environment (NOT your own shell):\nexport AGENTIC_GIT_REAL_GIT=\"$(command -v git)\"   # resolve BEFORE touching PATH\nexport PATH=\"$AGENTIC_GIT_HOME/bin:$PATH\"\nexport AGENTIC_GIT_AGENT=my-agent\n# (Order matters: `command -v git` after the PATH prepend would capture the\n# shim itself. The shim detects and ignores a self-referential REAL_GIT and\n# falls back to a self-excluding PATH search, but don't rely on it.)\n```\n\nagend-terminal plays this orchestrator role in the original fleet; the\n`agentic-git-core` crate is the contract surface for doing the same in yours.\n\n## Environment contract\n\nEvery variable also accepts its legacy `agend-terminal` name as a fallback,\nso an existing agend fleet can adopt this binary with **zero daemon-side\nchanges**:\n\n| Primary | Legacy fallback | Meaning |\n|---|---|---|\n| `AGENTIC_GIT_HOME` | `AGEND_HOME` | state root (bindings, hooks, event log) |\n| `AGENTIC_GIT_AGENT` | `AGEND_INSTANCE_NAME` | the calling agent's identity |\n| `AGENTIC_GIT_REAL_GIT` | `AGEND_REAL_GIT` | path to the real git binary |\n| `AGENTIC_GIT_BYPASS` | `AGEND_GIT_BYPASS` | one-shot bypass |\n| `AGENTIC_GIT_BYPASS_AGENT` | `AGEND_GIT_BYPASS_AGENT` | per-agent bypass |\n| `AGENTIC_GIT_BYPASS_UNTIL` | `AGEND_GIT_BYPASS_UNTIL` | time-boxed bypass (unix epoch) |\n| `AGENTIC_GIT_SHIM_DEPTH` | `AGEND_GIT_SHIM_DEPTH` | recursion-guard sentinel (internal) |\n| `AGENTIC_GIT_ALLOW_CANONICAL_MUTATE` | `AGEND_GIT_ALLOW_CANONICAL_MUTATE` | canonical-repo escape hatch |\n| `AGENTIC_GIT_SNAPSHOTS` | `AGEND_GIT_SNAPSHOTS` | pre-destructive-op recovery snapshots (`=1` to enable; default off in raw shim mode, on by default inside `run` sessions; `=0`/`off` force-disables) |\n\nOn-disk contract (also unchanged from upstream): `runtime/\u003cagent\u003e/binding.json`\n+ `.sig` · `.config-integrity-key` (32-byte HMAC key, 0600) ·\n`fleet_events.jsonl` (append-only audit) · `policy.toml` (optional\nprotected-ref override, fail-closed) · `.agend-managed` worktree marker.\n\n## Workspace layout\n\n| Crate | What it is |\n|---|---|\n| `agentic-git` | the shim binary |\n| `agentic-git-core` | the contract surface for **embedders**: `integrity_core` (HMAC sign/verify — link this in your daemon and signer/verifier can never drift) and `protected_refs` |\n\n## Status \u0026 roadmap\n\nAlpha. Battle-tested logic (the history in this repo is the battle), fresh\npackaging.\n\n**Recovery layer:** before a destructive op (`reset --hard`, `clean -f*`,\nany worktree-overwriting `checkout`/`restore`, `switch -f`/`--discard-changes`,\n`stash drop|clear`, `merge`/`rebase`/`pull`/`cherry-pick`/`revert`/`am`) runs\nin a git work tree, the shim snapshots the tree into a private\n`refs/agentic-git/snapshots/\u003cwho\u003e/…` ref first (skipped when clean; fails open\n+ loud, never blocks the op). The snapshot namespace is itself guarded against\nbeing pushed. Recover in one command — `agentic-git snapshots restore` writes\nthe snapshot's files back to the working tree (with no ref, it uses the only\nsnapshot, or the newest with `--yes`). It is **non-destructive** (files created\nafter the snapshot are left in place, never deleted), lands the recovery\nunstaged, and saves your current state first so the restore is itself undoable.\nInspect and prune with `agentic-git snapshots list|prune [--repo \u003cpath\u003e]`. Off\nby default in raw shim mode (`AGENTIC_GIT_SNAPSHOTS=1` to enable); on by default\ninside `run` sessions.\n\nKnown rough edges:\n\n- **Windows is unverified.** The `cfg(windows)` paths (copy-instead-of-symlink\n  wiring, `status()`+exit process replacement, case-insensitive dispatch) have\n  never run in the wild; CI exercises them as an *advisory* (non-blocking) job.\n- `policy.toml` covers protected-ref overrides; snapshot TTL / destructive-op\n  list are hardcoded defaults + flags — richer config is planned.\n\n## License\n\nApache-2.0. See [NOTICE](NOTICE) for provenance.\n\n*讀中文?* 見 [README.zh-TW.md](README.zh-TW.md)。\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsuzuke%2Fagentic-git","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsuzuke%2Fagentic-git","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsuzuke%2Fagentic-git/lists"}