# Tool approvals and permissions The Harness provides a permission system that controls which tools require user approval before execution. You can configure policies at the category level or per-tool, and grant session-wide exceptions for trusted tools. This gives agents with access to destructive or sensitive tools — file writes, command execution, API calls — a human-in-the-loop checkpoint before those tools run. ## Permission policies Three policies control tool behavior: - `allow`: The tool runs without prompting - `ask`: The tool pauses and emits a `tool_approval_required` event; the user must approve or decline - `deny`: The tool is blocked from execution ### Setting policies Set policies per-category or per-tool. Per-tool policies take precedence over category policies: ```typescript // Category-level: all execute tools require approval harness.setPermissionForCategory({ category: 'execute', policy: 'ask' }) // Tool-level: this specific tool is always blocked harness.setPermissionForTool({ toolName: 'dangerous_tool', policy: 'deny' }) ``` ### Tool categories The `toolCategoryResolver` maps tool names to categories. Pass it to the Harness constructor: ```typescript const harness = new Harness({ id: 'my-agent', toolCategoryResolver: toolName => { if (toolName.includes('write') || toolName.includes('delete')) return 'edit' if (toolName.includes('execute')) return 'execute' return 'read' }, }) ``` Built-in categories are `read`, `edit`, `execute`, `mcp`, and `other`. ## Responding to approval requests When a tool's policy is `ask`, the Harness emits a `tool_approval_required` event. Your UI should display a prompt and call `session.respondToToolApproval()`: ```typescript harness.subscribe(event => { if (event.type === 'tool_approval_required') { // Show approval UI... harness.session.respondToToolApproval({ decision: 'approve' }) } }) ``` The `decision` field accepts `'approve'`, `'decline'`, or `'always_allow_category'`. When `always_allow_category` is used, the tool's category is granted for the rest of the session. Future tools in the same category are auto-approved. ```typescript harness.session.respondToToolApproval({ decision: 'always_allow_category' }) ``` ## Session grants The Harness owns permission _policy_ (which categories require approval); the [`Session`](https://mastra.ai/docs/harness/session) owns the _grants_ a user makes during a conversation. Grant a category or tool for the rest of the session so it runs without further prompting: ```typescript // Grant all edit tools for this session harness.session.grantCategory('edit') // Grant a specific tool harness.session.grantTool('mastra_workspace_execute_command') // Check current grants const grants = harness.session.getGrants() // { categories: ['edit'], tools: ['mastra_workspace_execute_command'] } ``` ## Tool suspensions Interactive built-in tools (`ask_user`, `submit_plan`) use the native tool-suspension primitive instead of the approval flow. They emit a `tool_suspended` event with `toolCallId`, `toolName`, and `suspendPayload`. Resume with `respondToToolSuspension()`: ```typescript harness.subscribe(event => { if (event.type === 'tool_suspended' && event.toolName === 'ask_user') { const { question } = event.suspendPayload as { question: string } // Show question to user, then resume: harness.respondToToolSuspension({ toolCallId: event.toolCallId, resumeData: 'User response here', }) } }) ``` ### Plan approval The `submit_plan` tool suspends via the same mechanism. Resume with an `action` field: ```typescript // Approve the plan harness.respondToToolSuspension({ toolCallId: event.toolCallId, resumeData: { action: 'approved' }, }) // Reject with feedback harness.respondToToolSuspension({ toolCallId: event.toolCallId, resumeData: { action: 'rejected', feedback: 'Needs more detail' }, }) ``` ## Built-in tools The Harness provides these built-in tools to agents in every mode: | Tool | Description | | --------------- | ------------------------------------------------------------------- | | `ask_user` | Ask the user a question (free text, single-select, or multi-select) | | `submit_plan` | Submit a plan for user review and approval | | `task_write` | Create or replace a structured task list | | `task_update` | Update one tracked task by ID | | `task_complete` | Mark one tracked task completed | | `task_check` | Check task list completion status | | `subagent` | Spawn a focused subagent (requires `subagents` config) | Disable specific built-in tools with `disableBuiltinTools`: ```typescript const harness = new Harness({ id: 'no-plans', disableBuiltinTools: ['submit_plan'], }) ``` ## Related - [Harness overview](https://mastra.ai/docs/harness/overview) - [Session](https://mastra.ai/docs/harness/session) - [Subagents](https://mastra.ai/docs/harness/subagents) - [Agent approval](https://mastra.ai/docs/agents/agent-approval) - [API reference](https://mastra.ai/reference/harness/harness-class)