Approvals & Safety

Approve tool calls before they touch your files

Tools that read your files ask permission first, and an unanswered request always defaults to deny.

python
from praisonaiagents import Agent

agent = Agent(
    name="Assistant",
    instructions="You are a helpful assistant.",
)
# When this agent calls a file tool in the Desktop app,
# an approval card appears before the tool runs.
agent.start("Read notes.txt and summarize it")
Diagram
graph LR
    Call[🔧 Tool Call] --> Ask{⚿ Approve?}
    Ask -->|Allow| Run[✅ Runs]
    Ask -->|Deny / timeout| Stop[🛑 Declined]

    classDef call fill:#189AB4,stroke:#7C90A0,color:#fff
    classDef ask fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef run fill:#10B981,stroke:#7C90A0,color:#fff
    classDef stop fill:#8B0000,stroke:#7C90A0,color:#fff

    class Call call
    class Ask ask
    class Run run
    class Stop stop

Quick Start

  1. Pick an approval mode

    Open Settings → Safety → Tool approval and choose ask, smart, or never.

  2. Answer the card

    When a tool call arrives, an approval card offers Allow, Always allow, or Deny.

  3. Let silence deny

    If you do nothing, the request is declined after the timeout — the default is 300 seconds.


How It Works

Each approval carries a call_id, so a decision is bound to the specific tool call rather than to whichever prompt happens to be pending.

Diagram
👤 You🧠 Engine🤖 Agent👤 You🧠 Engine🤖 Agentalt[allowed][denied or timeout]tool_call (read_file)approval_request {msg_id, approval_id, call_id, name, args}POST /approve/{aid} {choice}tool executes“The user declined this tool call.”

The event carries name (the tool name) and args (the tool arguments) so the approval card can show what is about to run, not just that something is.

What smart mode waives

smart mode waives the approval card for a small allowlist of low-risk read tools and still prompts for everything else. Any tool that isn’t on the low-risk list — including new tools added in a future release — is treated as high-risk and shows the card.

ToolUnder smartNotes
read_file✅ No cardReads a file on disk
list_directory✅ No cardLists a directory’s entries
current_time✅ No cardReturns the current clock time
web_search✅ No cardRuns a web search query
fetch_url⚠️ Card shownNetwork fetch — still gated (redirects are re-gated too)
_any other builtin_⚠️ Card shownUnknown tools default to high-risk

An approval binds to one URL

fetch_url treats the approved URL as the URL — nothing else. A page that redirects stops at the redirect and returns an error rather than silently following it. To follow the new URL, ask for it again and get a fresh approval card for it.

Diagram
sequenceDiagram
    participant You as 👤 You
    participant Engine as 🧠 Engine
    participant Site as 🌐 example.com
    participant Elsewhere as 🌐 elsewhere

    Engine->>You: approval_request (fetch_url, https://example.com/a)
    You->>Engine: Allow
    Engine->>Site: GET /a
    Site-->>Engine: 302 Location: https://elsewhere/x
    Engine-->>Engine: refuse (redirect not approved)
    Engine->>You: "Fetch failed: HTTPError: redirect to https://elsewhere/x was not approved"
    Note over You,Engine: A new URL needs a new approval card.

    classDef prompt fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef site fill:#189AB4,stroke:#7C90A0,color:#fff
    classDef step fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef allow fill:#10B981,stroke:#7C90A0,color:#fff
    classDef refuse fill:#8B0000,stroke:#7C90A0,color:#fff

    class You prompt
    class Site site
    class Elsewhere step
    class Engine refuse
SituationWhat happens
Approved URL returns 200Body is returned (up to ~400 KB, UTF-8, replacement chars on decode errors).
Approved URL returns 3xxThe fetch stops. The tool returns Fetch failed: HTTPError: redirect to <url> was not approved.
Non-http(s) URLRejected before the gate: Only http and https URLs are supported.
Any other errorReturned as `Fetch failed:

: <message>`. |

SettingValuesDefault
approval_modeask \smart \neverask
approval_timeoutseconds (10–3600)300
confirm_deletetrue \falsetrue

The three buttons:

ButtonEffect
AllowRuns this one call
Always allowPersists for that tool name for the rest of the session
DenyDeclines this call

Choosing a Mode

Diagram

Review everything

Waive low-risk reads,
prompt on everything else

Trust the agent

How much
friction?

ask

smart

never

ModeBehaviourBest for
askPrompts on every file tool callMaximum control
smartWaives an allowlist of low-risk reads (read_file, list_directory, current_time, web_search) and prompts on everything elseBalanced
neverRuns file tools without askingYou fully trust the agent

See What smart mode waives for the full per-tool table and the fail-closed default.


Best Practices

Start with ask

The default ask mode surfaces every file read. Loosen to smart or never only once you trust the agent’s behaviour.

Use Always allow sparingly

Always allow persists for the whole session per tool name. Use it for tools you re-run constantly, not one-offs.

Keep the timeout short if unattended

The timeout declines unanswered requests. A shorter approval_timeout frees a stuck turn faster when you step away.

Re-approve a redirected URL by name

If fetch_url reports redirect to <url> was not approved, that’s the gate refusing to hand the new URL your approval. Ask the agent to fetch that URL directly if you want the content — you’ll get a fresh approval card for it, and you decide whether the second hop is allowed.


Related