Merge branch 'main' into commands-list-clean

This commit is contained in:
Luke
2026-01-08 19:33:56 -05:00
committed by GitHub
216 changed files with 6174 additions and 2822 deletions

View File

@@ -1,21 +1,44 @@
---
summary: "Design notes for a direct `clawdbot agent` CLI subcommand without WhatsApp delivery"
summary: "Direct `clawdbot agent` CLI runs (with optional delivery)"
read_when:
- Adding or modifying the agent CLI entrypoint
---
# `clawdbot agent` (direct-to-agent invocation)
# `clawdbot agent` (direct agent runs)
`clawdbot agent` lets you talk to the **embedded** agent runtime directly (no chat send unless you opt in), while reusing the same session store and thinking/verbose persistence as inbound auto-replies.
`clawdbot agent` runs a single agent turn without needing an inbound chat message.
By default it goes **through the Gateway**; add `--local` to force the embedded
runtime on the current machine.
## Behavior
- Required: `--message <text>`
- Session selection:
- If `--session-id` is given, reuse it.
- Else if `--to <e164>` is given, derive the session key from `session.scope` (direct chats collapse to `main`, or `global` when scope is global).
- Runs the embedded Pi agent (configured via `agent`).
- Thinking/verbose:
- Flags `--thinking <off|minimal|low|medium|high>` and `--verbose <on|off>` persist into the session store.
- `--to <E.164>` derives the session key (normal direct-chat routing), **or**
- `--session-id <id>` reuses an existing session by id
- Runs the same embedded agent runtime as normal inbound replies.
- Thinking/verbose flags persist into the session store.
- Output:
- Default: prints text (and `MEDIA:<url>` lines) to stdout.
- `--json`: prints structured payloads + meta.
- Optional: `--deliver` sends the reply back to the selected provider (`whatsapp`, `telegram`, `discord`, `signal`, `imessage`).
- default: prints reply text (plus `MEDIA:<url>` lines)
- `--json`: prints structured payload + metadata
- Optional delivery back to a provider with `--deliver` + `--provider`.
If the Gateway is unreachable, the CLI **falls back** to the embedded local run.
## Examples
```bash
clawdbot agent --to +15555550123 --message "status update"
clawdbot agent --session-id 1234 --message "Summarize inbox" --thinking medium
clawdbot agent --to +15555550123 --message "Trace logs" --verbose on --json
clawdbot agent --to +15555550123 --message "Summon reply" --deliver
```
## Flags
- `--local`: run locally (requires provider keys in your shell)
- `--deliver`: send the reply to the chosen provider (requires `--to`)
- `--provider`: `whatsapp|telegram|discord|slack|signal|imessage` (default: `whatsapp`)
- `--thinking <off|minimal|low|medium|high>`: persist thinking level
- `--verbose <on|off>`: persist verbose level
- `--timeout <seconds>`: override agent timeout
- `--json`: output structured JSON

View File

@@ -17,8 +17,9 @@ Background sessions are scoped per agent; `process` only sees sessions from the
- `yieldMs` (default 10000): auto-background after delay
- `background` (bool): background immediately
- `timeout` (seconds, default 1800): kill on expiry
- `elevated` (bool): run on host if elevated mode is enabled/allowed
- `elevated` (bool): run on host if elevated mode is enabled/allowed (only changes behavior when the agent is sandboxed)
- Need a real TTY? Use the tmux skill.
Note: `elevated` is ignored when sandboxing is off (bash already runs on the host).
## Examples

View File

