Klein Kit

Permissions

Approval modes and the permission round-trip

Modes

type PermissionMode = "read-only" | "ask" | "accept-edits" | "full-auto";
ModeMeaning
read-onlyThe agent may not change anything. Without a handler, requests are auto-denied.
askPrivileged actions surface as permission requests.
accept-editsFile edits auto-approved; shell and other privileged actions still ask.
full-autoMaps to each backend's bypass mode (Claude bypassPermissions, Codex approval_policy: never). Only expose in trusted contexts.

Default: "ask" when you pass onPermissionRequest, otherwise "accept-edits".

The round-trip

const session = await createAgent({
  provider: "claude",
  permissionMode: "ask",
  onPermissionRequest: async (req) => {
    // req: { id, kind, title, command?, cwd?, changes?, raw? }
    if (req.kind === "shell") {
      const ok = await myUi.confirm(`Run: ${req.command}?`);
      return { behavior: ok ? "allow" : "deny", scope: "once" };
    }
    return { behavior: "allow" };
  },
});
type PermissionKind = "shell" | "file_edit" | "file_read" | "network" | "mcp" | "other";

interface PermissionRequest {
  id: string;
  kind: PermissionKind;
  title: string;
  command?: string;        // for shell
  cwd?: string;
  changes?: FileChange[];  // for file edits
  raw?: unknown;           // the native payload
}

interface PermissionResponse {
  behavior: "allow" | "deny";
  scope?: "once" | "session";
  message?: string;        // shown to the agent on deny
  updatedInput?: unknown;  // rewrite the action before allowing
}

Without a handler

Requests surface as permission.requested events and stay pending until you call session.respond(requestId, response) — useful when approval happens in a different part of your app (IPC, HTTP, a UI thread). In read-only mode they auto-deny.

session.on("permission.requested", ({ request }) => {
  showApprovalDialog(request); // later: session.respond(request.id, { behavior: "allow" })
});

Every resolution — yours or automatic — emits permission.resolved.

Per-provider notes

  • codexask inherits Codex's sandbox semantics: in-workspace file edits are auto-approved natively and never reach your handler; shell commands outside the sandbox do.
  • claude — full native round-trip, including deny messages and mid-session mode changes.
  • opencode — mapped to opencode's permission config (bash/edit ask/allow/deny) and answered over its HTTP API.
  • pi — Pi has no approval protocol, so Klein Kit injects a permission-gate extension into the Pi process that blocks tool calls and asks through RPC. Reads always auto-allow.
  • cursor — no approval protocol in print mode; respond() throws CapabilityUnsupportedError. read-only is best-effort, not a security boundary.

Check session.capabilities.permissionCallback ("native" | "emulated" | "none") before relying on the round-trip. See Providers for the full matrix.

On this page