O Claude Agent SDK fornece controles de permissão poderosos que permitem gerenciar como Claude usa ferramentas em sua aplicação.
Este guia aborda como implementar sistemas de permissão usando o callback canUseTool, hooks e regras de permissão settings.json. Para documentação completa da API, consulte a referência do SDK TypeScript.
O Claude Agent SDK fornece quatro maneiras complementares de controlar o uso de ferramentas:
Casos de uso para cada abordagem:
canUseTool - Aprovação dinâmica para casos não cobertos, solicita permissão ao usuárioOrdem de Processamento: PreToolUse Hook → Regras de Negação → Regras de Permissão → Regras de Solicitação → Verificação de Modo de Permissão → Callback canUseTool → PostToolUse Hook
Os modos de permissão fornecem controle global sobre como Claude usa ferramentas. Você pode definir o modo de permissão ao chamar query() ou alterá-lo dinamicamente durante sessões de streaming.
O SDK suporta quatro modos de permissão, cada um com comportamento diferente:
| Modo | Descrição | Comportamento da Ferramenta |
|---|---|---|
default | Comportamento de permissão padrão | Verificações de permissão normais se aplicam |
plan | Modo de planejamento - sem execução | Claude pode usar apenas ferramentas somente leitura; apresenta um plano antes da execução (Não suportado atualmente no SDK) |
acceptEdits | Aceitar automaticamente edições de arquivo | Edições de arquivo e operações do sistema de arquivos são aprovadas automaticamente |
bypassPermissions | Bypass de todas as verificações de permissão | Todas as ferramentas são executadas sem prompts de permissão (use com cuidado) |
Você pode definir o modo de permissão de duas maneiras:
Defina o modo ao criar uma consulta:
import { query } from "@anthropic-ai/claude-agent-sdk";
const result = await query({
prompt: "Help me refactor this code",
options: {
permissionMode: 'default' // Standard permission mode
}
});Altere o modo durante uma sessão de streaming:
acceptEdits)No modo aceitar edições:
Operações auto-aprovadas:
bypassPermissions)No modo bypass de permissões:
Os modos de permissão são avaliados em um ponto específico no fluxo de permissão:
bypassPermissions - Se ativo, permite todas as ferramentas restantescanUseToolcanUseTool - Manipula casos restantesIsso significa:
bypassPermissionsbypassPermissions substitui o callback canUseTool para ferramentas não correspondidasExemplo de progressão de modo:
// Start in default mode for controlled execution
permissionMode: 'default'
// Switch to acceptEdits for rapid iteration
await q.setPermissionMode('acceptEdits')O callback canUseTool é passado como uma opção ao chamar a função query. Ele recebe o nome da ferramenta e os parâmetros de entrada, e deve retornar uma decisão - permitir ou negar.
canUseTool dispara sempre que Claude Code mostraria um prompt de permissão a um usuário, por exemplo, hooks e regras de permissão não cobrem e não está no modo acceptEdits.
Aqui está um exemplo completo mostrando como implementar aprovação interativa de ferramentas:
A ferramenta AskUserQuestion permite que Claude faça perguntas de esclarecimento ao usuário durante uma conversa. Quando esta ferramenta é chamada, seu callback canUseTool recebe as perguntas e deve retornar as respostas do usuário.
Quando canUseTool é chamado com toolName: "AskUserQuestion", a entrada contém:
{
questions: [
{
question: "Which database should we use?",
header: "Database",
options: [
{ label: "PostgreSQL", description: "Relational, ACID compliant" },
{ label: "MongoDB", description: "Document-based, flexible schema" }
],
multiSelect: false
},
{
question: "Which features should we enable?",
header: "Features",
options: [
{ label: "Authentication", description: "User login and sessions" },
{ label: "Logging", description: "Request and error logging" },
{ label: "Caching", description: "Redis-based response caching" }
],
multiSelect: true
}
]
}Retorne as respostas em updatedInput.answers como um registro mapeando texto de pergunta para o(s) rótulo(s) de opção selecionada(s):
return {
behavior: "allow",
updatedInput: {
questions: input.questions, // Pass through original questions
answers: {
"Which database should we use?": "PostgreSQL",
"Which features should we enable?": "Authentication, Caching"
}
}
}Respostas de seleção múltipla são strings separadas por vírgula (por exemplo, "Authentication, Caching").
import { query } from "@anthropic-ai/claude-agent-sdk";
// Create an async generator for streaming input
async function* streamInput() {
yield {
type: 'user',
message: {
role: 'user',
content: "Let's start with default permissions"
}
};
// Later in the conversation...
yield {
type: 'user',
message: {
role: 'user',
content: "Now let's speed up development"
}
};
}
const q = query({
prompt: streamInput(),
options: {
permissionMode: 'default' // Start in default mode
}
});
// Change mode dynamically
await q.setPermissionMode('acceptEdits');
// Process messages
for await (const message of q) {
console.log(message);
}import { query } from "@anthropic-ai/claude-agent-sdk";
async function promptForToolApproval(toolName: string, input: any) {
console.log("\n🔧 Tool Request:");
console.log(` Tool: ${toolName}`);
// Display tool parameters
if (input && Object.keys(input).length > 0) {
console.log(" Parameters:");
for (const [key, value] of Object.entries(input)) {
let displayValue = value;
if (typeof value === 'string' && value.length > 100) {
displayValue = value.substring(0, 100) + "...";
} else if (typeof value === 'object') {
displayValue = JSON.stringify(value, null, 2);
}
console.log(` ${key}: ${displayValue}`);
}
}
// Get user approval (replace with your UI logic)
const approved = await getUserApproval();
if (approved) {
console.log(" ✅ Approved\n");
return {
behavior: "allow",
updatedInput: input
};
} else {
console.log(" ❌ Denied\n");
return {
behavior: "deny",
message: "User denied permission for this tool"
};
}
}
// Use the permission callback
const result = await query({
prompt: "Help me analyze this codebase",
options: {
canUseTool: async (toolName, input) => {
return promptForToolApproval(toolName, input);
}
}
});