pi-git-commit
v1.1.4
Published
Pi extension: block mutative git commands in bash and provide git_commit and git_amend tools plus /commit, /amend, /stop-commit and /toggle-allow-git commands
Maintainers
Readme
pi-git-commit
Keeps mutative git operations out of the agent's bash and provides a safe, reviewable commit flow in pi-coding-agent: a bash guard, git_commit and git_amend tools, and /commit, /amend, /stop-commit and /toggle-allow-git commands.
What you get
- Bash git guard. Mutative git commands are blocked in the agent's bash and powershell tools —
add,stage,commit,push,pull,merge,rebase,reset,clean,rm,restore,switch,cherry-pick,revert,mv,init,clone, index/object plumbing (read-tree,checkout-index,merge-file,prune-packed,hash-object -w,commit-tree,mktree,index-pack,pack-objects), plus mutative forms ofbranch(including creation,-u,-f,-c/-C/--copy,-D/-M,--force,-t/--track),tag(including creation),checkout(including whole-tree restores likecheckout -- .),stash,submodule,worktree,config,remote,apply,notes,update-ref,gcand more. Read-only commands (status,diff,log,fetch,branch,tag,stash list, ...) stay allowed. git_committool. The agent stages everything (or, with/commit --staged, commits only the index) and commits with aFIX/IMPROVE/NEWtype prefix. The tool stays active for the whole session but refuses to run until/commitopens the flow, and it refuses again once the commit succeeds. The active tool set never changes mid-session, so the provider prompt cache is never invalidated.git_amendtool. Sametype/messageparameters asgit_commit, but it rewrites only the last commit's message and timestamp viagit commit --amend --date=now: it stages nothing, refuses when the index already has staged changes, and never touches the committed content. Gated likegit_commit: it refuses until/amendopens the flow and refuses again once the amend succeeds./commitcommand. Waits for queued messages to finish, stages all changes (/commit --stagedskips staging and commits only what is already in the index), shows a collapsed summary of the staged diff (agit diff --statfile list; pressctrl+oor click the message to expand the diff preview), unlocks thegit_committool, and asks the agent to review the changes and commit viagit_commit— never via bash. The full diff reaches the agent only when it fits pi's tool limits (2000 lines / 50KB); larger diffs are left out of the context entirely and the agent gets just the stat file list (capped at 100 lines / 8KB), so a giant change can never blow up the session. Run/stop-commitor pressescapeat any point to abort the flow before it starts and to clear the working message./amendcommand./amend <critique>sends the agent your critique of the last commit message and asks it to fix the message and refresh the timestamp withgit_amend— never via bash. Run/stop-committo abort a pending amend./stop-commitcommand. Aborts a pending commit or amend flow: closes the flow sogit_commitandgit_amendrefuse to run, cancels a/commitor/amendthat is still waiting for queued messages, so nothing is changed, and clears the flow's working message immediately. Pressingescapewhile a flow is pending or active does the same./toggle-allow-gitcommand. Temporarily allows mutative git commands in bash for the current session. The guard re-arms on the next session.
Quick start
- Make your changes, then run:
/commitThe extension stages the working tree and shows a collapsed summary of the staged diff — press
ctrl+oor click the message to expand it. The agent receives the full diff when it fits pi's tool limits (2000 lines / 50KB); when it does not, the diff is omitted entirely and the agent sees only the stat file list (capped at 100 lines / 8KB), with a note pointing at read-onlygit diff --staged -- <path>for details — so even a 400k-line change stays out of context.The agent commits using the
git_committool:
{
"type": "FIX",
"message": "Correct the off-by-one in the retry loop"
}Changed your mind? Run
/stop-commitor pressescapeto abort the flow before the agent commits.If you need to run mutative git yourself, allow it for the session:
/toggle-allow-gitInstallation
pi install npm:pi-git-commitFrom a local checkout:
pi install /path/to/pi-git-commitThe git_commit tool
| Field | Description |
| --- | --- |
| type | FIX (bug fix), IMPROVE (improvement), or NEW (new feature). |
| message | Commit message in imperative mood, without the type prefix (it is added automatically). A leading type word matching the chosen type is stripped (with :, whitespace, or -/— separators, any casing, repeats included) so the type is never duplicated. Multi-line allowed for detailed changes. |
The tool runs git add . followed by git commit -m "<TYPE>: <message>" and reports staging or commit failures as tool errors. When the flow was opened with /commit --staged it skips staging and commits only the index. A leading type word in the message is stripped whenever it repeats the chosen type — with :, whitespace, or -/— separators, at any casing, repeated prefixes included — so the type never ends up duplicated: FIX: Fix: ..., FIX: Fix ..., and fix - ... all become FIX: .... The flow gate is enforced in the tool itself: git_commit is listed for the whole session but refuses to run until you run /commit, and it refuses again once the commit succeeds, so the agent cannot commit at arbitrary points in the conversation. Because the active tool set never changes, pi's system prompt stays identical for the whole session and the provider's prompt cache is never invalidated (changing the active tool set rebuilds the system prompt and drops the cached prefix). If a commit fails, the flow stays open and the agent can retry immediately without re-running /commit.
The git_amend tool
/amend <critique> sends your critique of the last commit message to the agent and instructs it to call git_amend with a corrected message. The tool applies the same leading-type stripping and empty-message rejection as git_commit and runs git commit --amend -m "<TYPE>: <message>" --date=now, which refreshes the commit timestamp to the current time. It stages nothing and refuses to run when the index already has staged changes, because amend would fold them into the last commit. The flow gate matches git_commit: git_amend is listed for the whole session but refuses to run until you run /amend, and it refuses again once the amend succeeds. If the amend fails, the flow stays open and the agent can retry without re-running /amend.
Amending rewrites the last commit, so on a branch that is already pushed the local branch diverges from its upstream. Pushing stays blocked in bash either way.
The bash guard
The guard intercepts tool_call events for the bash and powershell tools and blocks commands that match mutative git forms. The block list is a conservative superset: anything that can change repository state is blocked, while a curated set of read-only forms is explicitly allowed (for example git fetch, git stash list, git remote -v, git config --get, git apply --check, git checkout -- <file>, git submodule status, git worktree list).
The guard parses the command into segments (pipelines, &&, ||, ;, &, command and process substitution, newlines) and inspects only segments that actually invoke git — including path-qualified invocations (/usr/bin/git), wrapper prefixes with their flags (sudo -u root, nice -n 5, timeout -k 5s 10s), environment-assignment prefixes (VAR=1 git ..., env VAR=1 git ...), control constructs ({ ...; }, !, if, while), and sh -c/su -c wrappers — while skipping git's global options such as -C, -c, --git-dir, and --work-tree and blocking -c alias.* overrides that define a mutative alias. Commands nested more than four wrapper levels deep are blocked outright (fail closed), even when no git command is visible. Git commands mentioned inside strings or heredocs are not blocked. Plain git fetch stays allowed, but git fetch --prune/-p/--prune-tags is blocked. Indirect invocation (aliases, variables, find -exec) cannot be detected reliably and is best-effort; likewise a directory passed to git checkout -- without a trailing slash is indistinguishable from a file, so git checkout -- src (restoring the whole src tree) is not caught.
A blocked command returns:
Mutative git commands are blocked. Ask the user to run /toggle-allow-git to allow them for this session.Troubleshooting
- The agent refuses to commit. The guard blocks
git commitin bash by design. Run/commitand let the agent use thegit_committool. - The agent stopped committing. You ran
/stop-commitor pressedescape, which aborted the pending flow. Run/commitagain to start a new one. - Prompt cache misses (sudden cost/latency spikes) after /commit. Older versions activated and deactivated the
git_committool per flow, which rebuilt pi's system prompt and invalidated the provider's cached prompt prefix. Update to this version: the tool set now never changes mid-session. - "Nothing to commit (empty diff)." There are no staged changes — make edits first, then run
/commitagain. - I want to commit only some files. Stage the files yourself (or run
/toggle-allow-gitand let the agent stage them), then run/commit --stagedto review and commit exactly the index. - I need git in bash right now. Run
/toggle-allow-git; the guard re-arms automatically on the next session start.
Development
Requires Node.js ≥ 22.19 and npm.
npm install
npm test
npm run typecheckCredits
- badlogic, pi-coding-agent and the tool/command APIs
