aivyx-coder · ManualContents ↓

Undo, diff, commit and test

In a git repository, aivyx-coder keeps track of everything the assistant changes, so you can review it, take it back, commit it, and check it.

Checkpoints

Before every change the model makes — a file write or edit, a command — and when each of your messages starts and its reply ends, aivyx-coder snapshots the whole worktree into a hidden git ref (refs/aivyx/checkpoints/<time>). It never touches your branch, index or files, respects .gitignore, skips identical states, and keeps the newest 50. Turn it off with checkpoints = false under [git].

If a snapshot fails (git refuses it, say), the change still goes ahead and a notice in the transcript says so, with git’s message. Nothing can go back to just before that change, and nothing goes back further either: an --auto rewind keeps that round of edits, and a failed call doesn’t roll back the earlier edits in the same reply, since the only snapshot left would also discard older work. Later failures in a row only go to the log; the next failure after a snapshot that worked gets a notice again.

See what changed

After every turn that changed files, a dim line sums it up: Changed: stats.py (+3 −1) · test_stats.py (+12, new).

  • /diff — every uncommitted change in a scrollable view (↑ ↓, PgUp/PgDn, Home/End; Esc closes).
  • /diff turn — just the last turn’s changes.

Take it back

  • /undo — rewinds the assistant’s last turn as a whole: every edit, every command effect, and the work of any sub-agent it delegated to. It shows which files will change, flags any you edited afterwards, and asks first. Run it again to go back further.
  • /redo — puts back what the last /undo removed.
  • /checkpoints — lists the turns you can take back.

The model is told about an undo in your next message. Git-ignored files are never touched. /undo after a /commit rewinds your files but leaves the commit in place, and its preview says so.

The checkpoints are plain git refs, if you prefer git itself:

git for-each-ref refs/aivyx/checkpoints/     # list them
git diff <ref>                               # what changed since one
git checkout <ref> -- <path>                 # restore one file

Commit

/commit commits what you’ve staged — or, if nothing is staged, every uncommitted change — with a message the model drafts from the diff. Approve it, press e to edit the message, or cancel; your staging is left exactly as it was. /commit -m "message" commits with your own message straight away. It uses your git identity and runs your hooks (inside the sandbox, so a hook that writes outside the project may fail).

/commit never stages files on your deny list, and their contents are never sent to the model. If the repository’s .git is outside the folder you started in (a subfolder, or a linked worktree), the sandbox can’t write it and /commit says so — start at the repository root, or commit with git.

Generated files such as __pycache__/, node_modules/ and target/ are kept out of the change line, /diff, the undo previews, what /commit stages, and checkpoints — as long as git doesn’t track them. So a new project without a .gitignore doesn’t copy its build output into every checkpoint, and /undo or an --auto rewind leaves that output alone. The list is ignore under [git], in .gitignore syntax.

Test

/test runs the project’s tests: your [verification] command if you set one, otherwise a command detected from the project:

Found Runs
Cargo.toml cargo test
go.mod go test ./...
package.json pnpm test, yarn test or npm test, by lockfile
pytest markers (pytest.ini, [tool.pytest], conftest.py) python3 -m pytest
Python test files or a tests/ folder that use unittest python3 -m unittest (with discover for *_test.py or tests/)
other Python test files (pytest style: def test_… with assert) python3 -m pytest
a Makefile with a test: target make test

The start-up hint and /help show which one it found. /test needs no approval (you typed it), runs inside the sandbox, works in plan mode, and stops after 10 minutes or on Ctrl+C. The result and the last 80 lines of output are added to your next message, marked as program output, so the model can act on failures.

Make the model check its own work

Set a verification command and the model can’t end a turn that edited files without running it:

[[permissions.allowed_commands]]
name = "test"
program = "cargo"
args = ["test"]

[verification]
command = "test"
max_auto_verify_retries = 3

After edits, aivyx-coder runs the command (labelled auto-verify: in the transcript); on failure the model gets the output and tries to fix it, up to max_auto_verify_retries times. The command only runs again once the model has changed something: if it stops without a further change, the turn ends there. Either way, a turn that ends failing gets a loud notice pointing at the checkpoints. Each failure also says which failing lines are new since the previous attempt, or that the output didn’t change at all, in which case the failure may predate the edits.

For speed, scoped_command can name a second command that runs only the tests for the files touched, with {touched_paths} in its arguments; a full run is still required before edits count as verified. Not every test runner can select tests by file — cargo test <path> silently matches nothing, so Rust projects need a small wrapper script. A broken scoped_command makes verification fail for that batch rather than quietly using the full one.

Because its arguments change on every retry, the scoped command doesn’t use the per-exact-command approval cache: it runs directly, inside the sandbox. That’s a deliberate, narrow exception to the rule that the model never shapes a command’s arguments — the only varying input is files it already had approval to edit.

The model’s own git tools

Besides git_commit, the model can create and switch branches (git_branch), push (git_push) and open a pull request through the gh CLI (git_pr). Each asks first, like a command. git_push can never force-push, branch and remote names starting with - are refused (git would read them as options), and git_pr checks that the branch is pushed and gh is signed in before trying.