Documentation Index
Fetch the complete documentation index at: https://kawax.biz/llms.txt
Use this file to discover all available pages before exploring further.
Permission request
Default behavior (deny-all)
If permission_approve is set to "deny-all" (default) in config/copilot.php, all permission requests are automatically denied when you use Copilot::run() or Copilot::start().
This is a safe default when your main use case is text generation, where permissions are usually unnecessary.
// config/copilot.php
'permission_approve' => env('COPILOT_PERMISSION_APPROVE', 'deny-all'),
Configurable values
| Value | Behavior |
|---|
"deny-all" | Auto-deny everything (default) |
"approve-safety" | Deny only shell and write; auto-approve others |
"approve-all" | Auto-approve everything |
false | No handler → onPermissionRequest is required (same as official SDK) |
// .env
COPILOT_PERMISSION_APPROVE="approve-safety"
If you allow user prompt input, "approve-safety" and "approve-all" are dangerous.
Always use false or "deny-all".
Even read-only access can be risky because it can expose your Laravel project code.
PermissionHandler::approveAll()
Use PermissionHandler::approveAll() to auto-approve all requests.
use Revolution\Copilot\Facades\Copilot;
use Revolution\Copilot\Support\PermissionHandler;
use Revolution\Copilot\Types\SessionConfig;
$config = new SessionConfig(
onPermissionRequest: PermissionHandler::approveAll(),
);
$response = Copilot::run(prompt: 'Hello', config: $config);
PermissionHandler::approveSafety()
Use PermissionHandler::approveSafety() to deny only high-risk permissions (shell, write) and auto-approve others.
use Revolution\Copilot\Facades\Copilot;
use Revolution\Copilot\Support\PermissionHandler;
use Revolution\Copilot\Types\SessionConfig;
$config = new SessionConfig(
onPermissionRequest: PermissionHandler::approveSafety(),
);
$response = Copilot::run(prompt: 'Hello', config: $config);
This still may not be fully safe.
If you need precise control, write a custom handler and decide based on $request['kind'].
PermissionHandler::denyAll()
Use PermissionHandler::denyAll() to deny everything.
use Revolution\Copilot\Support\PermissionHandler;
use Revolution\Copilot\Types\SessionConfig;
$config = new SessionConfig(
onPermissionRequest: PermissionHandler::denyAll(),
);
Direct client usage
When you use CopilotClient directly, specifying onPermissionRequest is required, just like the official SDK.
use Revolution\Copilot\Client;
use Revolution\Copilot\Support\PermissionHandler;
$client = new Client([
'cli_path' => 'copilot',
'cli_args' => [],
'cwd' => base_path(),
'log_level' => 'info',
'env' => null,
]);
$client->start();
// onPermissionRequest is required
$session = $client->createSession([
'onPermissionRequest' => PermissionHandler::approveSafety(),
]);
// If omitted, InvalidArgumentException is thrown
// $session = $client->createSession([]); // Error!
Custom handler
To control approval or rejection per request type, pass a closure.
$request and $invocation are arrays like the examples below.
use Illuminate\Support\Facades\Artisan;
use Revolution\Copilot\Contracts\CopilotSession;
use Revolution\Copilot\Facades\Copilot;
use Revolution\Copilot\Support\PermissionRequestResultKind;
use Revolution\Copilot\Types\SessionConfig;
use function Laravel\Prompts\{confirm, note, spin, text};
Artisan::command('copilot:chat', function () {
$config = new SessionConfig(
onPermissionRequest: function (array $request, array $invocation) {
$confirm = confirm(
label: 'Do you accept the requested permissions?',
);
if ($confirm) {
return PermissionRequestResultKind::approveOnce();
} else {
return PermissionRequestResultKind::reject();
}
},
);
Copilot::start(function (CopilotSession $session) use ($config) {
while (true) {
$prompt = text(
label: 'Enter your prompt',
placeholder: 'Ask me anything...',
required: true,
hint: 'Ctrl+C to exit',
);
$response = spin(
callback: fn () => $session->sendAndWait($prompt),
message: 'Waiting for Copilot response...',
);
note($response->content());
}
}, config: $config);
});
$request
Other than kind and toolCallId, fields vary by kind.
kind: "shell" | "write" | "mcp" | "read" | "url" | "custom-tool" | "memory" | "hook"
[
"kind" => "shell",
"toolCallId" => "toolu_...",
"fullCommandText" => "...",
"intention" => "Run copilot:ping to test permission request",
"commands" => [
[
"identifier" => "bash",
"readOnly" => false,
]
]
"possiblePaths" => [],
"possibleUrls" => [],
"hasWriteFileRedirection" => false,
"canOfferSessionApproval" => false,
]
$invocation
[
"sessionId" => "...",
]
Response
Return an array for the permission decision.
Using the PermissionRequestResultKind class is convenient.
return PermissionRequestResultKind::approveOnce();
return PermissionRequestResultKind::reject();
Protocol details
In Protocol v3 (current default), permission requests are broadcast as session events (permission.requested) instead of JSON-RPC requests.
The SDK handles this internally and responds through the session.permissions.handlePendingPermissionRequest RPC.
How you use SessionConfig does not change.
You only need to pass a handler to onPermissionRequest, and the SDK absorbs protocol differences.
PermissionRequestResultKind
You can return the ['kind' => 'approve-once'] format directly, but it is easier to read with PermissionRequestResultKind.
use Revolution\Copilot\Support\PermissionRequestResultKind;
$confirm = confirm(
label: 'Do you accept the requested permissions?',
);
if ($confirm) {
return PermissionRequestResultKind::approveOnce();
} else {
return PermissionRequestResultKind::reject();
}
Available methods
| Method | Value | Description |
|---|
approveOnce() | approve-once | Approve this request only |
approveForSession() | approve-for-session | Approve all requests of the same type for this session |
approveForLocation() | approve-for-location | Approve all requests of the same type from this location (file path, etc.) |
reject() | reject | Reject the request |
userNotAvailable() | user-not-available | User cannot respond (non-interactive environment, etc.) |
noResult() | no-result | Handler cannot return a result (skip RPC call) |
If you prefer Laravel\Prompts\select over Laravel\Prompts\confirm, use PermissionRequestResultKind::select() for options.
use Revolution\Copilot\Support\PermissionRequestResultKind;
use function Laravel\Prompts\select;
$select = select(
label: 'Do you accept the requested permissions?',
options: PermissionRequestResultKind::select(),
);
return ['kind' => $select];
no-result
If a handler cannot return a result (for example, in a non-interactive environment), you can return no-result.
When no-result is returned, the RPC call is skipped and Copilot CLI applies its default deny behavior.
return PermissionRequestResultKind::noResult();
// or ['kind' => 'no-result']