Skip to content
ivralo
Sections

Docs / Developer mode

Editing and approvals

Every call that changes something stops at one dialog first. This page is that dialog in full, with the permission modes, how an unattended run may edit, and the cases where ivralo asks even when you said not to.

What asks and what does not

A call that only reads never asks: reading a file, searching, listing, git's reads, loading a skill, delegating to a specialist. These stop at the dialog and wait for you:

  • an edit or a new file (edit_file, write_file, a rename through the language server, the symbol edits);
  • run_python, the Python runtime;
  • a shell command the policy did not clear on its own (Shell commands);
  • a git write (staging, a commit, a branch, a revert) and the one push (Git);
  • a send, such as an e-mail or a chat message.

The run is paused underneath. Nothing the dialog shows is cut: an edit is shown as a diff of what is being replaced, a new file in full, a command highlighted the way the shell that runs it reads it. PageUp, PageDown and the arrow keys scroll it, and the answers stay on screen at any terminal size.

The dialog

The title says what ivralo wants to do, who asks, and the shape of the change (new file, 90 lines, overwrites, +12 −3). Under it are the call's facts:

RowWhat it says
effectsWhat the call does, read off the tool's contract (writes files, runs a command)
riskLow, medium or high, and what raised it
reasonWhy it asks although edits are accepted (a test the request did not name)
whereFor a coder in a worktree: which worktree the edit lands in
runsFor a verification: the declared commands it would run
<agent> saysThe asking agent's own words before the call, under its name, so they never read as ivralo's

Then the answers. Only the ones that apply to this call are shown:

KeyAnswerOffered on
yThis callevery call
EnterThis callevery call except a high-risk one
aThis call and everything else this turn wants to runevery call that does not always ask
sThis edit and every edit for the rest of the sessionedits
pRun it and always allow its prefix, or the host it reaches, in this repositoryshell commands and git writes, in a trusted folder
n, EscDeny, with a note for the modelevery call
dOpen the change in the diff viewer, read-only; q comes backedits

a dies with the turn. In a plan's wave it covers only that step's run, so a step running beside it still asks.

n does not dismiss at once. It opens a line where you say what to do instead, such as "keep the old return value, add a test instead", and Enter sends it to the model with the refusal. A second Esc refuses without a note.

Some calls always ask. For a tool whose contract says it always asks (a send, the push), the broader answers are not disabled: they are absent, so no key can lift that call.

High risk. On a high-risk call (a send, a change somewhere else such as GitHub through gh, or a tool no contract covers) Enter is not bound at all and the focus sits on deny. It takes one deliberate y.

Permission modes

ModeHow to turn it onWhat happens
Normalthe defaultEvery call above asks
Accept editss in an edit's dialog, or /accept-editsEdits land without a dialog for the rest of the session; shell commands, Python and sends still ask
Auto-approve/confirmNo call asks, except those that always ask

/accept-edits toggles accept edits on and off. /confirm toggles auto-approve; turning it off again turns accept edits off too, so all the asking comes back at once.

A parked job's question opens in the same dialog with three answers only: y, s for every edit of the rest of that job, and n. There is no turn for a to cover and no prefix for p to store.

Unattended runs and allow_tools

A run nobody is watching, such as ivralo ask in a pipe, a schedule or a job, has nobody to show a dialog to. Its Python runs inside the worker's limits (The Python worker), but an edit, a git write and a shell command that would ask are refused instead of run unseen, and so is a send.

The one way to let an unattended run edit is allow_tools in a permissions.json, the home's or the repository's .ivralo/permissions.json:

{
  "allow_tools": ["edit_file", "write_file"]
}
NameLets an unattended run
edit_fileEdit files, including the six symbol edits, which land through the same write
write_fileCreate files, or replace one whole; never lifted by edit_file
replace_symbol, replace_range, insert_before_symbol, insert_after_symbol, delete_symbol, add_importEach symbol edit on its own
git_create_branch, git_stage_files, git_unstage_files, git_commit, git_revert_commit, git_restore_fileEach git write on its own

Any other name is reported by ivralo doctor and ignored. In a session, a tool named there runs with an allowed line instead of a dialog. The repository's file is usually the right place: "this repository may be edited unattended" is rarely true of every repository you work in. In a folder you have not trusted, the repository's allow_tools does not apply.

A test the request did not name

The shortcut that turns a red suite green while the bug stays is editing the test. So an edit of an existing test file asks even under accept edits, with the reason edits a test the task did not name among its facts, and an unattended run refuses it even with edit_file in allow_tools.

A file counts as a test by the repository's own naming: under a directory called tests, test, __tests__ or spec, or named test_*, *_test.*, *.test.*, *.spec.*, FooTest or FooTests. The rule lifts when your request names the file, its path or a test inside it. What the main agent writes when it hands work to a specialist names nothing, so only your own words count. Creating a new test file is not editing one.

A rename or organize-imports through the language server is judged on every file it would change: one unnamed test among them makes the whole call ask, or be refused unattended.

When a test really is wrong, the agent is told to say so (which test, what it expects, what the code does instead) rather than change it. To let it edit, name the file in your request.

Integrating a coder's worktree

A Code Engineer working in its own git worktree, as a parallel coder or an instance, changes nothing in your workspace while it works. When it finishes, its whole change comes back as one patch, and that patch asks once more in the integration dialog: the step, the coder, and every file with its lines added and removed.

KeyAnswer
y, EnterApply the patch to your workspace
sApply it, and accept edits for the rest of the session
n, EscRefuse it; the worktree is kept
dOpen the whole patch in the diff viewer, with the same three answers

Each edit inside the worktree already asked as it was made. Accept edits for the session, or edit_file in allow_tools, lifts the integration dialog too. How the patch is applied, and what happens on a conflict, is on Parallel coders and worktrees.