Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Approvals

Approvals are how you decide which tools run without asking. One setting drives them: tools.approvalMode. There is no operating-system sandbox behind it (no Landlock, seccomp, Seatbelt, or bubblewrap). Shell commands and file writes run as your user, bounded only by this policy, per-tool tools.approval overrides, and the hard-coded flagged bash patterns below.

Operator reference. For the model behind it, see Permission model. For the wider boundary, see Safety.

Tool tiers

TierExamples
readread, search, listing
writeedit, write
execbash and other command execution

Modes

Modereadwriteexec
planautoask with an active plan-mode session, denied otherwisedenied
askaskaskask
ask-commandautoautoask
autoautoautoauto, except the per-tool, working-directory, credential and flagged-command checks, which still prompt
yoloautoautoauto, except a blatantly destructive command, which still prompts

Schema default: auto. Legacy aliases: always-ask → ask, write and auto-edit → ask-command.

$ veyyon --approval-mode ask-command
$ veyyon --yolo                    # same as --auto-approve → yolo
$ veyyon --plan-yolo               # plan now; yolo after leaving plan mode
tools:
  approvalMode: ask

The approval prompt

When the active mode requires approval for a tool call, the TUI shows a Permission required card. The card shows the tool, states that the decision applies to this call only, separates the reason from the requested command or file operation, and waits on four options, five for a bash call that reports a pattern:

  • Approve: run this call once. Nothing is remembered.
  • Approve "<pattern>" for session: run this and every later call that reports the same pattern, until you exit. Only bash reports one.
  • Approve for session: run this and every later call to this tool, until you exit.
  • Deny: reject this call and return Tool call denied by user: <name> to the model.
  • Deny for session: reject this and every later call to this tool, until you exit.

The “for session” rows are session memory, not policy: nothing is written to tools.approval, and the next launch prompts again. A remembered decision also covers only the ordinary tier prompt. The three prompts that are about a call’s ARGUMENTS rather than its tool name still prompt every time: a flagged bash command, a path outside the working directory, and a call that spends a stored credential.

A bash pattern keeps the program and, for a subcommand, the subcommand: git status -s reports git status *, which covers git status and git status --short src and not git log. A second word that is not a subcommand is kept verbatim, so ls -la reports ls -la and covers only that command. A program that runs another command (sudo, xargs, env, ssh, bash, nohup, timeout) reports its exact command. A call reports no pattern when it contains quoting, $, ~, a backtick, a glob, a pipe, a separator, a subshell, a redirect, a comment or a newline, when it assigns a variable before the program or sets an environment variable or working directory, when the pattern would be longer than 48 characters, or when the guard flags it. A pattern grant is compared by string equality with the pattern the next call reports.

The selected option uses a radio marker and includes a short description. Navigate with the usual list keys (up/down, enter to confirm, esc to cancel; cancelling counts as a denial). Denied actions return an error to the model, and permissions are never widened.

Headless

veyyon --print has no terminal to prompt in. If the mode would require approval, the tool call fails with an error that explains the required setting or override (set tools.approvalMode: yolo, add tools.approval.<name>: allow, or use an interactive UI), and the model receives that error. To run unattended, pass --yolo or pick a mode that does not prompt for the tiers you need. The process exit status follows the run.

Critical bash commands

Some shell commands always prompt in plan, ask, ask-command and auto, even over a per-tool allow override. The check is implemented in packages/coding-agent/src/tools/shell/bash-guard.ts and has two halves.

The first half inspects what a command would delete, after expansion rather than as text. It resolves a leading tilde and $HOME, evaluates every target rather than only the first, and stops a recursive delete of the home directory, of anything containing it, of a system directory, or of a directory holding your credentials. It also stops a recursive delete whose target it cannot resolve, such as rm -rf "$dir"/*, because an empty $dir makes that command start at the root. It also stops a truncating redirect into a credentials directory, such as echo x > ~/.ssh/id_ed25519; appending with >> is left alone. Deletes inside your workspace, such as rm -rf node_modules or rm -rf dist, run without a prompt, and so do ordinary redirects such as bun test > /tmp/results.txt.

The second half is a pattern list (FLAGGED_BASH_PATTERNS, same file) for shapes with no path to expand, and each entry records what it would do. The destructive ones are sudo rm, recursive chmod/chown on /, fork bombs, disk and filesystem destruction (mkfs, dd to a device, writes to /dev/sd*), and writes to /etc/passwd/shadow/sudoers. The dangerous ones are a remote fetch piped to a shell (curl … | sh and its process-substitution and eval variants), host control (shutdown, reboot, kill -9 1), and network shells (nc -e): these run code nobody read or restart the machine, without destroying anything.

Neither half can be narrowed. You can widen the first half with tools.protectedPaths, a list of absolute paths (a leading ~ is expanded) that a recursive delete must also stop for. It only adds: the built-in rules read no configuration, so no value there stops the check from prompting for a delete of your home directory. See the permission model for an example.

The destructive half, and the whole of the first half, stop for approval in yolo as well, and the /yolo session bypass does not lift them. That floor is the one place yolo does not auto-approve. The dangerous half prompts on every rung below yolo and not on yolo itself. To turn the floor off on yolo, set tools.approval.bash to allow; below yolo the check takes precedence over allow, and deny is a hard block on every rung.

Separately, the bash interceptor (bashInterceptor.enabled, default off) blocks shell commands that duplicate dedicated tools, so the model uses read/search instead of cat/rg/find. Its rules are defined in bashInterceptor.patterns.