pub struct ToolPermissionRequest {
pub tool_name: String,
pub input: Value,
pub permission_suggestions: Vec<PermissionSuggestion>,
pub blocked_path: Option<String>,
pub decision_reason: Option<String>,
pub tool_use_id: Option<String>,
}Expand description
Tool permission request details
This is sent when Claude wants to use a tool. The SDK should evaluate the request and respond with allow/deny using the ergonomic builder methods.
§Example
use claude_codes::{ToolPermissionRequest, ControlResponse};
use serde_json::json;
fn handle_permission(req: &ToolPermissionRequest, request_id: &str) -> ControlResponse {
// Block dangerous bash commands
if req.tool_name == "Bash" {
if let Some(cmd) = req.input.get("command").and_then(|v| v.as_str()) {
if cmd.contains("rm -rf") {
return req.deny("Dangerous command blocked", request_id);
}
}
}
// Allow everything else
req.allow(request_id)
}Fields§
§tool_name: StringName of the tool Claude wants to use (e.g., “Bash”, “Write”, “Read”)
input: ValueInput parameters for the tool
permission_suggestions: Vec<PermissionSuggestion>Suggested permissions that could be granted to avoid repeated prompts
blocked_path: Option<String>Path that was blocked (if this is a retry after path-based denial)
decision_reason: Option<String>Reason why this tool use requires approval
tool_use_id: Option<String>The tool use ID for this request
Implementations§
Source§impl ToolPermissionRequest
impl ToolPermissionRequest
Sourcepub fn allow(&self, request_id: &str) -> ControlResponse
pub fn allow(&self, request_id: &str) -> ControlResponse
Allow the tool to execute with its original input.
§Example
let req = ToolPermissionRequest {
tool_name: "Read".to_string(),
input: json!({"file_path": "/tmp/test.txt"}),
permission_suggestions: vec![],
blocked_path: None,
decision_reason: None,
tool_use_id: None,
};
let response = req.allow("req-123");Sourcepub fn allow_with(
&self,
modified_input: Value,
request_id: &str,
) -> ControlResponse
pub fn allow_with( &self, modified_input: Value, request_id: &str, ) -> ControlResponse
Allow the tool to execute with modified input.
Use this to sanitize or redirect tool inputs. For example, redirecting file writes to a safe directory.
§Example
let req = ToolPermissionRequest {
tool_name: "Write".to_string(),
input: json!({"file_path": "/etc/passwd", "content": "test"}),
permission_suggestions: vec![],
blocked_path: None,
decision_reason: None,
tool_use_id: None,
};
// Redirect to safe location
let safe_input = json!({"file_path": "/tmp/safe/passwd", "content": "test"});
let response = req.allow_with(safe_input, "req-123");Sourcepub fn allow_with_permissions(
&self,
modified_input: Value,
permissions: Vec<Value>,
request_id: &str,
) -> ControlResponse
pub fn allow_with_permissions( &self, modified_input: Value, permissions: Vec<Value>, request_id: &str, ) -> ControlResponse
Allow with updated permissions list (raw JSON Values).
Prefer using allow_and_remember for type safety.
Sourcepub fn allow_and_remember(
&self,
permissions: Vec<Permission>,
request_id: &str,
) -> ControlResponse
pub fn allow_and_remember( &self, permissions: Vec<Permission>, request_id: &str, ) -> ControlResponse
Allow the tool and grant permissions for “remember this decision”.
This is the ergonomic way to allow a tool while also granting permissions so similar actions won’t require approval in the future.
§Example
use claude_codes::{ToolPermissionRequest, Permission};
use serde_json::json;
let req = ToolPermissionRequest {
tool_name: "Bash".to_string(),
input: json!({"command": "npm test"}),
permission_suggestions: vec![],
blocked_path: None,
decision_reason: None,
tool_use_id: None,
};
// Allow and remember this decision for the session
let response = req.allow_and_remember(
vec![Permission::allow_tool("Bash", "npm test")],
"req-123",
);Sourcepub fn allow_with_and_remember(
&self,
modified_input: Value,
permissions: Vec<Permission>,
request_id: &str,
) -> ControlResponse
pub fn allow_with_and_remember( &self, modified_input: Value, permissions: Vec<Permission>, request_id: &str, ) -> ControlResponse
Allow the tool with modified input and grant permissions.
Combines input modification with “remember this decision” functionality.
Sourcepub fn allow_and_remember_suggestion(
&self,
request_id: &str,
) -> Option<ControlResponse>
pub fn allow_and_remember_suggestion( &self, request_id: &str, ) -> Option<ControlResponse>
Allow the tool and remember using the first permission suggestion.
This is a convenience method for the common case of accepting Claude’s first suggested permission (usually the most relevant one).
Returns None if there are no permission suggestions.
§Example
use claude_codes::ToolPermissionRequest;
use serde_json::json;
let req = ToolPermissionRequest {
tool_name: "Bash".to_string(),
input: json!({"command": "npm test"}),
permission_suggestions: vec![], // Would have suggestions in real use
blocked_path: None,
decision_reason: None,
tool_use_id: None,
};
// Try to allow with first suggestion, or just allow without remembering
let response = req.allow_and_remember_suggestion("req-123")
.unwrap_or_else(|| req.allow("req-123"));Sourcepub fn deny(
&self,
message: impl Into<String>,
request_id: &str,
) -> ControlResponse
pub fn deny( &self, message: impl Into<String>, request_id: &str, ) -> ControlResponse
Deny the tool execution.
The message will be shown to Claude, who may try a different approach.
§Example
let req = ToolPermissionRequest {
tool_name: "Bash".to_string(),
input: json!({"command": "sudo rm -rf /"}),
permission_suggestions: vec![],
blocked_path: None,
decision_reason: None,
tool_use_id: None,
};
let response = req.deny("Dangerous command blocked by policy", "req-123");Sourcepub fn deny_and_stop(
&self,
message: impl Into<String>,
request_id: &str,
) -> ControlResponse
pub fn deny_and_stop( &self, message: impl Into<String>, request_id: &str, ) -> ControlResponse
Deny the tool execution and stop the entire session.
Use this for severe policy violations that should halt all processing.
Sourcepub fn answer_questions(
&self,
answers_by_index: &HashMap<usize, String>,
request_id: &str,
) -> Result<ControlResponse, AskUserQuestionResponseError>
pub fn answer_questions( &self, answers_by_index: &HashMap<usize, String>, request_id: &str, ) -> Result<ControlResponse, AskUserQuestionResponseError>
Build an allow response for an AskUserQuestion permission request
by supplying the user’s chosen answers.
The CLI’s AskUserQuestion tool has a finicky wire contract that
is easy to get wrong by hand:
- The response’s
inputmust preserve the originalquestionsarray. Stripping it (sending just{"answers": ...}) makes the downstream viewer crash withundefined is not an object (evaluating 'q.map')(the CLI echoes theupdatedInputwe return intotool_use_result, and viewers readtool_use_result.questions). - The
answersmap must be keyed by the full question text (thequestionfield). Keying byheaderor by question index makes the CLI’s tool render"Your questions have been answered: ."with an empty answer body, leaving Claude unable to see which option the user picked.
This helper does both correctly: it parses self.input as
AskUserQuestionInput, looks each
answer up by question index, and inserts the answer keyed by
q.question. The original questions (and any metadata) pass
through unchanged.
answers_by_index maps 0-based question index into the original
questions array to the user’s chosen answer label. For
multi-select questions, join the selected labels with ", ".
Questions not in the map are treated as unanswered.
Non-AskUserQuestion callers should keep using
allow / allow_with.
§Errors
Returns AskUserQuestionResponseError if the request isn’t an
AskUserQuestion request, the input doesn’t parse, or an answer
references a question index that doesn’t exist.
§Example
use claude_codes::ToolPermissionRequest;
use std::collections::HashMap;
fn answer(req: &ToolPermissionRequest, request_id: &str) {
let mut answers = HashMap::new();
answers.insert(0_usize, "Blue".to_string());
let response = req
.answer_questions(&answers, request_id)
.expect("request is AskUserQuestion-shaped");
// send `response` back to the CLI
}Trait Implementations§
Source§impl Clone for ToolPermissionRequest
impl Clone for ToolPermissionRequest
Source§fn clone(&self) -> ToolPermissionRequest
fn clone(&self) -> ToolPermissionRequest
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more