|
| 1 | +# Trust, Permission & Sandbox System — Design (Draft) |
| 2 | + |
| 3 | +**Date:** 2026-04-07 |
| 4 | +**Repos:** ratchet-cli + workflow-plugin-agent |
| 5 | +**Status:** Draft — needs refinement before implementation |
| 6 | + |
| 7 | +## Problem |
| 8 | + |
| 9 | +PTY agents (Claude Code, Copilot) require permission configuration to operate in orchestration mode. Currently, adapter args are hardcoded. Users need control over what agents can do, with sensible defaults and the ability to customize per-provider, per-agent, and per-project. |
| 10 | + |
| 11 | +## Existing Infrastructure (Reusable) |
| 12 | + |
| 13 | +| Component | Location | Status | |
| 14 | +|---|---|---| |
| 15 | +| ToolPolicyEngine (SQL, deny-wins, groups) | wpa/orchestrator/tool_policy.go | Production | |
| 16 | +| Registry.Execute gating | wpa/tools/types.go | Production | |
| 17 | +| ApprovalGate (channel blocking) | ratchet/daemon/approval_gate.go | Production | |
| 18 | +| Context propagation (AgentID/TeamID) | wpa/tools/context.go | Production | |
| 19 | +| Mesh tool allowlist | ratchet/mesh/local_node.go | Beta | |
| 20 | +| Path guard (prefix) | ratchet/mesh/local_node.go | Beta | |
| 21 | +| Config permissions (auto-allow/always-ask) | ratchet/config/config.go | Defined, not wired | |
| 22 | +| Hooks system | ratchet/hooks/hooks.go | Production | |
| 23 | + |
| 24 | +## Design |
| 25 | + |
| 26 | +### 1. Ratchet Operating Mode (CLI flag + config) |
| 27 | + |
| 28 | +```bash |
| 29 | +# CLI flag sets the mode for the session |
| 30 | +ratchet --mode conservative # default |
| 31 | +ratchet --mode permissive # auto-approve most actions |
| 32 | +ratchet --mode locked # deny all, queue everything for human |
| 33 | +ratchet --mode custom # load rules from config |
| 34 | + |
| 35 | +# Switch dynamically in TUI |
| 36 | +/mode permissive |
| 37 | +/mode conservative |
| 38 | +``` |
| 39 | + |
| 40 | +Mode maps to a set of trust rules. Modes are presets — `custom` loads explicit rules from config. |
| 41 | + |
| 42 | +### 2. Trust Rules Config (`~/.ratchet/config.yaml`) |
| 43 | + |
| 44 | +```yaml |
| 45 | +trust: |
| 46 | + mode: conservative # default mode |
| 47 | + |
| 48 | + # Rules: pattern → action |
| 49 | + # Patterns: exact, glob, regex (prefixed with ~) |
| 50 | + # Actions: allow, deny, ask (queue for human) |
| 51 | + rules: |
| 52 | + # Tool-level rules |
| 53 | + - pattern: "file_read" |
| 54 | + action: allow |
| 55 | + - pattern: "file_write" |
| 56 | + action: ask |
| 57 | + - pattern: "bash" |
| 58 | + action: ask |
| 59 | + - pattern: "bash:git *" # glob on command |
| 60 | + action: allow |
| 61 | + - pattern: "bash:rm -rf *" |
| 62 | + action: deny |
| 63 | + - pattern: "bash:docker *" |
| 64 | + action: ask |
| 65 | + |
| 66 | + # Path-level rules |
| 67 | + - pattern: "path:/tmp/*" |
| 68 | + action: allow |
| 69 | + - pattern: "path:/Users/*/workspace/*" |
| 70 | + action: allow |
| 71 | + - pattern: "path:/etc/*" |
| 72 | + action: deny |
| 73 | + - pattern: "path:~/.ssh/*" |
| 74 | + action: deny |
| 75 | + |
| 76 | + # Provider-level PTY args |
| 77 | + - pattern: "pty:claude_code" |
| 78 | + args: ["--permission-mode", "acceptEdits"] |
| 79 | + - pattern: "pty:copilot_cli" |
| 80 | + args: ["--allow-tool=Edit", "--allow-tool=Write"] |
| 81 | + |
| 82 | + # Preset modes (expand to rule sets) |
| 83 | + modes: |
| 84 | + conservative: |
| 85 | + auto_approve: [trust_dialogs, command_execution] |
| 86 | + require_human: [file_write, file_delete, destructive] |
| 87 | + deny: [network_unrestricted] |
| 88 | + permissive: |
| 89 | + auto_approve: [trust_dialogs, command_execution, file_write, file_read] |
| 90 | + require_human: [file_delete, destructive] |
| 91 | + deny: [] |
| 92 | + locked: |
| 93 | + auto_approve: [trust_dialogs] |
| 94 | + require_human: [everything_else] |
| 95 | + deny: [] |
| 96 | +``` |
| 97 | +
|
| 98 | +### 3. Per-Agent Override in Team Config |
| 99 | +
|
| 100 | +```yaml |
| 101 | +teams: |
| 102 | + - name: dev |
| 103 | + agents: |
| 104 | + - name: coder |
| 105 | + provider: claude_code |
| 106 | + args: ["--permission-mode", "bypassPermissions"] # override global |
| 107 | + trust: |
| 108 | + rules: |
| 109 | + - pattern: "bash:*" |
| 110 | + action: allow # this agent can run any command |
| 111 | + - name: reviewer |
| 112 | + provider: copilot_cli |
| 113 | + # inherits global trust rules + provider args |
| 114 | +``` |
| 115 | + |
| 116 | +### 4. Resolution Order |
| 117 | + |
| 118 | +``` |
| 119 | +per-agent trust rules |
| 120 | + → per-agent args |
| 121 | + → global provider_args (pty:provider_name) |
| 122 | + → ratchet trust rules |
| 123 | + → ratchet mode preset |
| 124 | + → ToolPolicyEngine (SQL, existing) |
| 125 | + → deny (default) |
| 126 | +``` |
| 127 | + |
| 128 | +First match wins. Deny always wins over allow at the same level. |
| 129 | + |
| 130 | +### 5. PTY Auto-Prompt Handler |
| 131 | + |
| 132 | +Screen pattern matching in the PTY session, driven by trust rules: |
| 133 | + |
| 134 | +```go |
| 135 | +type PromptPattern struct { |
| 136 | + Pattern string // regex or substring match on screen content |
| 137 | + Action string // "approve", "deny", "queue" |
| 138 | + Keys string // keystrokes to send (e.g., "y\r", "\r") |
| 139 | +} |
| 140 | +``` |
| 141 | + |
| 142 | +Built-in patterns: |
| 143 | +- Trust dialogs: "Trust this folder" → approve (Enter) |
| 144 | +- Command execution: "Run command?" / "Execute?" → check trust rules |
| 145 | +- File write: "Allow edit?" / "Write file?" → check trust rules |
| 146 | +- Unknown (screen stuck >30s) → queue for human |
| 147 | + |
| 148 | +When queued: |
| 149 | +1. Write to HumanGate pending queue |
| 150 | +2. Send OS notification |
| 151 | +3. Write to BB: `notifications/<team> = "agent X waiting for human approval"` |
| 152 | +4. Orchestrator sees the notification, knows to work on other tasks |
| 153 | + |
| 154 | +### 6. Push to Agent Plugin |
| 155 | + |
| 156 | +Move these to workflow-plugin-agent so all consumers benefit: |
| 157 | + |
| 158 | +| Component | Current Location | Target | |
| 159 | +|---|---|---| |
| 160 | +| Trust rule parsing/matching | New | wpa/policy/trust.go | |
| 161 | +| Path policy (glob, not just prefix) | ratchet/mesh | wpa/policy/path.go | |
| 162 | +| PTY prompt patterns | New | wpa/genkit/pty_prompts.go | |
| 163 | +| Permission persistence | Missing | wpa/policy/store.go (SQLite) | |
| 164 | + |
| 165 | +The agent plugin's ToolPolicyEngine extends to cover: |
| 166 | +- Tool policies (existing) |
| 167 | +- Path policies (new — glob matching) |
| 168 | +- Command policies (new — bash command patterns) |
| 169 | +- Resource policies (new — network, filesystem scope) |
| 170 | + |
| 171 | +### 7. Sandbox Mode |
| 172 | + |
| 173 | +```bash |
| 174 | +ratchet --sandbox # or --mode sandbox |
| 175 | +``` |
| 176 | + |
| 177 | +Sandbox mode: |
| 178 | +- All file operations restricted to project workdir |
| 179 | +- Network access denied by default |
| 180 | +- No access to ~/.ssh, ~/.aws, credentials |
| 181 | +- Bash commands run in a restricted shell (no sudo, no rm -rf /) |
| 182 | +- Future: WASM isolation for MCP servers (workflow-plugin-sandbox repo) |
| 183 | + |
| 184 | +### 8. Dynamic Mode Switching |
| 185 | + |
| 186 | +``` |
| 187 | +/mode permissive # switch mode in TUI |
| 188 | +/trust allow bash # add rule dynamically |
| 189 | +/trust deny "rm -rf" # add deny rule |
| 190 | +/trust list # show active rules |
| 191 | +``` |
| 192 | + |
| 193 | +For PTY providers, mode switch requires session restart: |
| 194 | +1. Save conversation state to Blackboard |
| 195 | +2. Kill PTY session |
| 196 | +3. Restart with new args |
| 197 | +4. Restore context via prompt injection |
| 198 | + |
| 199 | +## Implementation Phases |
| 200 | + |
| 201 | +Phase 1: Wire existing config permissions + persist "always" grants |
| 202 | +Phase 2: Trust rules config + mode presets + CLI flag |
| 203 | +Phase 3: PTY auto-prompt handler with pattern matching |
| 204 | +Phase 4: Push trust/path policy to agent plugin |
| 205 | +Phase 5: Per-agent overrides + dynamic mode switching |
| 206 | +Phase 6: Sandbox mode (restricted shell, path deny) |
| 207 | +Phase 7: WASM sandbox plugin (future, separate repo) |
0 commit comments