109 lines
3.7 KiB
Markdown
109 lines
3.7 KiB
Markdown
|
|
---
|
|||
|
|
summary: "Exec approvals, allowlists, and sandbox escape prompts in the macOS app"
|
|||
|
|
read_when:
|
|||
|
|
- Configuring exec approvals or allowlists
|
|||
|
|
- Implementing exec approval UX in the macOS app
|
|||
|
|
- Reviewing sandbox escape prompts and implications
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# Exec approvals (macOS app)
|
|||
|
|
|
|||
|
|
Exec approvals are the **macOS companion app** guardrail for running host
|
|||
|
|
commands from sandboxed agents. Think of it as a per-agent “run this on my Mac”
|
|||
|
|
approval layer: the agent asks, the app decides, and the command runs (or not).
|
|||
|
|
This is **in addition** to tool policy and elevated gating; all of those checks
|
|||
|
|
must pass before a command can run.
|
|||
|
|
|
|||
|
|
If you are **not** running the macOS companion app, exec approvals are
|
|||
|
|
unavailable and `system.run` requests will be rejected with a message that a
|
|||
|
|
companion app is required.
|
|||
|
|
|
|||
|
|
## Settings
|
|||
|
|
|
|||
|
|
In the macOS app, each agent has an **Exec approvals** setting:
|
|||
|
|
|
|||
|
|
- **Deny**: block all host exec requests from the agent.
|
|||
|
|
- **Always ask**: show a confirmation dialog for each host exec request.
|
|||
|
|
- **Always allow**: run host exec requests without prompting.
|
|||
|
|
|
|||
|
|
Optional toggles:
|
|||
|
|
- **Auto-allow skill CLIs**: when enabled, CLIs referenced by known skills are
|
|||
|
|
treated as allowlisted (see below).
|
|||
|
|
|
|||
|
|
## Allowlist (per agent)
|
|||
|
|
|
|||
|
|
The allowlist is **per agent**. If multiple agents exist, you can switch which
|
|||
|
|
agent’s allowlist you’re editing. Entries are path-based and support **globs**.
|
|||
|
|
|
|||
|
|
Examples:
|
|||
|
|
- `~/Projects/**/bin/bird`
|
|||
|
|
- `~/.local/bin/*`
|
|||
|
|
- `/opt/homebrew/bin/rg`
|
|||
|
|
|
|||
|
|
Each allowlist entry tracks:
|
|||
|
|
- **last used** (timestamp)
|
|||
|
|
- **last used command**
|
|||
|
|
- **last used path** (resolved absolute path)
|
|||
|
|
- **last seen metadata** (hash/version/mtime when available)
|
|||
|
|
|
|||
|
|
## How matching works
|
|||
|
|
|
|||
|
|
1) Parse the command to determine the executable (first token).
|
|||
|
|
2) Resolve the executable to an absolute path using `PATH`.
|
|||
|
|
3) Match against denylist (if present) → **deny**.
|
|||
|
|
4) Match against allowlist → **allow**.
|
|||
|
|
5) Otherwise follow the Exec approvals policy (deny/ask/allow).
|
|||
|
|
|
|||
|
|
If **auto-allow skill CLIs** is enabled, each installed skill can contribute one
|
|||
|
|
or more allowlist entries. A skill-based allowlist entry only auto-allows when:
|
|||
|
|
- the resolved path matches, and
|
|||
|
|
- the binary hash/version matches the last approved record (if tracked).
|
|||
|
|
|
|||
|
|
If the binary changes (new hash/version), the command falls back to **Ask** so
|
|||
|
|
the user can re-approve.
|
|||
|
|
|
|||
|
|
## Approval flow
|
|||
|
|
|
|||
|
|
When the policy is **Always ask** (or when a binary has changed), the macOS app
|
|||
|
|
shows a confirmation dialog. The dialog should include:
|
|||
|
|
- command + args
|
|||
|
|
- cwd
|
|||
|
|
- environment overrides (diff)
|
|||
|
|
- policy + rule that matched (if any)
|
|||
|
|
|
|||
|
|
Actions:
|
|||
|
|
- **Allow once** → run now
|
|||
|
|
- **Always allow** → add/update allowlist entry + run
|
|||
|
|
- **Deny** → block
|
|||
|
|
|
|||
|
|
When approved, the command runs **in the background** and the agent receives
|
|||
|
|
system events as it starts and completes.
|
|||
|
|
|
|||
|
|
## System events
|
|||
|
|
|
|||
|
|
The agent receives system messages for observability and recovery:
|
|||
|
|
|
|||
|
|
- `exec.started` — command accepted and launched
|
|||
|
|
- `exec.finished` — command completed (exit code + output)
|
|||
|
|
- `exec.denied` — command blocked (policy or denylist)
|
|||
|
|
|
|||
|
|
These are **system messages**; no extra agent tool call is required to resume.
|
|||
|
|
|
|||
|
|
## Implications
|
|||
|
|
|
|||
|
|
- **Always allow** is powerful: the agent can run any host command without a
|
|||
|
|
prompt. Prefer allowlisting trusted CLIs instead.
|
|||
|
|
- **Ask** keeps you in the loop while still allowing fast approvals.
|
|||
|
|
- Per-agent allowlists prevent one agent’s approval set from leaking into others.
|
|||
|
|
|
|||
|
|
## Storage
|
|||
|
|
|
|||
|
|
Allowlists and approval settings are stored **locally in the macOS app** (SQLite
|
|||
|
|
is a good fit). The Markdown docs describe behavior; they are not the storage
|
|||
|
|
mechanism.
|
|||
|
|
|
|||
|
|
Related:
|
|||
|
|
- [Exec tool](/tools/exec)
|
|||
|
|
- [Elevated mode](/tools/elevated)
|
|||
|
|
- [Skills](/tools/skills)
|