Agents that change code
Anvil can change the code of a pull request, not only review it. You can apply a review's suggestions from the workspace, ask Anvil in a comment to fix findings, a failing CI job or merge conflicts, have it add docstrings or tests, or run a prompt your repository defines. With agents.autofix_ci on, Anvil also tries to fix a failing CI job on its own.
Apply suggestions #
Findings with a committable suggestion get an Apply button in the pull request workspace. It commits the suggested lines to the pull request's branch, as you: the commit is yours, made with your access, and branch protection applies as it would to a push from you. Apply all, on the overview, commits every suggestion that still applies in one commit.
Before it commits, Anvil compares the file on the branch with the version the review saw:
- If the file is unchanged, the suggestion goes in where the review put it.
- If the file changed elsewhere (someone pushed, or you applied another suggestion above it), Anvil looks for the original lines. Found exactly once, the suggestion goes there.
- If those lines changed, or now appear more than once, Anvil refuses and says why. Ask for a new review, or make the change by hand.
- If the suggested lines are already there, the finding shows Applied.
Anvil checks each file again right before committing and refuses if it moved in the meantime, so a push you haven't seen is never overwritten. Only people who can push to the repository see the button enabled; others see why it's locked. Pull requests from forks can't be changed this way, because their branch isn't in the repository.
On GitHub repositories, applying needs you to be signed in to Anvil with GitHub; the commit is made with your GitHub user token through the GitHub App.
Commands #
Mention @anvil in a pull request comment. Anvil posts a progress comment straight away and edits it with the result: what changed, a link to the commit or the pull request it opened, the check command's result, and what the run cost.
| Command | What it does |
|---|---|
@anvil fix |
Address the findings from the latest review. Anvil fixes the ones it agrees with and says why it left any |
@anvil fix <what to change> |
Make the change you describe (fix: rename foo to bar works too) |
@anvil fix ci |
Read the failed CI jobs' logs, find the cause and fix it (fix the build works too) |
@anvil docstrings |
Add or improve doc comments on the functions and types the pull request changes |
@anvil tests |
Add tests for the changed code with the repository's test framework (add tests, add unit tests) |
@anvil simplify |
Simplify the changed code without changing behaviour |
@anvil resolve conflicts |
Merge the base branch into the pull request and resolve the conflicts |
@anvil run <recipe> |
Run one of the repository's recipes |
Lines after the command are passed on as extra instructions:
@anvil fix
Only the security findings; leave the naming ones.
Who can use them: people with write access to the repository. Anvil checks the commenter's permission before it does anything.
resolve conflicts merges first. When the merge is clean, Anvil commits it without running an agent. When files conflict, the agent resolves them, and Anvil refuses to push if any conflict marker is left.
Where changes go #
agents.push in .anvil.yaml decides:
| Value | What happens |
|---|---|
new_branch (default) |
Anvil pushes to anvil/fix-<pr>-<n> and opens a pull request into your pull request's branch. You review and merge it like any other |
pr_branch |
Anvil pushes a commit to your pull request's branch |
off |
Nothing is pushed; the progress comment holds the change as a patch you can git apply |
Whatever the setting, Anvil never pushes to the repository's default branch or to the pull request's base, never force-pushes, and never pushes to a fork. With pr_branch, a change whose check command failed goes to a new branch instead. If someone pushes to the branch while Anvil works, its push is refused and nothing is overwritten; run the command again.
Commits are made by the bot (anvil) and end with an Anvil-Task: <task> #<id> line, so they're easy to tell apart. On repositories hosted on Anvil the bot needs write access to push; without it, use push: off.
The check command #
agents.command (for example pnpm test or ruff check .) runs after the change, and the agent can run it while it works to check itself. The result is in the progress comment.
The command runs only if the Anvil server allows it (AGENTS_COMMANDS=local; it's off by default). When it's off, the comment says the check didn't run. The command runs your repository's code, so it gets a throwaway home folder and an environment with nothing but PATH and CI=1, never Anvil's secrets, and it's killed after agents.command_timeout_s.
Recipes #
Recipes are prompts your repository keeps in .anvil.yaml, run with @anvil run <name>:
agents:
recipes:
- name: changelog
prompt: Add an entry for this pull request to CHANGELOG.md under "Unreleased", in the style of the existing entries.
- name: i18n
prompt: Move every user-facing string this pull request adds into locales/en.json and use t() for it.
command: pnpm lint:i18n
name is lowercase letters, digits, - and _. command replaces agents.command for that recipe. An unknown name gets a reply listing the recipes the repository has.
Autofix for CI #
agents:
autofix_ci: true
autofix_max_attempts: 1
When CI fails on a pull request, Anvil runs fix ci by itself. It stops after autofix_max_attempts automatic attempts per pull request (default 1), never runs on a commit it pushed itself or on its own anvil/ branches, never twice for the same commit, and waits while another Anvil task runs on the pull request. A paused pull request (@anvil pause) gets no autofix. The fix goes wherever agents.push says.
Limits and safety #
- Settings for agents are read from
.anvil.yamlon the base branch, so a pull request can't turn on autofix or push to its own branch by editing the file. - The agent works in a fresh checkout with tools to read, search, edit and create files there, and nothing else: no shell and no network. Every path is checked, symbolic links included, and edits to
.gitand to CI workflow files (.github/workflows,.gitea/workflows) are refused, because a pushed workflow would run with the repository's secrets. - A change that touches more than
agents.max_filesfiles is refused, and nothing is pushed. - Each task has a spending cap (
agents.max_budget_usd, never above the server's), a turn limit (agents.max_turns) and a 25-minute limit overall. A task that runs out of budget or time pushes nothing. - One task at a time per pull request. Tasks are never retried on their own, so nothing is pushed twice.
- Text in the code, the pull request and CI logs is treated as data. Everything Anvil posts is scrubbed of the secrets it holds.
GitHub repositories #
The commands and autofix work on GitHub repositories connected through the GitHub App: Anvil clones and pushes with the App's installation token, opens pull requests as the App, and checks the commenter's permission through GitHub's collaborator API. The App needs its default contents: write and pull_requests: write permissions. Applying suggestions uses your own GitHub sign-in.