feat: add exec host approvals flow
This commit is contained in:
251
docs/refactor/exec-host.md
Normal file
251
docs/refactor/exec-host.md
Normal file
@@ -0,0 +1,251 @@
|
||||
---
|
||||
summary: "Refactor plan: exec host routing, node approvals, and headless runner"
|
||||
read_when:
|
||||
- Designing exec host routing or exec approvals
|
||||
- Implementing node runner + UI IPC
|
||||
- Adding exec host security modes and slash commands
|
||||
---
|
||||
|
||||
# Exec host refactor plan
|
||||
|
||||
## Goals
|
||||
- Add `exec.host` + `exec.security` to route execution across **sandbox**, **gateway**, and **node**.
|
||||
- Keep defaults **safe**: no cross-host execution unless explicitly enabled.
|
||||
- Split execution into a **headless runner service** with optional UI (macOS app) via local IPC.
|
||||
- Provide **per-agent** policy, allowlist, ask mode, and node binding.
|
||||
- Support **ask modes** that work *with* or *without* allowlists.
|
||||
- Cross-platform: Unix socket + token auth (macOS/Linux/Windows parity).
|
||||
|
||||
## Non-goals
|
||||
- No legacy allowlist migration or legacy schema support.
|
||||
- No PTY/streaming for node exec (aggregated output only).
|
||||
- No new network layer beyond the existing Bridge + Gateway.
|
||||
|
||||
## Decisions (locked)
|
||||
- **Config keys:** `exec.host` + `exec.security` (per-agent override allowed).
|
||||
- **Elevation:** keep `/elevated` as an alias for gateway full access.
|
||||
- **Ask default:** `on-miss`.
|
||||
- **Approvals store:** `~/.clawdbot/exec-approvals.json` (JSON, no legacy migration).
|
||||
- **Runner:** headless system service; UI app hosts a Unix socket for approvals.
|
||||
- **Node identity:** use existing `nodeId`.
|
||||
- **Socket auth:** Unix socket + token (cross-platform); split later if needed.
|
||||
|
||||
## Key concepts
|
||||
### Host
|
||||
- `sandbox`: Docker exec (current behavior).
|
||||
- `gateway`: exec on gateway host.
|
||||
- `node`: exec on node runner via Bridge (`system.run`).
|
||||
|
||||
### Security mode
|
||||
- `deny`: always block.
|
||||
- `allowlist`: allow only matches.
|
||||
- `full`: allow everything (equivalent to elevated).
|
||||
|
||||
### Ask mode
|
||||
- `off`: never ask.
|
||||
- `on-miss`: ask only when allowlist does not match.
|
||||
- `always`: ask every time.
|
||||
|
||||
Ask is **independent** of allowlist; allowlist can be used with `always` or `on-miss`.
|
||||
|
||||
### Policy resolution (per exec)
|
||||
1) Resolve `exec.host` (tool param → agent override → global default).
|
||||
2) Resolve `exec.security` and `exec.ask` (same precedence).
|
||||
3) If host is `sandbox`, proceed with local sandbox exec.
|
||||
4) If host is `gateway` or `node`, apply security + ask policy on that host.
|
||||
|
||||
## Default safety
|
||||
- Default `exec.host = sandbox`.
|
||||
- Default `exec.security = deny` for `gateway` and `node`.
|
||||
- Default `exec.ask = on-miss` (only relevant if security allows).
|
||||
- If no node binding is set, **agent may target any node**, but only if policy allows it.
|
||||
|
||||
## Config surface
|
||||
### Tool parameters
|
||||
- `exec.host` (optional): `sandbox | gateway | node`.
|
||||
- `exec.security` (optional): `deny | allowlist | full`.
|
||||
- `exec.ask` (optional): `off | on-miss | always`.
|
||||
- `exec.node` (optional): node id/name to use when `host=node`.
|
||||
|
||||
### Config keys (global)
|
||||
- `tools.exec.host`
|
||||
- `tools.exec.security`
|
||||
- `tools.exec.ask`
|
||||
- `tools.exec.node` (default node binding)
|
||||
|
||||
### Config keys (per agent)
|
||||
- `agents.list[].tools.exec.host`
|
||||
- `agents.list[].tools.exec.security`
|
||||
- `agents.list[].tools.exec.ask`
|
||||
- `agents.list[].tools.exec.node`
|
||||
|
||||
### Alias
|
||||
- `/elevated on` = set `tools.exec.host=gateway`, `tools.exec.security=full` for the agent session.
|
||||
- `/elevated off` = restore previous exec settings for the agent session.
|
||||
|
||||
## Approvals store (JSON)
|
||||
Path: `~/.clawdbot/exec-approvals.json`
|
||||
|
||||
Purpose:
|
||||
- Local policy + allowlists for the **execution host** (gateway or node runner).
|
||||
- Ask fallback when no UI is available.
|
||||
- IPC credentials for UI clients.
|
||||
|
||||
Proposed schema (v1):
|
||||
```json
|
||||
{
|
||||
"version": 1,
|
||||
"socket": {
|
||||
"path": "~/.clawdbot/exec-approvals.sock",
|
||||
"token": "base64-opaque-token"
|
||||
},
|
||||
"defaults": {
|
||||
"security": "deny",
|
||||
"ask": "on-miss",
|
||||
"askFallback": "deny"
|
||||
},
|
||||
"agents": {
|
||||
"agent-id-1": {
|
||||
"security": "allowlist",
|
||||
"ask": "on-miss",
|
||||
"allowlist": [
|
||||
{
|
||||
"pattern": "~/Projects/**/bin/rg",
|
||||
"lastUsedAt": 0,
|
||||
"lastUsedCommand": "rg -n TODO",
|
||||
"lastResolvedPath": "/Users/user/Projects/.../bin/rg"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
Notes:
|
||||
- No legacy allowlist formats.
|
||||
- `askFallback` applies only when `ask` is required and no UI is reachable.
|
||||
- File permissions: `0600`.
|
||||
|
||||
## Runner service (headless)
|
||||
### Role
|
||||
- Enforce `exec.security` + `exec.ask` locally.
|
||||
- Execute system commands and return output.
|
||||
- Emit Bridge events for exec lifecycle (optional but recommended).
|
||||
|
||||
### Service lifecycle
|
||||
- Launchd/daemon on macOS; system service on Linux/Windows.
|
||||
- Approvals JSON is local to the execution host.
|
||||
- UI hosts a local Unix socket; runners connect on demand.
|
||||
|
||||
## UI integration (macOS app)
|
||||
### IPC
|
||||
- Unix socket at `~/.clawdbot/exec-approvals.sock`.
|
||||
- Runner connects and sends an approval request; UI responds with a decision.
|
||||
- Token stored in `exec-approvals.json`.
|
||||
|
||||
### Ask flow
|
||||
1) Runner receives `system.run` from gateway.
|
||||
2) If ask required, runner connects to the socket and sends a prompt request.
|
||||
3) UI shows dialog; returns decision.
|
||||
4) Runner enforces decision and proceeds.
|
||||
|
||||
If UI missing:
|
||||
- Apply `askFallback` (`deny|allowlist|full`).
|
||||
|
||||
## Node identity + binding
|
||||
- Use existing `nodeId` from Bridge pairing.
|
||||
- Binding model:
|
||||
- `tools.exec.node` restricts the agent to a specific node.
|
||||
- If unset, agent can pick any node (policy still enforces defaults).
|
||||
- Node selection resolution:
|
||||
- `nodeId` exact match
|
||||
- `displayName` (normalized)
|
||||
- `remoteIp`
|
||||
- `nodeId` prefix (>= 6 chars)
|
||||
|
||||
## Eventing
|
||||
### Who sees events
|
||||
- System events are **per session** and shown to the agent on the next prompt.
|
||||
- Stored in the gateway in-memory queue (`enqueueSystemEvent`).
|
||||
|
||||
### Event text
|
||||
- `Exec started (host=node, node=<id>, id=<runId>)`
|
||||
- `Exec finished (exit=<code>, tail=<...>)`
|
||||
- `Exec denied (policy=<...>, reason=<...>)`
|
||||
|
||||
### Transport
|
||||
Option A (recommended):
|
||||
- Runner sends Bridge `event` frames `exec.started` / `exec.finished`.
|
||||
- Gateway `handleBridgeEvent` maps these into `enqueueSystemEvent`.
|
||||
|
||||
Option B:
|
||||
- Gateway `exec` tool handles lifecycle directly (synchronous only).
|
||||
|
||||
## Exec flows
|
||||
### Sandbox host
|
||||
- Existing `exec` behavior (Docker or host when unsandboxed).
|
||||
- PTY supported in non-sandbox mode only.
|
||||
|
||||
### Gateway host
|
||||
- Gateway process executes on its own machine.
|
||||
- Enforces local `exec-approvals.json` (security/ask/allowlist).
|
||||
|
||||
### Node host
|
||||
- Gateway calls `node.invoke` with `system.run`.
|
||||
- Runner enforces local approvals.
|
||||
- Runner returns aggregated stdout/stderr.
|
||||
- Optional Bridge events for start/finish/deny.
|
||||
|
||||
## Output caps
|
||||
- Cap combined stdout+stderr at **200k**; keep **tail 20k** for events.
|
||||
- Truncate with a clear suffix (e.g., `"… (truncated)"`).
|
||||
|
||||
## Slash commands
|
||||
- `/exec host=<sandbox|gateway|node> security=<deny|allowlist|full> ask=<off|on-miss|always> node=<id>`
|
||||
- Per-agent, per-session overrides; non-persistent unless saved via config.
|
||||
- `/elevated on|off` remains a shortcut for `host=gateway security=full`.
|
||||
|
||||
## Cross-platform story
|
||||
- The runner service is the portable execution target.
|
||||
- UI is optional; if missing, `askFallback` applies.
|
||||
- Windows/Linux support the same approvals JSON + socket protocol.
|
||||
|
||||
## Implementation phases
|
||||
### Phase 1: config + exec routing
|
||||
- Add config schema for `exec.host`, `exec.security`, `exec.ask`, `exec.node`.
|
||||
- Update tool plumbing to respect `exec.host`.
|
||||
- Add `/exec` slash command and keep `/elevated` alias.
|
||||
|
||||
### Phase 2: approvals store + gateway enforcement
|
||||
- Implement `exec-approvals.json` reader/writer.
|
||||
- Enforce allowlist + ask modes for `gateway` host.
|
||||
- Add output caps.
|
||||
|
||||
### Phase 3: node runner enforcement
|
||||
- Update node runner to enforce allowlist + ask.
|
||||
- Add Unix socket prompt bridge to macOS app UI.
|
||||
- Wire `askFallback`.
|
||||
|
||||
### Phase 4: events
|
||||
- Add node → gateway Bridge events for exec lifecycle.
|
||||
- Map to `enqueueSystemEvent` for agent prompts.
|
||||
|
||||
### Phase 5: UI polish
|
||||
- Mac app: allowlist editor, per-agent switcher, ask policy UI.
|
||||
- Node binding controls (optional).
|
||||
|
||||
## Testing plan
|
||||
- Unit tests: allowlist matching (glob + case-insensitive).
|
||||
- Unit tests: policy resolution precedence (tool param → agent override → global).
|
||||
- Integration tests: node runner deny/allow/ask flows.
|
||||
- Bridge event tests: node event → system event routing.
|
||||
|
||||
## Open risks
|
||||
- UI unavailability: ensure `askFallback` is respected.
|
||||
- Long-running commands: rely on timeout + output caps.
|
||||
- Multi-node ambiguity: error unless node binding or explicit node param.
|
||||
|
||||
## Related docs
|
||||
- [Exec tool](/tools/exec)
|
||||
- [Exec approvals](/tools/exec-approvals)
|
||||
- [Nodes](/nodes)
|
||||
- [Elevated mode](/tools/elevated)
|
||||
@@ -6,9 +6,8 @@ read_when:
|
||||
# Elevated Mode (/elevated directives)
|
||||
|
||||
## What it does
|
||||
- Elevated mode allows the exec tool to run with elevated privileges when the feature is available and the sender is approved.
|
||||
- The bash chat command (`!`; `/bash` alias) uses the same `tools.elevated` allowlists because it always runs on the host.
|
||||
- **Optional for sandboxed agents**: elevated only changes behavior when the agent is running in a sandbox. If the agent already runs unsandboxed, elevated is effectively a no-op.
|
||||
- `/elevated on` is a **shortcut** for `exec.host=gateway` + `exec.security=full`.
|
||||
- Only changes behavior when the agent is **sandboxed** (otherwise exec already runs on the host).
|
||||
- Directive forms: `/elevated on`, `/elevated off`, `/elev on`, `/elev off`.
|
||||
- Only `on|off` are accepted; anything else returns a hint and does not change state.
|
||||
|
||||
@@ -17,18 +16,9 @@ read_when:
|
||||
- **Per-session state**: `/elevated on|off` sets the elevated level for the current session key.
|
||||
- **Inline directive**: `/elevated on` inside a message applies to that message only.
|
||||
- **Groups**: In group chats, elevated directives are only honored when the agent is mentioned. Command-only messages that bypass mention requirements are treated as mentioned.
|
||||
- **Host execution**: elevated runs `exec` on the host (bypasses sandbox).
|
||||
- **Unsandboxed agents**: when there is no sandbox to bypass, elevated does not change where `exec` runs.
|
||||
- **Host execution**: elevated forces `exec` onto the gateway host with full security.
|
||||
- **Unsandboxed agents**: no-op for location; only affects gating, logging, and status.
|
||||
- **Tool policy still applies**: if `exec` is denied by tool policy, elevated cannot be used.
|
||||
- **Not skill-scoped**: elevated cannot be limited to a specific skill; it only changes `exec` location.
|
||||
|
||||
Note:
|
||||
- Sandbox on: `/elevated on` runs that `exec` command on the host.
|
||||
- Sandbox off: `/elevated on` does not change execution (already on host).
|
||||
|
||||
## When elevated matters
|
||||
- Only impacts `exec` when the agent is running sandboxed (it drops the sandbox for that command).
|
||||
- For unsandboxed agents, elevated does not change execution; it only affects gating, logging, and status.
|
||||
|
||||
## Resolution order
|
||||
1. Inline directive on the message (applies only to that message).
|
||||
@@ -38,7 +28,7 @@ Note:
|
||||
## Setting a session default
|
||||
- Send a message that is **only** the directive (whitespace allowed), e.g. `/elevated on`.
|
||||
- Confirmation reply is sent (`Elevated mode enabled.` / `Elevated mode disabled.`).
|
||||
- If elevated access is disabled or the sender is not on the approved allowlist, the directive replies with an actionable error (runtime sandboxed/direct + failing config key paths) and does not change session state.
|
||||
- If elevated access is disabled or the sender is not on the approved allowlist, the directive replies with an actionable error and does not change session state.
|
||||
- Send `/elevated` (or `/elevated:`) with no argument to see the current elevated level.
|
||||
|
||||
## Availability + allowlists
|
||||
|
||||
@@ -1,39 +1,88 @@
|
||||
---
|
||||
summary: "Exec approvals, allowlists, and sandbox escape prompts in the macOS app"
|
||||
summary: "Exec approvals, allowlists, and sandbox escape prompts"
|
||||
read_when:
|
||||
- Configuring exec approvals or allowlists
|
||||
- Implementing exec approval UX in the macOS app
|
||||
- Reviewing sandbox escape prompts and implications
|
||||
---
|
||||
|
||||
# Exec approvals (macOS app)
|
||||
# Exec approvals
|
||||
|
||||
Exec approvals are the **macOS companion app** guardrail for running host
|
||||
commands from sandboxed agents. Think of it as a per-agent “run this on my Mac”
|
||||
approval layer: the agent asks, the app decides, and the command runs (or not).
|
||||
This is **in addition** to tool policy and elevated gating; all of those checks
|
||||
must pass before a command can run.
|
||||
Exec approvals are the **companion app guardrail** for letting a sandboxed agent run
|
||||
commands on a real host (`gateway` or `node`). Think of it like a safety interlock:
|
||||
commands are allowed only when policy + allowlist + (optional) user approval all agree.
|
||||
Exec approvals are **in addition** to tool policy and elevated gating.
|
||||
|
||||
If you are **not** running the macOS companion app, exec approvals are
|
||||
unavailable and `system.run` requests will be rejected with a message that a
|
||||
companion app is required.
|
||||
If the companion app UI is **not available**, any request that requires a prompt is
|
||||
resolved by the **ask fallback** (default: deny).
|
||||
|
||||
## Settings
|
||||
## Where it applies
|
||||
|
||||
In the macOS app, each agent has an **Exec approvals** setting:
|
||||
Exec approvals are enforced locally on the execution host:
|
||||
- **gateway host** → `clawdbot` process on the gateway machine
|
||||
- **node host** → node runner (macOS companion app or headless node)
|
||||
|
||||
- **Deny**: block all host exec requests from the agent.
|
||||
- **Always ask**: show a confirmation dialog for each host exec request.
|
||||
- **Always allow**: run host exec requests without prompting.
|
||||
## Settings and storage
|
||||
|
||||
Optional toggles:
|
||||
- **Auto-allow skill CLIs**: when enabled, CLIs referenced by known skills are
|
||||
treated as allowlisted (see below).
|
||||
Approvals live in a local JSON file:
|
||||
|
||||
`~/.clawdbot/exec-approvals.json`
|
||||
|
||||
Example schema:
|
||||
```json
|
||||
{
|
||||
"version": 1,
|
||||
"socket": {
|
||||
"path": "~/.clawdbot/exec-approvals.sock",
|
||||
"token": "base64url-token"
|
||||
},
|
||||
"defaults": {
|
||||
"security": "deny",
|
||||
"ask": "on-miss",
|
||||
"askFallback": "deny",
|
||||
"autoAllowSkills": false
|
||||
},
|
||||
"agents": {
|
||||
"main": {
|
||||
"security": "allowlist",
|
||||
"ask": "on-miss",
|
||||
"askFallback": "deny",
|
||||
"autoAllowSkills": true,
|
||||
"allowlist": [
|
||||
{
|
||||
"pattern": "~/Projects/**/bin/rg",
|
||||
"lastUsedAt": 1737150000000,
|
||||
"lastUsedCommand": "rg -n TODO",
|
||||
"lastResolvedPath": "/Users/user/Projects/.../bin/rg"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Policy knobs
|
||||
|
||||
### Security (`exec.security`)
|
||||
- **deny**: block all host exec requests.
|
||||
- **allowlist**: allow only allowlisted commands.
|
||||
- **full**: allow everything (equivalent to elevated).
|
||||
|
||||
### Ask (`exec.ask`)
|
||||
- **off**: never prompt.
|
||||
- **on-miss**: prompt only when allowlist does not match.
|
||||
- **always**: prompt on every command.
|
||||
|
||||
### Ask fallback (`askFallback`)
|
||||
If a prompt is required but no UI is reachable, fallback decides:
|
||||
- **deny**: block.
|
||||
- **allowlist**: allow only if allowlist matches.
|
||||
- **full**: allow.
|
||||
|
||||
## Allowlist (per agent)
|
||||
|
||||
The allowlist is **per agent**. If multiple agents exist, you can switch which
|
||||
agent’s allowlist you’re editing. Entries are path-based and support **globs**.
|
||||
Allowlists are **per agent**. If multiple agents exist, switch which agent you’re
|
||||
editing in the macOS app. Patterns are **case-insensitive glob matches**.
|
||||
|
||||
Examples:
|
||||
- `~/Projects/**/bin/bird`
|
||||
@@ -41,66 +90,44 @@ Examples:
|
||||
- `/opt/homebrew/bin/rg`
|
||||
|
||||
Each allowlist entry tracks:
|
||||
- **last used** (timestamp)
|
||||
- **last used** timestamp
|
||||
- **last used command**
|
||||
- **last used path** (resolved absolute path)
|
||||
- **last seen metadata** (hash/version/mtime when available)
|
||||
- **last resolved path**
|
||||
|
||||
## How matching works
|
||||
## Auto-allow skill CLIs
|
||||
|
||||
1) Parse the command to determine the executable (first token).
|
||||
2) Resolve the executable to an absolute path using `PATH`.
|
||||
3) Match against denylist (if present) → **deny**.
|
||||
4) Match against allowlist → **allow**.
|
||||
5) Otherwise follow the Exec approvals policy (deny/ask/allow).
|
||||
|
||||
If **auto-allow skill CLIs** is enabled, each installed skill can contribute one
|
||||
or more allowlist entries. A skill-based allowlist entry only auto-allows when:
|
||||
- the resolved path matches, and
|
||||
- the binary hash/version matches the last approved record (if tracked).
|
||||
|
||||
If the binary changes (new hash/version), the command falls back to **Ask** so
|
||||
the user can re-approve.
|
||||
When **Auto-allow skill CLIs** is enabled, executables referenced by known skills
|
||||
are treated as allowlisted (node hosts only). Disable this if you want strict
|
||||
manual allowlists.
|
||||
|
||||
## Approval flow
|
||||
|
||||
When the policy is **Always ask** (or when a binary has changed), the macOS app
|
||||
shows a confirmation dialog. The dialog should include:
|
||||
When a prompt is required, the companion app displays a confirmation dialog with:
|
||||
- command + args
|
||||
- cwd
|
||||
- environment overrides (diff)
|
||||
- policy + rule that matched (if any)
|
||||
- agent id
|
||||
- resolved executable path
|
||||
- host + policy metadata
|
||||
|
||||
Actions:
|
||||
- **Allow once** → run now
|
||||
- **Always allow** → add/update allowlist entry + run
|
||||
- **Always allow** → add to allowlist + run
|
||||
- **Deny** → block
|
||||
|
||||
When approved, the command runs **in the background** and the agent receives
|
||||
system events as it starts and completes.
|
||||
|
||||
## System events
|
||||
|
||||
The agent receives system messages for observability and recovery:
|
||||
Exec lifecycle is surfaced as system messages:
|
||||
- `exec.started`
|
||||
- `exec.finished`
|
||||
- `exec.denied`
|
||||
|
||||
- `exec.started` — command accepted and launched
|
||||
- `exec.finished` — command completed (exit code + output)
|
||||
- `exec.denied` — command blocked (policy or denylist)
|
||||
|
||||
These are **system messages**; no extra agent tool call is required to resume.
|
||||
These are posted to the agent’s session after the node reports the event.
|
||||
|
||||
## Implications
|
||||
|
||||
- **Always allow** is powerful: the agent can run any host command without a
|
||||
prompt. Prefer allowlisting trusted CLIs instead.
|
||||
- **Ask** keeps you in the loop while still allowing fast approvals.
|
||||
- Per-agent allowlists prevent one agent’s approval set from leaking into others.
|
||||
|
||||
## Storage
|
||||
|
||||
Allowlists and approval settings are stored **locally in the macOS app** (SQLite
|
||||
is a good fit). The Markdown docs describe behavior; they are not the storage
|
||||
mechanism.
|
||||
- **full** is powerful; prefer allowlists when possible.
|
||||
- **ask** keeps you in the loop while still allowing fast approvals.
|
||||
- Per-agent allowlists prevent one agent’s approvals from leaking into others.
|
||||
|
||||
Related:
|
||||
- [Exec tool](/tools/exec)
|
||||
|
||||
@@ -14,21 +14,36 @@ Background sessions are scoped per agent; `process` only sees sessions from the
|
||||
## Parameters
|
||||
|
||||
- `command` (required)
|
||||
- `workdir` (defaults to cwd)
|
||||
- `env` (key/value overrides)
|
||||
- `yieldMs` (default 10000): auto-background after delay
|
||||
- `background` (bool): background immediately
|
||||
- `timeout` (seconds, default 1800): kill on expiry
|
||||
- `pty` (bool): run in a pseudo-terminal when available (TTY-only CLIs, coding agents, terminal UIs)
|
||||
- `elevated` (bool): run on host if elevated mode is enabled/allowed (only changes behavior when the agent is sandboxed)
|
||||
- Need a fully interactive session? Use `pty: true` and the `process` tool for stdin/output.
|
||||
Note: `elevated` is ignored when sandboxing is off (exec already runs on the host).
|
||||
- `host` (`sandbox | gateway | node`): where to execute
|
||||
- `security` (`deny | allowlist | full`): enforcement mode for `gateway`/`node`
|
||||
- `ask` (`off | on-miss | always`): approval prompts for `gateway`/`node`
|
||||
- `node` (string): node id/name for `host=node`
|
||||
- `elevated` (bool): alias for `host=gateway` + `security=full` when sandboxed and allowed
|
||||
|
||||
Notes:
|
||||
- `host` defaults to `sandbox`.
|
||||
- `elevated` is ignored when sandboxing is off (exec already runs on the host).
|
||||
- `gateway`/`node` approvals are controlled by `~/.clawdbot/exec-approvals.json`.
|
||||
- `node` requires a paired node (macOS companion app).
|
||||
- If multiple nodes are available, set `exec.node` or `tools.exec.node` to select one.
|
||||
|
||||
## Config
|
||||
|
||||
- `tools.exec.notifyOnExit` (default: true): when true, backgrounded exec sessions enqueue a system event and request a heartbeat on exit.
|
||||
- `tools.exec.host` (default: `sandbox`)
|
||||
- `tools.exec.security` (default: `deny`)
|
||||
- `tools.exec.ask` (default: `on-miss`)
|
||||
- `tools.exec.node` (default: unset)
|
||||
|
||||
## Exec approvals (macOS app)
|
||||
|
||||
Sandboxed agents can require per-request approval before `exec` runs on the host.
|
||||
Sandboxed agents can require per-request approval before `exec` runs on the gateway or node host.
|
||||
See [Exec approvals](/tools/exec-approvals) for the policy, allowlist, and UI flow.
|
||||
|
||||
## Examples
|
||||
|
||||
@@ -169,15 +169,19 @@ Core parameters:
|
||||
- `background` (immediate background)
|
||||
- `timeout` (seconds; kills the process if exceeded, default 1800)
|
||||
- `elevated` (bool; run on host if elevated mode is enabled/allowed; only changes behavior when the agent is sandboxed)
|
||||
- `host` (`sandbox | gateway | node`)
|
||||
- `security` (`deny | allowlist | full`)
|
||||
- `ask` (`off | on-miss | always`)
|
||||
- `node` (node id/name for `host=node`)
|
||||
- Need a real TTY? Set `pty: true`.
|
||||
|
||||
Notes:
|
||||
- Returns `status: "running"` with a `sessionId` when backgrounded.
|
||||
- Use `process` to poll/log/write/kill/clear background sessions.
|
||||
- If `process` is disallowed, `exec` runs synchronously and ignores `yieldMs`/`background`.
|
||||
- `elevated` is gated by `tools.elevated` plus any `agents.list[].tools.elevated` override (both must allow) and runs on the host.
|
||||
- `elevated` is gated by `tools.elevated` plus any `agents.list[].tools.elevated` override (both must allow) and is an alias for `host=gateway` + `security=full`.
|
||||
- `elevated` only changes behavior when the agent is sandboxed (otherwise it’s a no-op).
|
||||
- macOS app approvals/allowlists: [Exec approvals](/tools/exec-approvals).
|
||||
- gateway/node approvals and allowlists: [Exec approvals](/tools/exec-approvals).
|
||||
|
||||
### `process`
|
||||
Manage background exec sessions.
|
||||
|
||||
Reference in New Issue
Block a user