@@ -1,254 +1,142 @@
---
summary: "Spec: integrated browser control server + action commands"
summary: "Integrated browser control server + action commands"
read_when:
- Adding agent-controlled browser automation
- Debugging why clawd is interfering with your own Chrome
- Implementing browser settings + lifecycle in the macOS app
---
# Browser (integrated) — clawd-managed Chrome
# Browser (clawd-managed)
Status: draft spec · Date: 2025-12-20
Clawdbot can run a **dedicated Chrome/Chromium profile** that the agent controls.
It is isolated from your personal browser and is managed through a small local
control server.
Goal: give the **clawd** persona its own browser that is:
- Visually distinct (lobster-orange, profile labeled "clawd").
- Fully agent-manageable (start/stop, list tabs, focus/close tabs, open URLs, screenshot).
- Non-interfering with the user's own browser (separate profile + dedicated ports).
## What you get
This doc covers the macOS app/gateway side. It intentionally does not mandate
Playwright vs Puppeteer; the key is the **contract** and the **separation guarantees**.
- A separate browser profile named **clawd** (orange accent by default).
- Deterministic tab control (list/open/focus/close).
- Agent actions (click/type/drag/select), snapshots, screenshots, PDFs.
- Optional multi-profile support (`clawd`, `work`, `remote`, ...).
## User-facing settings
This browser is **not** your daily driver. It is a safe, isolated surface for
agent automation and verification.
Add a dedicated settings section (preferably under **Skills** or its own "Browser" tab):
## Quick start
- **Enable clawd browser** (`default: on`)
- When off: no browser is launched, and browser tools return "disabled".
- **Browser control URL** (`default: http://127.0.0.1:18791`)
- Interpreted as the base URL of the local/remote browser-control server.
- If the URL host is not loopback, Clawdbot must **not** attempt to launch a local
browser; it only connects.
- **CDP URL** (`default: controlUrl + 1`)
- Base URL for Chrome DevTools Protocol (e.g. `http://127.0.0.1:18792`).
- Set this to a non-loopback host to attach the local control server to a remote
Chrome/Chromium CDP endpoint (SSH/Tailscale tunnel recommended).
- If the CDP URL host is non-loopback, clawd does **not** auto-launch a local browser.
- If you tunnel a remote CDP to `localhost`, set **Attach to existing only** to
avoid accidentally launching a local browser.
- **Accent color** (`default: #FF4500`, "lobster-orange")
- Used to theme the clawd browser profile (best-effort) and to tint UI indicators
in Clawdbot.
```bash
clawdbot browser status
clawdbot browser start
clawdbot browser open https://example.com
clawdbot browser snapshot
```
Optional (advanced, can be hidden behind Debug initially):
- **Use headless browser** (`default: off`)
- **Attach to existing only** (`default: off`) — if on, never launch; only connect if
already running.
- **Browser executable path** (override, optional)
- **No sandbox** (`default: off`) — adds `--no-sandbox` + `--disable-setuid-sandbox`
If you get “Browser disabled, enable it in config (see below) and restart the
Gateway.
### Port convention
## Configuration
Clawdbot already uses:
- Gateway WebSocket: `18789`
- Bridge (voice/node): `18790`
Browser settings live in `~/.clawdbot/clawdbot.json`.
For the clawd browser-control server, use "family" ports:
- Browser control HTTP API: `18791` (bridge + 1)
- Browser CDP/debugging port: `18792` (control + 1)
- Canvas host HTTP: `18793` by default, mounted at `/__clawdbot__/canvas/`
The user usually only configures the **control URL** (port `18791`). CDP is an
internal detail.
## Browser isolation guarantees (non-negotiable)
1) **Dedicated user data dir**
- Never attach to or reuse the user's default Chrome profile.
- Store clawd browser state under an app-owned directory, e.g.:
- `~/Library/Application Support/Clawdbot/browser/clawd/` (mac app)
- or `~/.clawdbot/browser/clawd/` (gateway/CLI)
2) **Dedicated ports**
- Never use `9222` (reserved for ad-hoc dev workflows; avoids colliding with
`agent-tools/browser-tools`).
- Default ports are `18791/18792` unless overridden.
3) **Named tab/page management**
- The agent must be able to enumerate and target tabs deterministically (by
stable `targetId` or equivalent), not "last tab".
## Browser selection (macOS + Linux)
On startup (when enabled + local URL), Clawdbot chooses the browser executable
in this order:
1) **Google Chrome Canary** (if installed)
2) **Chromium** (if installed)
3) **Google Chrome** (fallback)
Linux:
- Looks for `google-chrome` / `chromium` in common system paths.
- Use **Browser executable path** to force a specific binary.
Implementation detail:
- macOS: detection is by existence of the `.app` bundle under `/Applications`
(and optionally `~/Applications`), then using the resolved executable path.
- Linux: common `/usr/bin`/`/snap/bin` paths.
Rationale:
- Canary/Chromium are easy to visually distinguish from the user's daily driver.
- Chrome fallback ensures the feature works on a stock machine.
## Visual differentiation ("lobster-orange")
The clawd browser should be obviously different at a glance:
- Profile name: **clawd**
- Profile color: **#FF4500**
Preferred behavior:
- Seed/patch the profile's preferences on first launch so the color + name persist.
Fallback behavior:
- If preferences patching is not reliable, open with the dedicated profile and let
the user set the profile color/name once via Chrome UI; it must persist because
the `userDataDir` is persistent.
## Control server contract (vNext)
Expose a small local HTTP API (and/or gateway RPC surface) so the agent can manage
state without touching the user's Chrome.
Basics:
- `GET /` status payload (enabled/running/pid/cdpPort/etc)
- `POST /start` start browser
- `POST /stop` stop browser
- `GET /tabs` list tabs
- `POST /tabs/open` open a new tab
- `POST /tabs/focus` focus a tab by id/prefix
- `DELETE /tabs/:targetId` close a tab by id/prefix
Inspection:
- `POST /screenshot` `{ targetId?, fullPage?, ref?, element?, type? }`
- `GET /snapshot` `?format=aria|ai&targetId?&limit?`
- `GET /console` `?level?&targetId?`
- `POST /pdf` `{ targetId? }`
Actions:
- `POST /navigate`
- `POST /act` `{ kind, targetId?, ... }` where `kind` is one of:
- `click`, `type`, `press`, `hover`, `drag`, `select`, `fill`, `wait`, `resize`, `close`, `evaluate`
Hooks (arming):
- `POST /hooks/file-chooser` `{ targetId?, paths, timeoutMs? }`
- `POST /hooks/dialog` `{ targetId?, accept, promptText?, timeoutMs? }`
### "Is it open or closed?"
"Open" means:
- the control server is reachable at the configured URL **and**
- it reports a live browser connection.
"Closed" means:
- control server not reachable, or server reports no browser.
Clawdbot should treat "open/closed" as a health check (fast path), not by scanning
global Chrome processes (avoid false positives).
## Multi-profile support
Clawdbot supports multiple named browser profiles, each with:
- Dedicated CDP port (auto-allocated from 18800-18899) **or** a per-profile CDP URL
- Persistent user data directory (`~/.clawdbot/browser/<name>/user-data/`)
- Unique color for visual distinction
### Configuration
```json
```json5
{
"browser": {
"enabled": true,
"defaultProfile": "clawd",
"profiles": {
"clawd": { "cdpPort": 18800, "color": "#FF4500" },
"work": { "cdpPort": 18801, "color": "#0066CC" },
"remote": { "cdpUrl": "http://10.0.0.42:9222", "color": "#00AA00" }
browser: {
enabled: true, // default: true
controlUrl: "http://127.0.0.1:18791",
cdpUrl: "http://127.0.0.1:18792", // defaults to controlUrl + 1
defaultProfile: "clawd",
color: "#FF4500",
headless: false,
noSandbox: false,
attachOnly: false,
executablePath: "/Applications/Chromium.app/Contents/MacOS/Chromium",
profiles: {
clawd: { cdpPort: 18800, color: "#FF4500" },
work: { cdpPort: 18801, color: "#0066CC" },
remote: { cdpUrl: "http://10.0.0.42:9222", color: "#00AA00" }
}
}
}
```
### Profile actions
Notes:
- `controlUrl` defaults to `http://127.0.0.1:18791`.
- If you override the Gateway port (`gateway.port` or `CLAWDBOT_GATEWAY_PORT`),
the default browser ports shift to stay in the same “family” (control = gateway + 2).
- `cdpUrl` defaults to `controlUrl + 1` when unset.
- `attachOnly: true` means “never launch Chrome; only attach if it is already running.”
- `GET /profiles` — list all profiles with status
- `POST /profiles/create` `{ name, color?, cdpUrl? }` — create new profile (auto-allocates port if no `cdpUrl`)
- `DELETE /profiles/:name` — delete profile (stops browser + removes user data for local profiles)
- `POST /reset-profile?profile=<name>` — kill orphan process on profile's port (local profiles only)
## Local vs remote control
### Profile parameter
- **Local control (default):** `controlUrl` is loopback (`127.0.0.1`/`localhost`).
The Gateway starts the control server and can launch Chrome.
- **Remote control:** `controlUrl` is non-loopback. The Gateway **does not** start
a local server; it assumes you are pointing at an existing server elsewhere.
- **Remote CDP:** set `browser.profiles.<name>.cdpUrl` (or `browser.cdpUrl`) to
attach to a remote Chrome. In this case, Clawdbot will not launch a local browser.
All existing endpoints accept optional `?profile=<name>` query parameter:
- `GET /?profile=work` — status for work profile
- `POST /start?profile=work` — start work profile browser
- `GET /tabs?profile=work` — list tabs for work profile
- `POST /tabs/open?profile=work` — open tab in work profile
- etc.
## Profiles (multi-browser)
When `profile` is omitted, uses `browser.defaultProfile` (defaults to "clawd").
Clawdbot supports multiple named profiles. Each profile has its own:
- user data directory
- CDP port (local) or CDP URL (remote)
- accent color
### Agent browser tool
Defaults:
- The `clawd` profile is auto-created if missing.
- Local CDP ports allocate from **1880018899** by default.
- Deleting a profile moves its local data directory to Trash.
The `browser` tool accepts an optional `profile` parameter for all actions:
All control endpoints accept `?profile=<name>`; the CLI uses `--browser-profile`.
```json
{
"action": "open",
"targetUrl": "https://example.com",
"profile": "work"
}
```
## Isolation guarantees
This routes the operation to the specified profile's browser instance. Omitting
`profile` uses the default profile.
- **Dedicated user data dir**: never touches your personal Chrome profile.
- **Dedicated ports**: avoids `9222` to prevent collisions with dev workflows.
- **Deterministic tab control**: target tabs by `targetId`, not “last tab”.
### Profile naming rules
## Browser selection
- Lowercase alphanumeric characters and hyphens only
- Must start with a letter or number (not a hyphen)
- Maximum 64 characters
- Examples: `clawd`, `work`, `my-project-1`
When launching locally, Clawdbot picks the first available:
1. Chrome Canary
2. Chromium
3. Chrome
### Port allocation
You can override with `browser.executablePath`.
Ports are allocated from range 18800-18899 (~100 profiles max). This is far more
than practical use — memory and CPU exhaustion occur well before port exhaustion.
Ports are allocated once at profile creation and persisted permanently.
Remote profiles are attach-only and do **not** use the local port range.
## Interaction with the agent (clawd)
Platforms:
- macOS: checks `/Applications` and `~/Applications`.
- Linux: looks for `google-chrome`, `chromium`, etc.
- Windows: checks common install locations.
The agent should use browser tools only when:
- enabled in settings
- control URL is configured
## Control API (optional)
If disabled, tools must fail fast with a friendly error ("Browser disabled in settings").
If you want to integrate directly, the browser control server exposes a small
HTTP API:
The agent should not assume tabs are ephemeral. It should:
- call `browser.tabs.list` to discover existing tabs first
- reuse an existing tab when appropriate (e.g. a persistent "main" tab)
- avoid opening duplicate tabs unless asked
- Status/start/stop: `GET /`, `POST /start`, `POST /stop`
- Tabs: `GET /tabs`, `POST /tabs/open`, `POST /tabs/focus`, `DELETE /tabs/:targetId`
- Snapshot/screenshot: `GET /snapshot`, `POST /screenshot`
- Actions: `POST /navigate`, `POST /act`
- Hooks: `POST /hooks/file-chooser`, `POST /hooks/dialog`
- Debugging: `GET /console`, `POST /pdf`
## CLI quick reference (one example each)
All endpoints accept `?profile=<name>`.
All commands accept `--browser-profile <name>` to target a specific profile (default: `clawd`).
### Playwright requirement
Some features (navigate/act/ai snapshot, element screenshots, PDF) require
Playwright. In embedded gateway builds, Playwright may be unavailable; those
endpoints return a clear 501 error. ARIA snapshots and basic screenshots still work.
## CLI quick reference
All commands accept `--browser-profile <name>` to target a specific profile.
Profile management:
- `clawdbot browser profiles`
- `clawdbot browser create-profile --name work`
- `clawdbot browser create-profile --name remote --cdp-url http://10.0.0.42:9222`
- `clawdbot browser delete-profile --name work`
Basics:
- `clawdbot browser status`
- `clawdbot browser start`
- `clawdbot browser stop`
- `clawdbot browser reset-profile`
- `clawdbot browser tabs`
- `clawdbot browser open https://example.com`
- `clawdbot browser focus abcd1234`
@@ -260,6 +148,8 @@ Inspection:
- `clawdbot browser screenshot --ref 12`
- `clawdbot browser snapshot`
- `clawdbot browser snapshot --format aria --limit 200`
- `clawdbot browser console --level error`
- `clawdbot browser pdf`
Actions:
- `clawdbot browser navigate https://example.com`
@@ -271,39 +161,27 @@ Actions:
- `clawdbot browser drag 10 11`
- `clawdbot browser select 9 OptionA OptionB`
- `clawdbot browser upload /tmp/file.pdf`
- `clawdbot browser fill --fields '[{\"ref\":\"1\",\"value\":\"Ada\"}]'`
- `clawdbot browser fill --fields '[{"ref":"1","type":"text","value":"Ada"}]'`
- `clawdbot browser dialog --accept`
- `clawdbot browser wait --text "Done"`
- `clawdbot browser evaluate --fn '(el) => el.textContent' --ref 7`
- `clawdbot browser evaluate --fn "document.querySelector('.my-class').click()"`
- `clawdbot browser console --level error`
- `clawdbot browser pdf`
Notes:
- `upload` and `dialog` are **arming** calls; run them before the click/press that triggers the chooser/dialog.
- `upload` can take a `ref` to auto-click after arming (useful for single-step file uploads).
- `upload` can also take `inputRef` (aria ref) or `element` (CSS selector) to set `<input type="file">` directly without waiting for a file chooser.
- The arm default timeout is **2 minutes** (clamped to max 2 minutes); pass `timeoutMs` if you need shorter.
- `snapshot` defaults to `ai`; `aria` returns an accessibility tree for debugging.
- `click`/`type` require `ref` from `snapshot --format ai`; use `evaluate` for rare CSS selector one-offs.
- Avoid `wait` by default; use it only in exceptional cases when there is no reliable UI state to wait on.
- `upload` and `dialog` are **arming** calls; run them before the click/press
that triggers the chooser/dialog.
- `upload` can also set file inputs directly via `--input-ref` or `--element`.
- `snapshot` defaults to `ai` when available; use `--format aria` for the
accessibility tree.
- `click`/`type` require a `ref` from `snapshot` (CSS selectors are intentionally
not supported for actions).
## Security & privacy notes
## Security & privacy
- The clawd browser profile is app-owned; it may contain logged-in sessions.
Treat it as sensitive data.
- The control server must bind to loopback only by default (`127.0.0.1`) unless the
user explicitly configures a non-loopback URL.
- Never reuse or copy the user's default Chrome profile.
- Remote CDP endpoints should be tunneled or protected; CDP is highly privileged.
## Non-goals (for the first cut)
- Cross-device "sync" of tabs between Mac and Pi.
- Sharing the user's logged-in Chrome sessions automatically.
- General-purpose web scraping; this is primarily for "close-the-loop" verification
and interaction.
- The clawd browser profile may contain logged-in sessions; treat it as sensitive.
- Keep control URLs loopback-only unless you intentionally expose the server.
- Remote CDP endpoints are powerful; tunnel and protect them.
## Troubleshooting
For Linux-specific issues (especially Ubuntu with snap Chromium), see [browser-linux-troubleshooting](/tools/browser-linux-troubleshooting).
For Linux-specific issues (especially snap Chromium), see
[Browser troubleshooting](/tools/browser-linux-troubleshooting).

View File

@@ -7,9 +7,27 @@ read_when:
## What it does
- Elevated mode allows the bash tool to run with elevated privileges when the feature is available and the sender is approved.
- **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.
- 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.
## What it controls (and what it doesnt)
- **Global availability gate**: `agent.elevated` is global (not per-agent). If disabled or sender not allowlisted, elevated is unavailable everywhere.
- **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.
- **Host execution**: elevated runs `bash` on the host (bypasses sandbox).
- **Unsandboxed agents**: when there is no sandbox to bypass, elevated does not change where `bash` runs.
- **Tool policy still applies**: if `bash` is denied by tool policy, elevated cannot be used.
Note:
- Sandbox on: `/elevated on` runs that `bash` command on the host.
- Sandbox off: `/elevated on` does not change execution (already on host).
## When elevated matters
- Only impacts `bash` 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).
2. Session override (set by sending a directive-only message).

View File

@@ -1,8 +1,8 @@
---
summary: "Agent tool surface for Clawdbot (browser, canvas, nodes, cron) replacing clawdbot-* skills"
summary: "Agent tool surface for Clawdbot (browser, canvas, nodes, cron) replacing legacy `clawdbot-*` skills"
read_when:
- Adding or modifying agent tools
- Retiring or changing clawdbot-* skills
- Retiring or changing `clawdbot-*` skills
---
# Tools (Clawdbot)
@@ -36,13 +36,15 @@ Core parameters:
- `yieldMs` (auto-background after timeout, default 10000)
- `background` (immediate background)
- `timeout` (seconds; kills the process if exceeded, default 1800)
- `elevated` (bool; run on host if elevated mode is enabled/allowed)
- `elevated` (bool; run on host if elevated mode is enabled/allowed; only changes behavior when the agent is sandboxed)
- Need a real TTY? Use the tmux skill.
Notes:
- Returns `status: "running"` with a `sessionId` when backgrounded.
- Use `process` to poll/log/write/kill/clear background sessions.
- If `process` is disallowed, `bash` runs synchronously and ignores `yieldMs`/`background`.
- `elevated` is gated by `agent.elevated` (global sender allowlist) and runs on the host.
- `elevated` only changes behavior when the agent is sandboxed (otherwise its a no-op).
### `process`
Manage background bash sessions.
@@ -233,7 +235,7 @@ Notes:
- `reactions` returns per-emoji user lists (limited to 100 per reaction).
- Reaction removal semantics: see [/tools/reactions](/tools/reactions).
- `discord.actions.*` gates Discord tool actions; `roles` + `moderation` default to `false`.
- `searchMessages` follows the Discord preview spec (limit max 25, channel/author filters accept arrays).
- `searchMessages` follows the Discord preview feature constraints (limit max 25, channel/author filters accept arrays).
- The tool is only exposed when the current provider is Discord.
### `whatsapp`
@@ -293,25 +295,12 @@ Node targeting:
- Respect user consent for camera/screen capture.
- Use `status/describe` to ensure permissions before invoking media commands.
## How the model sees tools (pi-mono internals)
## How tools are presented to the agent
Tools are exposed to the model in **two parallel channels**:
Tools are exposed in two parallel channels:
1) **System prompt text**: a human-readable list + guidelines.
2) **Provider tool schema**: the actual function/tool declarations sent to the model API.
1) **System prompt text**: a human-readable list + guidance.
2) **Tool schema**: the structured function definitions sent to the model API.
In pi-mono:
- System prompt builder: [`packages/coding-agent/src/core/system-prompt.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/system-prompt.ts)
- Builds the `Available tools:` list from `toolDescriptions`.
- Appends skills and project context.
- Tool schemas passed to providers:
- OpenAI: [`packages/ai/src/providers/openai-responses.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/ai/src/providers/openai-responses.ts) (`convertTools`)
- Anthropic: [`packages/ai/src/providers/anthropic.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/ai/src/providers/anthropic.ts) (`convertTools`)
- Gemini: [`packages/ai/src/providers/google-shared.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/ai/src/providers/google-shared.ts) (`convertTools`)
- Tool execution loop:
- Agent loop: [`packages/ai/src/agent/agent-loop.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/ai/src/agent/agent-loop.ts)
- Validates tool arguments and executes tools, then appends `toolResult` messages.
In Clawdbot:
- System prompt append: [`src/agents/system-prompt.ts`](https://github.com/clawdbot/clawdbot/blob/main/src/agents/system-prompt.ts)
- Tool list injected via `createClawdbotCodingTools()` in [`src/agents/pi-tools.ts`](https://github.com/clawdbot/clawdbot/blob/main/src/agents/pi-tools.ts)
That means the agent sees both “what tools exist” and “how to call them.” If a tool
doesnt appear in the system prompt or the schema, the model cannot call it.

View File

@@ -1,3 +1,8 @@
---
summary: "Reaction semantics shared across providers"
read_when:
- Working on reactions in any provider
---
# Reaction tooling
Shared reaction semantics across providers:

View File

@@ -7,7 +7,9 @@ read_when:
# Slash commands
Commands are handled by the Gateway. Send them as a **standalone** message that starts with `/`.
Inline text like `hello /status` is ignored.
Inline text like `hello /status` is ignored for commands.
Directives (`/think`, `/verbose`, `/reasoning`, `/elevated`) are parsed even when inline and are stripped from the message before the model sees it.
## Config