Skip to Content
DocsSecurityOverview

Security

Every tool call goes through a four-layer gate. Each layer is independently configurable and has a no-op default. Pay only for what you wire up.

@before_tool hooks Permissions check ─── deny ──► tool result = denied Sandbox wrap Tool dispatch @after_tool hooks Audit log entry

Read more

The four layers

1. Permissions

Decides yes / no / ask per tool call. Default AllowAll (no-op); production usually wants StandardPermissions(mode=Mode.DEFAULT), which routes destructive tools through an approval handler.

2. Hooks

@agent.before_tool runs before the call (returning a denial short-circuits the dispatch). @agent.after_tool runs after, with the ToolResult. Used for inline review, redaction, custom metrics, or whatever else doesn’t fit a standard policy.

3. Sandboxes

Wraps the tool host with isolation. FilesystemSandbox blocks path arguments that escape declared roots (symlink-aware). SubprocessSandbox runs each tool in a fresh child process for crash isolation and hard timeouts.

4. Audit log

Every tool call lands in the audit log with user_id attribution. HMAC signatures cover the entries. Tampering breaks verification. See Audit log attribution.

Pick a starting profile

You want…Start here
Dev / CI / sandboxpermissions=StandardPermissions(mode=Mode.BYPASS)
Single-user productivity toolmode=Mode.ACCEPT_EDITS, audit_log=FileAuditLog(...)
Multi-tenant SaaSpermissions=PerUserPermissions(policies=, default=), approval_handler=..., audit_log=...
Coding agent with FS accesswrap tools in FilesystemSandbox, mode ACCEPT_EDITS, audit on

Defaults are fast. Agent ships with AllowAll permissions, no hooks, NoSandbox, and audit_log=None. The agent loop detects each layer is a no-op and skips it on the hot path. The moment you wire a real implementation, the corresponding integration point flips on. Same Agent class, same API, no flags.

Last updated on