Skip to content

Tool approvals

The rules that decide if a tool call needs your approval in the terminal and desktop apps, and what each answer does.

Tool approvals decide who approves a tool call before it runs. Ask, the default in both apps, asks you. Model decision lets the decision model approve clearly intended calls and block clearly risky ones. When it is unsure, it asks you. Full access runs every call without asking. Typing into a terminal you opened still asks. The cards and keys are on terminal approvals and desktop approvals.

How a call is decided#

The host checks each tool call in order:

  1. Tool approvals is Full access: the call runs.
  2. The tool is implicitly safe: the call runs.
  3. The call matches the project's safelist, or you approved it for this session: the call runs.
  4. Tool approvals is Model decision and the decision model is sure: it approves or blocks the call.
  5. Otherwise the run pauses for your answer.

Pick the mode in Settings › Agent › Guardrails › Tool approvals in the terminal, and in Settings › Agent › Approvals & safety › Tool approvals in the desktop app.

Tools that never ask#

WhyTools
Read filesread_file, list_files, glob, grep
Track worktodowrite, todoread, skills_use
They ask you anywayask_user, present_plan
Read the session's terminalsterminal_list, terminal_read
Use the dev browserEvery browser tool except browser_evaluate. browser_open and browser_navigate skip the question only for a loopback address such as localhost.
Read the chat a side session was opened onread_parent_session

terminal_write types into a shell, so it asks like shell. skills_read and skills_run_script also ask.

Your answers#

AnswerDoesTerminalDesktop
OnceRuns this callaccept onceAllow once
For the sessionRuns this and every matching call in this sessionaccept for sessionFile edits only (Allow for session)
RememberRuns it and adds a safelist entry for the projectaccept + rememberAlways allow
DenyBlocks the call. The agent reads that you refused.denyDeny

edit, multi_edit and write_file show the diff first. For an edit with several hunks, you tick the ones to apply. The agent learns which you applied.

Safelist#

The safelist is a per-project list in projects.json in your config folder (where). The project is the git root, so subfolders and every worktree of a repo share one list.

EntryMatches
grepEvery call to that tool
shell:git:*Shell commands whose first word is git
browser_navigate:example.comThat browser tool on that host (port included)
projects.json
{
  "/Users/me/my-app": { "safelist": ["grep", "shell:git:*", "shell:bun:*"] }
}

A shell command with several parts (&&, ||, ;, |, $(...), subshells) skips the question only when every part is on the list. So Remember on cd src && bun test adds shell:cd:* and shell:bun:*. A command zidane cannot parse always asks. Review entries in the desktop safelist panel (Settings › Agent › Approvals & safety) or edit projects.json by hand.

Plans and questions#

ToolYou can
present_planApprove, revise with a note, or reject. A rejection stops the run.
ask_userPick options, type an answer, or give a secret (below)

Interaction modes#

Interaction mode sets what happens when the agent calls them. It is in Settings › Agent › Guardrails in the terminal, and in Settings › Agent › Defaults in the desktop app.

ModeThe agent
Ask normally (ask, default)Waits for your answer
Skip interactions (skip)Gets an automatic answer and decides from the repository. Plans are approved, yes/no questions get yes, choices get the first option, and text questions get no answer.
Disable tools (disabled)Has no present_plan or ask_user tool

Switching to Skip answers the questions already waiting. Prompts from / commands and extensions ask in every mode.

Secrets#

With Secrets on (Settings, Guardrails group, off by default), ask_user can ask you for an API key or a token. You type it in a password field and pick how long zidane keeps it: 1 hour, 24 hours (the default), 7 days or until you revoke it. Then press Save securely, or Decline.

The value never goes into the chat. zidane keeps it in a private file for the project: ~/.zidane/secrets/<project-hash>/ on your computer, or /tmp/zidane-secrets/<project-hash>/ inside a Docker, E2B or Daytona sandbox. The agent's commands read it at $ZIDANE_SECRETS/NAME. Tool output shows a saved value as [secret:NAME], and the transcript shows "Saved NAME, expires in 24 hours". A value shorter than 4 characters is not hidden. A secret is removed when it expires, even if nothing reads it.

When the agent asks again for a saved name, zidane uses the saved one without asking. In Skip mode, and in Slack and GitHub channels, nobody can type a value: zidane uses a saved one or declines. A value only travels over the local app, TLS, or a connection from the server machine itself. Revoke secrets in the Secrets panel of the desktop app or on the Secrets page of the terminal app's settings. The full rules are in INTERACTIONS.md.

With several windows#

With the daemon, every window shows approvals and questions, zidane attach included, and the first answer wins. Without it, only the window that started the run can answer. A browser connected through a zidane-server answers them with its chat token (UI kit adapters).

Limits and the sandbox#

Run limits (both apps) stop a run:

SettingStops a run afterDefault
Max turns per run (maxTurns)That many turnsUnlimited
Max cost per run (maxCostUsd)The estimated cost passes the amountUnlimited
Max tokens per run (maxTotalTokens)That many tokensUnlimited
Max run time (maxWallMinutes)That much timeUnlimited

SDK options and errors: run-level budgets.

Sandbox shell commands confines the agent's commands and edits to the project and hides your credential files (OS sandbox). With Full access and the sandbox on, the agent runs without asking and stays inside the project.

Headless runs and editors#

zidane run --json and --stream-json never ask. Every tool call runs (headless approvals). Through ACP, zidane asks your editor for permission.