Skip to content

Commit db7950e

Browse files
committed
docs: Approver + WebSocket approval protocol documentation
SECURITY.md: unified Approver table, Web UI modal docs, non-interactive note WEBUI.md: approval_request/approval_response WebSocket events + client messages DEVELOPMENT.md: approver.go + wsapprover.go in source layout
1 parent a4bf52a commit db7950e

3 files changed

Lines changed: 26 additions & 4 deletions

File tree

docs/DEVELOPMENT.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ internal/
4343
danger/
4444
classifier.go Command/URL classification for security gating
4545
classifier_test.go 209 tests, 8 risk classes, config overrides
46+
approver.go Approver interface + TTYApprover (CLI /dev/tty)
4647
memory/
4748
memory.go MemoryManager orchestrator (facts, buffer, episodes)
4849
facts.go FactStore with caps, dedup, substring CRUD
@@ -71,6 +72,7 @@ cmd/kode/
7172
serve.go Web UI server (HTTP + WebSocket)
7273
subagent.go Sub-agent command (--goal, --context, --task, JSON stdout)
7374
subagent_tool.go delegate_tasks built-in tool
75+
wsapprover.go WSApprover — WebSocket-based approval for serve mode
7476
subagent_test.go Tests (flag parsing, JSON stdout, exit codes, tool schema)
7577
subagent_contract_test.go Contract tests (flag parsing, stdout protocol, exit codes)
7678
subagent_e2e_test.go E2E tests (16 — KODE_E2E=true, real subprocess spawning)

docs/SECURITY.md

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,22 @@ API keys are read from environment variables or explicit config. kode never logs
6868

6969
## Dangerous Operations Approval
7070

71-
When running **without** `--sandbox`, kode's shell tool classifies every command by risk level and can prompt for user approval before executing high-risk operations.
71+
When running **without** `--sandbox`, kode's shell tool and native tools (read_file, write_file, browser, etc.) classify every operation by risk level and can prompt for user approval before executing high-risk operations.
7272

73-
### How it works
73+
The approval mechanism uses a unified **Approver** interface with two implementations:
74+
75+
| Mode | Approver | How it works |
76+
|------|----------|-------------|
77+
| **CLI** (`kode run`, `kode repl`) | `TTYApprover` | Opens `/dev/tty` — the same keypress-based prompt described below |
78+
| **Web UI** (`kode serve`) | `WSApprover` | Sends `approval_request` via WebSocket — the browser shows a modal with Approve / Deny / Trust buttons |
79+
80+
Both provide the **same three actions**: approve once, deny, or trust for the session. The experience is identical regardless of how you interact with kode.
81+
82+
### How it works (CLI mode)
7483

7584
1. The shell tool receives a command from the agent (JSON with `command` and optional `description`)
7685
2. The command is tokenized and classified into one of 8 risk classes (see [CLI.md](CLI.md#dangerous-operations))
77-
3. If the class is configured to `prompt` (default for system_write, network_egress, code_execution, install), the tool opens `/dev/tty` and shows:
86+
3. If the class is configured to `prompt` (default for system_write, network_egress, code_execution, install), the tool shows:
7887

7988
```
8089
⚠️ Risk: system_write
@@ -114,10 +123,12 @@ When you press `T`, the risk class is cached in memory for the lifetime of the k
114123

115124
### Non-interactive mode
116125

117-
When `/dev/tty` is not available (piped stdin, CI environments), the configured `non_interactive` action is used:
126+
When `/dev/tty` is not available (piped stdin, CI environments, or when no custom approver is configured), the configured `non_interactive` action is used:
118127
- `"allow"` (default) — run all commands without prompting
119128
- `"deny"` — block all prompted operations
120129

130+
> **Note:** In `kode serve` (Web UI) mode, this fallback is never hit — a WebSocket-based approver (`WSApprover`) is automatically injected, giving you interactive approval dialogs in the browser. The `non_interactive` setting only matters for CLI sessions without a TTY.
131+
121132
### Allowlist vs Denylist
122133

123134
- **Allowlist** entries (exact command match) bypass all checks — the command runs without prompt even if it would normally be denied

docs/WEBUI.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,19 @@ The UI communicates entirely over a single WebSocket at `/ws`. Messages are newl
7171
### Client → Server
7272

7373
```jsonc
74+
// Prompt — send a task to the agent
7475
{
7576
"type": "prompt",
7677
"content": "What files are in src/?",
7778
"session_id": "20260519-abc123" // optional — omit for new session
7879
}
80+
81+
// Approval response — answer a security prompt
82+
{
83+
"type": "approval_response",
84+
"id": "apr-a1b2c3d4",
85+
"action": "approve" // "approve" | "deny" | "trust"
86+
}
7987
```
8088

8189
### Server → Client
@@ -88,6 +96,7 @@ The UI communicates entirely over a single WebSocket at `/ws`. Messages are newl
8896
| `tool_result` | Tool returns output | `name`, `output` (truncated to 500 chars) |
8997
| `done` | Agent finishes | `latency` (seconds) |
9098
| `error` | Agent or server error | `message` |
99+
| `approval_request` | Agent needs user approval for dangerous operation | `id`, `risk` (class name), `command` (or resource), `description`, `is_operation` |
91100

92101
Example event sequence:
93102

0 commit comments

Comments
 (0)