Skip to content

Answering permission requests

When the CLI asks whether it may do something, the responder decides.

command.onPermission((request) => {
if (request.subtype === 'can_use_tool') return request.approve();
return request.deny('user declined');
});

The reply is built on the request, because a reply is only meaningful paired with the request_id it answers — and that id arrived with the request.

A host may also edit what the CLI proposed before allowing it, which is how a UI lets a user amend a command before it runs:

command.onPermission((request) => request.approve({ command: 'ls -la' }));

Returning null leaves the request unanswered, which stalls the CLI. Do that only when something else will answer it.

The payload that reaches the CLI is nested twice, and it has to be. The outer response is the delivery envelope — that a reply was produced, and which request it answers — while the inner one carries the decision:

{
"type": "control_response",
"response": {
"subtype": "success",
"request_id": "req-7",
"response": { "behavior": "allow", "updatedInput": { "command": "ls -la" } }
}
}