Providers
Per-provider capabilities, quirks, and known limits
Capability matrix
"native" — the backend supports it directly. "emulated" — Klein Kit fills the gap. "none" — absent; check before building UI on it.
| Capability | codex | claude | opencode | cursor | pi |
|---|---|---|---|---|---|
| plans | native | emulated | none | none | none |
| todos | none | native | native | none | none |
| permissionCallback | native | native | native | none | emulated |
| permissionModes | native | native | native | emulated | emulated |
| resume | native | native | native | native | native |
| subagents | native | native | native | none | none |
| reasoningControls | native | native | native | none | native |
| usage | native | native | native | none | native |
| reasoningStream | native | native | native | none | native |
| interrupt | native | native | native | emulated | native |
| mcp | native | native | none | none | none |
| midSessionModelChange | native | native | none | emulated | native |
Codex
Spawns the codex binary as a JSON-RPC app server. Install: npm i -g @openai/codex.
- Auth is detected via
codex login status(ChatGPT login or API key). askinherits the sandbox: in-workspace file edits are auto-approved natively and never reach your permission handler; out-of-sandbox shell commands do.- Uniquely emits
turn.diff(cumulative working-tree diff) andlimits.updated(rate-limit windows). session.raw()returns the JSON-RPC connection.
Claude Code
Spawns the claude CLI in stream-json mode.
- Mode mapping:
read-only→ plan mode,ask→ default,accept-edits→ acceptEdits,full-auto→ bypassPermissions. detect()reportsauthenticated: undefinedon purpose — the reliable check would consume quota.providerOptions: { subscriptionAuth: true }strips API-key/routing env vars so the local/login(subscription) wins.- Full permission round-trip including deny messages.
OpenCode
Spawns opencode serve and talks HTTP + SSE.
- Models must be
"provider/model"form (e.g."anthropic/claude-sonnet-4-5"). mcpServersthrowsCapabilityUnsupportedError— configure MCP in opencode itself.- SSE reconnects can't replay missed frames; Klein Kit emits a
noticeand reconciles state. - End-to-end verification pending a configured model provider.
Cursor
Experimental — built against docs only, never run against the real binary. Do not use in production.
- One
agent -pprocess per turn; no approval protocol in print mode (respond()throws). read-onlyis best-effort (--mode ask), not a security boundary.setModel/setPermissionModeapply to the next turn.
Pi
Spawns pi --mode rpc. Install: @earendil-works/pi-coding-agent.
- Pi has no approval protocol, so Klein Kit injects a permission-gate extension that blocks tool calls and asks over RPC. Reads/searches always auto-allow;
accept-editsalso auto-allows edits. - Auth detected from
~/.pi/agent/auth.jsonor provider env keys. mcpServersproduce anoticewarning (not attached).
Windows
Windows is supported. Executable discovery honors PATHEXT; npm .cmd shims are read and their interpreter is run directly, so arguments stay byte-exact; .ps1 launchers run via PowerShell; process trees are cleaned up with taskkill. CI runs on windows-latest.
Notes:
- Termination on Windows is immediately forceful (
taskkill /F); the POSIX SIGTERM grace window doesn't apply. .ps1launchers usepowershell.exeunlessPOWERSHELL_EXEpoints atpwsh.- A shim that can't be modeled falls back to
cmd.exe, where arguments containing newlines (e.g. a multi-linesystemPrompt) are rejected rather than silently truncated.
Known limits (0.1)
full-automaps to each backend's bypass mode. Only expose it in trusted contexts.- Provider CLIs churn. Adapters emit anything unrecognized as
unknownevents rather than breaking, but pin the versions each adapter was built against: codex 0.146.0, claude 2.1.220, opencode 1.3.0, pi latest.