# pi-autocommit

A [Pi](https://pi.dev) extension that **auto-commits all working-tree changes after each response**, with a commit message generated by the model. Comes with per-project slash commands for manual commit/undo and an `/autocommit` on/off toggle so you can suspend it for messy WIP.

After Pi finishes responding to a prompt, the extension:

1. Checks that the project is a git repo and the working tree is dirty — otherwise it does nothing, silently.
2. Aborts with a warning if there are unresolved merge conflicts (it never commits conflict markers).
3. Stages everything (`git add -A`).
4. Asks the **currently selected model** to write a concise, descriptive commit message from the user's prompt, the assistant's summary, the changed-file list, and a truncated staged diff.
5. Commits with a sanitized subject (≤72 chars) and an optional body.

If the model call can't happen (no model / no API key) or fails, it falls back to a subject derived from the assistant's last response — so it **always** commits when there are changes and it's enabled.

## Install

```bash
pi install git:github.com/claudiolaas/pi-autocommit
```

Or try it once without installing:

```bash
pi -e git:github.com/claudiolaas/pi-autocommit
```

Reload an existing session with `/reload` after installing.

### Manual / from source

Copy `extensions/autocommit.ts` to your global Pi extensions directory:

```bash
mkdir -p ~/.pi/agent/extensions
cp extensions/autocommit.ts ~/.pi/agent/extensions/
```

Then `/reload` in Pi.

## Requirements

- A git repository in the project working directory.
- A configured git identity (`user.name` / `user.email`) — repo-local or global. A missing identity surfaces as an error notification rather than committing under a fake author.
- A model with an API key (for generated commit messages). Without one, the fallback subject is used.

## Usage

The extension runs automatically after every agent response. Control it with the `/autocommit` command (state is **persisted per project**):

| Command | Effect |
| --- | --- |
| `/autocommit` | Show current status for this project |
| `/autocommit on` | Enable (default) |
| `/autocommit off` | Suspend — leave all changes uncommitted |
| `/autocommit toggle` | Flip on/off |
| `/autocommit status` | Show current status |
| `/commit [message]` | Commit all open changes now with an auto-generated (or explicit) message. Works regardless of the autocommit toggle. |
| `/undo` | Revert the last commit with `git reset --soft HEAD~1`, bringing changes back as uncommitted. Warns if autocommit is on (changes will re-commit next prompt). |

When suspended, a `autocommit: paused` status is shown in the footer, and you get a warning whenever a response leaves changes uncommitted (so WIP doesn't pile up silently).

### State location

Per-project state is stored at `<agentDir>/autocommit-state/<encoded-cwd>.json` (default `~/.pi/agent/autocommit-state/...`), where `<agentDir>` is Pi's config dir (respects `PI_CODING_AGENT_DIR`) and the cwd is encoded the same way Pi encodes it for session dirs. Suspending in one project does **not** disable autocommit in others.

## Behavior details

- **Timing:** Commits once per user prompt, after Pi completes its full response (`agent_end`). One extra model call per commit message.
- **Scope:** Commits *all* open changes, including any you made manually outside Pi.
- **Conflicts:** Skips (and warns) on unresolved merge conflicts; never auto-resolves them.
- **Non-git / clean tree:** Silent no-op.
- **Commit message style:** Free-form descriptive (e.g. `Add input validation to the login form`), no Conventional Commits prefixes. Model output is sanitized: code fences, surrounding quotes, and preambles like "Here is the commit message:" are stripped. The subject is truncated to 72 chars at a word boundary with an ellipsis; the body to 1000 chars.
- **Stays out of the conversation:** The commit-message model call is a standalone call (`pi-ai` `complete()`) that does not touch the Pi session, so it never produces a visible agent turn. Successful commits are reported in the **footer status line** (`✓ autocommit: <subject>`), not as inline chat messages, and the indicator clears when you send your next prompt. This keeps the autocommit flow out of the main conversation thread.
- **Errors / warnings:** Never interrupt the agent. Commit failures, exceptions, the suspended-with-pending-changes notice, and unresolved-conflict warnings are surfaced as inline notifications so they are not missed.

## Manual commands

The extension provides two manual commands that work independently of the autocommit toggle:

### `/commit [message]`

Stage all open changes and commit. When no message is given, the model generates one (same logic as the automatic commit). When a message is provided, it is used directly.

```
/commit                          # auto-generated message
/commit Fix login redirect bug   # uses your message
```

### `/undo`

Reverts the latest commit with `git reset --soft HEAD~1`. The changes from that commit reappear as uncommitted (staged). If autocommit is on, you'll get a warning that the changes will be recommitted after your next prompt — use `/autocommit off` first if you want to keep them uncommitted.

## License

MIT
