|
| 1 | +# External CLI Connectors |
| 2 | + |
| 3 | +External CLI connectors let OpenClaw.NET wrap official platform CLIs through a governed native tool named `external_cli`. The feature is disabled by default and is intentionally not a general-purpose shell. |
| 4 | + |
| 5 | +Official CLIs provide platform depth. OpenClaw.NET provides the runtime controls: named command allowlists, risk scoring, previews, approvals, redaction, timeouts, audit records, and runtime events. |
| 6 | + |
| 7 | +## Security Model |
| 8 | + |
| 9 | +External CLIs can operate under powerful user, bot, cloud, cluster, or payment identities. Treat mutating commands as high-risk. Use least privilege, dry-run previews, approvals, and audit logs. |
| 10 | + |
| 11 | +The connector does not accept arbitrary command strings. Agents call a configured connector and command name with named parameters: |
| 12 | + |
| 13 | +```json |
| 14 | +{ |
| 15 | + "action": "execute", |
| 16 | + "connector": "gh", |
| 17 | + "command": "issue_list", |
| 18 | + "parameters": { |
| 19 | + "repo": "clawdotnet/openclaw.net" |
| 20 | + } |
| 21 | +} |
| 22 | +``` |
| 23 | + |
| 24 | +The runtime expands configured argument templates directly into `ProcessStartInfo.ArgumentList`. It does not pass through a shell and it rejects missing or unknown parameters unless the specific command allows them. |
| 25 | + |
| 26 | +## Configuration |
| 27 | + |
| 28 | +`OpenClaw:ExternalCli:Enabled` must be true before the `external_cli` tool is registered. Each connector and each command must also be explicitly configured. |
| 29 | + |
| 30 | +```json |
| 31 | +{ |
| 32 | + "OpenClaw": { |
| 33 | + "ExternalCli": { |
| 34 | + "Enabled": true, |
| 35 | + "DefaultTimeoutSeconds": 60, |
| 36 | + "MaxStdoutBytes": 262144, |
| 37 | + "MaxStderrBytes": 65536, |
| 38 | + "RedactSecrets": true, |
| 39 | + "AllowFreeformCommands": false, |
| 40 | + "RequireApprovalForMutatingCommands": true, |
| 41 | + "Connectors": { |
| 42 | + "gh": { |
| 43 | + "Enabled": true, |
| 44 | + "DisplayName": "GitHub CLI", |
| 45 | + "Executable": "gh", |
| 46 | + "DefaultOutputFormat": "json", |
| 47 | + "StatusCommand": { |
| 48 | + "Args": [ "auth", "status" ], |
| 49 | + "TimeoutSeconds": 20 |
| 50 | + }, |
| 51 | + "VersionCommand": { |
| 52 | + "Args": [ "--version" ], |
| 53 | + "TimeoutSeconds": 10 |
| 54 | + }, |
| 55 | + "Commands": { |
| 56 | + "repo_view": { |
| 57 | + "Description": "View repository metadata", |
| 58 | + "ArgsTemplate": [ "repo", "view", "{{repo}}", "--json", "name,owner,description,url,isPrivate" ], |
| 59 | + "RiskLevel": "low", |
| 60 | + "ReadOnly": true, |
| 61 | + "StructuredOutput": "json", |
| 62 | + "Parameters": { |
| 63 | + "repo": { |
| 64 | + "Required": true, |
| 65 | + "Pattern": "^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$" |
| 66 | + } |
| 67 | + } |
| 68 | + }, |
| 69 | + "issue_create": { |
| 70 | + "Description": "Create a GitHub issue", |
| 71 | + "ArgsTemplate": [ "issue", "create", "--repo", "{{repo}}", "--title", "{{title}}", "--body", "{{body}}" ], |
| 72 | + "RiskLevel": "medium", |
| 73 | + "ReadOnly": false, |
| 74 | + "RequiresApproval": true, |
| 75 | + "StructuredOutput": "text", |
| 76 | + "Parameters": { |
| 77 | + "repo": { "Required": true }, |
| 78 | + "title": { "Required": true, "MaxLength": 200 }, |
| 79 | + "body": { "Required": true, "MaxLength": 16000 } |
| 80 | + } |
| 81 | + } |
| 82 | + } |
| 83 | + } |
| 84 | + } |
| 85 | + } |
| 86 | + } |
| 87 | +} |
| 88 | +``` |
| 89 | + |
| 90 | +Important defaults: |
| 91 | + |
| 92 | +- `Enabled=false`: no tool registration. |
| 93 | +- `AllowFreeformCommands=false`: raw commands are rejected. |
| 94 | +- `RequireApprovalForMutatingCommands=true`: non-read-only commands require approval unless policy is changed. |
| 95 | +- `RiskLevel=high`: always approval-required. |
| 96 | +- `ReadOnly=false`: treated as mutating. |
| 97 | + |
| 98 | +## Preview And Approval |
| 99 | + |
| 100 | +Use preview before execution: |
| 101 | + |
| 102 | +```bash |
| 103 | +openclaw external preview gh repo_view --param repo=clawdotnet/openclaw.net |
| 104 | +``` |
| 105 | + |
| 106 | +Preview returns: |
| 107 | + |
| 108 | +- resolved executable and argument list |
| 109 | +- redacted command-line preview |
| 110 | +- risk level |
| 111 | +- read-only or mutating classification |
| 112 | +- whether approval is required |
| 113 | +- output format |
| 114 | +- required identity or scopes, when configured |
| 115 | +- a stable approval fingerprint |
| 116 | + |
| 117 | +Preview does not execute the command unless `--dry-run` is supplied and the command has an explicit `DryRunArgsTemplate`. The runtime never guesses dry-run flags. |
| 118 | + |
| 119 | +Approval-required admin execution must include the matching preview fingerprint. The CLI does this when `--yes` is supplied after preview review: |
| 120 | + |
| 121 | +```bash |
| 122 | +openclaw external execute gh issue_create \ |
| 123 | + --param repo=clawdotnet/openclaw.net \ |
| 124 | + --param title="Example" \ |
| 125 | + --param body="Example body" \ |
| 126 | + --yes |
| 127 | +``` |
| 128 | + |
| 129 | +Agent tool calls use the existing OpenClaw tool approval path. If the command template, resolved args, or policy changes between approval and execution, execution is blocked by fingerprint mismatch. |
| 130 | + |
| 131 | +## Audit, Events, And Redaction |
| 132 | + |
| 133 | +External CLI execution writes an append-only audit record with: |
| 134 | + |
| 135 | +- connector and command |
| 136 | +- executable |
| 137 | +- redacted argument preview |
| 138 | +- argument and parameter hashes |
| 139 | +- actor, session, channel, and sender where available |
| 140 | +- approval fingerprint where available |
| 141 | +- exit code, duration, timeout flag |
| 142 | +- stdout and stderr truncation flags |
| 143 | +- risk level and working directory |
| 144 | + |
| 145 | +Runtime events are emitted for status checks, previews, dry-runs, execution, failures, timeouts, truncation, redaction, and policy blocks. Raw secrets are not stored in audit records. |
| 146 | + |
| 147 | +Redaction applies to argument previews, stdout, stderr, audit records, runtime events, and error messages. Add connector or command `RedactionRules` for platform-specific token formats. |
| 148 | + |
| 149 | +## Output Parsing |
| 150 | + |
| 151 | +Set `StructuredOutput` per command: |
| 152 | + |
| 153 | +- `json`: parse stdout as JSON and return parsed JSON alongside redacted stdout. |
| 154 | +- `ndjson`: parse newline-delimited JSON into a JSON array. |
| 155 | +- `csv`, `table`, `text`: returned as redacted text in the initial implementation. |
| 156 | + |
| 157 | +The connector does not inject global `--json` flags. Put output flags in each command template. |
| 158 | + |
| 159 | +## Conservative Presets |
| 160 | + |
| 161 | +Keep presets disabled by default and enable only the commands needed for the operator surface. |
| 162 | + |
| 163 | +### GitHub CLI |
| 164 | + |
| 165 | +Read-only examples: |
| 166 | + |
| 167 | +- `auth status` |
| 168 | +- `repo view` |
| 169 | +- `issue list` |
| 170 | +- `pr list` |
| 171 | +- `pr view` |
| 172 | +- `release list` |
| 173 | + |
| 174 | +Approval-required examples: |
| 175 | + |
| 176 | +- `issue create` |
| 177 | +- `issue comment` |
| 178 | +- `pr review` |
| 179 | +- `pr merge` |
| 180 | +- `release create` |
| 181 | + |
| 182 | +### Azure CLI |
| 183 | + |
| 184 | +Read-only examples: |
| 185 | + |
| 186 | +- `account show` |
| 187 | +- `group list` |
| 188 | +- `resource list` |
| 189 | +- `webapp list` |
| 190 | + |
| 191 | +Approval-required examples: |
| 192 | + |
| 193 | +- resource create, update, or delete |
| 194 | +- deployment create |
| 195 | +- role assignment changes |
| 196 | + |
| 197 | +### kubectl |
| 198 | + |
| 199 | +Read-only examples: |
| 200 | + |
| 201 | +- `config current-context` |
| 202 | +- `get pods -o json` |
| 203 | +- `get services -o json` |
| 204 | +- `get deployments -o json` |
| 205 | +- `describe` as text when approved by policy |
| 206 | + |
| 207 | +High-risk approval-required examples: |
| 208 | + |
| 209 | +- `apply` |
| 210 | +- `delete` |
| 211 | +- `scale` |
| 212 | +- `rollout restart` |
| 213 | +- `exec` |
| 214 | +- `port-forward` |
| 215 | + |
| 216 | +Logs can expose secrets and should be at least medium risk. |
| 217 | + |
| 218 | +### Stripe CLI |
| 219 | + |
| 220 | +Read-only examples: |
| 221 | + |
| 222 | +- listen status, if safe for your environment |
| 223 | +- fixtures/list, if applicable |
| 224 | +- customers/list, only with least-privilege credentials |
| 225 | + |
| 226 | +High-risk approval-required examples: |
| 227 | + |
| 228 | +- payment mutations |
| 229 | +- refunds |
| 230 | +- customer and subscription mutations |
| 231 | +- webhook trigger |
| 232 | +- event replay |
| 233 | + |
| 234 | +### Lark / Feishu CLI |
| 235 | + |
| 236 | +Read-only examples: |
| 237 | + |
| 238 | +- `auth status` |
| 239 | +- schema inspection |
| 240 | +- calendar agenda |
| 241 | +- docs search/read |
| 242 | +- sheets read |
| 243 | +- mail search/read |
| 244 | +- meeting minutes query |
| 245 | + |
| 246 | +Approval-required examples: |
| 247 | + |
| 248 | +- send messages |
| 249 | +- write docs |
| 250 | +- write sheets |
| 251 | +- send email |
| 252 | +- approve or reject workflows |
| 253 | +- create or update OKRs |
| 254 | +- raw API calls |
| 255 | + |
| 256 | +## Admin API |
| 257 | + |
| 258 | +The gateway exposes: |
| 259 | + |
| 260 | +- `GET /admin/external-cli/connectors` |
| 261 | +- `GET /admin/external-cli/connectors/{connector}` |
| 262 | +- `GET /admin/external-cli/connectors/{connector}/commands` |
| 263 | +- `POST /admin/external-cli/preview` |
| 264 | +- `POST /admin/external-cli/execute` |
| 265 | + |
| 266 | +POST endpoints require CSRF for browser-session auth. Execute requires operator role and matching approval metadata for approval-required commands. |
| 267 | + |
| 268 | +## CLI |
| 269 | + |
| 270 | +```bash |
| 271 | +openclaw external list |
| 272 | +openclaw external status gh |
| 273 | +openclaw external commands gh |
| 274 | +openclaw external preview gh repo_view --param repo=clawdotnet/openclaw.net |
| 275 | +openclaw external execute gh repo_view --param repo=clawdotnet/openclaw.net |
| 276 | +``` |
| 277 | + |
| 278 | +Use `--json` for machine-readable responses. |
0 commit comments