diff --git a/docs/docs.json b/docs/docs.json index e39cf3f25a8..121125c6b98 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -1025,43 +1025,6 @@ "group": "Overview", "pages": ["tools/index"] }, - { - "group": "Built-in tools", - "pages": [ - "tools/exec", - "tools/exec-approvals", - "tools/elevated", - "tools/apply-patch", - "tools/web", - "tools/brave-search", - "tools/firecrawl", - "tools/tavily", - "tools/perplexity-search", - "tools/pdf", - "tools/reactions", - "tools/thinking", - "tools/loop-detection", - "tools/btw" - ] - }, - { - "group": "Browser", - "pages": [ - "tools/browser", - "tools/browser-login", - "tools/browser-linux-troubleshooting", - "tools/browser-wsl2-windows-remote-cdp-troubleshooting" - ] - }, - { - "group": "Agent coordination", - "pages": [ - "tools/agent-send", - "tools/subagents", - "tools/acp-agents", - "tools/multi-agent-sandbox-tools" - ] - }, { "group": "Plugins", "pages": [ @@ -1087,10 +1050,6 @@ "prose" ] }, - { - "group": "Plugin tools", - "pages": ["tools/diffs", "tools/llm-task", "tools/lobster"] - }, { "group": "Automation", "pages": [ @@ -1106,18 +1065,43 @@ ] }, { - "group": "Media and devices", + "group": "Tools", "pages": [ - "nodes/index", - "nodes/troubleshooting", - "nodes/media-understanding", - "nodes/images", - "nodes/audio", - "nodes/camera", - "nodes/talk", - "nodes/voicewake", - "nodes/location-command", - "tools/tts" + "tools/exec", + "tools/exec-approvals", + "tools/elevated", + "tools/apply-patch", + "tools/web", + "tools/brave-search", + "tools/firecrawl", + "tools/tavily", + "tools/perplexity-search", + "tools/pdf", + "tools/diffs", + "tools/llm-task", + "tools/lobster", + "tools/reactions", + "tools/thinking", + "tools/loop-detection", + "tools/btw" + ] + }, + { + "group": "Browser", + "pages": [ + "tools/browser", + "tools/browser-login", + "tools/browser-linux-troubleshooting", + "tools/browser-wsl2-windows-remote-cdp-troubleshooting" + ] + }, + { + "group": "Agent coordination", + "pages": [ + "tools/agent-send", + "tools/subagents", + "tools/acp-agents", + "tools/multi-agent-sandbox-tools" ] } ] @@ -1287,6 +1271,21 @@ "security/CONTRIBUTING-THREAT-MODEL" ] }, + { + "group": "Nodes and devices", + "pages": [ + "nodes/index", + "nodes/troubleshooting", + "nodes/media-understanding", + "nodes/images", + "nodes/audio", + "nodes/camera", + "nodes/talk", + "nodes/voicewake", + "nodes/location-command", + "tools/tts" + ] + }, { "group": "Web interfaces", "pages": ["web/index", "web/control-ui", "web/dashboard", "web/webchat", "web/tui"] diff --git a/docs/tools/agent-send.md b/docs/tools/agent-send.md index e301feeea12..153a1e9b3c6 100644 --- a/docs/tools/agent-send.md +++ b/docs/tools/agent-send.md @@ -1,53 +1,100 @@ --- -summary: "Direct `openclaw agent` CLI runs (with optional delivery)" +summary: "Run agent turns from the CLI and optionally deliver replies to channels" read_when: - - Adding or modifying the agent CLI entrypoint + - You want to trigger agent runs from scripts or the command line + - You need to deliver agent replies to a chat channel programmatically title: "Agent Send" --- -# `openclaw agent` (direct agent runs) +# Agent Send -`openclaw 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. +`openclaw agent` runs a single agent turn from the command line without needing +an inbound chat message. Use it for scripted workflows, testing, and +programmatic delivery. + +## Quick start + + + + ```bash + openclaw agent --message "What is the weather today?" + ``` + + This sends the message through the Gateway and prints the reply. + + + + + ```bash + # Target a specific agent + openclaw agent --agent ops --message "Summarize logs" + + # Target a phone number (derives session key) + openclaw agent --to +15555550123 --message "Status update" + + # Reuse an existing session + openclaw agent --session-id abc123 --message "Continue the task" + ``` + + + + + ```bash + # Deliver to WhatsApp (default channel) + openclaw agent --to +15555550123 --message "Report ready" --deliver + + # Deliver to Slack + openclaw agent --agent ops --message "Generate report" \ + --deliver --reply-channel slack --reply-to "#reports" + ``` + + + + +## Flags + +| Flag | Description | +| ----------------------------- | ----------------------------------------------------------- | +| `--message \` | Message to send (required) | +| `--to \` | Derive session key from a target (phone, chat id) | +| `--agent \` | Target a configured agent (uses its `main` session) | +| `--session-id \` | Reuse an existing session by id | +| `--local` | Force local embedded runtime (skip Gateway) | +| `--deliver` | Send the reply to a chat channel | +| `--channel \` | Delivery channel (whatsapp, telegram, discord, slack, etc.) | +| `--reply-to \` | Delivery target override | +| `--reply-channel \` | Delivery channel override | +| `--reply-account \` | Delivery account id override | +| `--thinking \` | Set thinking level (off, minimal, low, medium, high, xhigh) | +| `--verbose \` | Set verbose level | +| `--timeout \` | Override agent timeout | +| `--json` | Output structured JSON | ## Behavior -- Required: `--message ` -- Session selection: - - `--to ` derives the session key (group/channel targets preserve isolation; direct chats collapse to `main`), **or** - - `--session-id ` reuses an existing session by id, **or** - - `--agent ` targets a configured agent directly (uses that agent's `main` session key) -- Runs the same embedded agent runtime as normal inbound replies. -- Thinking/verbose flags persist into the session store. -- Output: - - default: prints reply text (plus `MEDIA:` lines) - - `--json`: prints structured payload + metadata -- Optional delivery back to a channel with `--deliver` + `--channel` (target formats match `openclaw message --target`). -- Use `--reply-channel`/`--reply-to`/`--reply-account` to override delivery without changing the session. - -If the Gateway is unreachable, the CLI **falls back** to the embedded local run. +- By default, the CLI goes **through the Gateway**. Add `--local` to force the + embedded runtime on the current machine. +- If the Gateway is unreachable, the CLI **falls back** to the local embedded run. +- Session selection: `--to` derives the session key (group/channel targets + preserve isolation; direct chats collapse to `main`). +- Thinking and verbose flags persist into the session store. +- Output: plain text by default, or `--json` for structured payload + metadata. ## Examples ```bash -openclaw agent --to +15555550123 --message "status update" -openclaw agent --agent ops --message "Summarize logs" -openclaw agent --session-id 1234 --message "Summarize inbox" --thinking medium +# Simple turn with JSON output openclaw agent --to +15555550123 --message "Trace logs" --verbose on --json -openclaw agent --to +15555550123 --message "Summon reply" --deliver -openclaw agent --agent ops --message "Generate report" --deliver --reply-channel slack --reply-to "#reports" + +# Turn with thinking level +openclaw agent --session-id 1234 --message "Summarize inbox" --thinking medium + +# Deliver to a different channel than the session +openclaw agent --agent ops --message "Alert" --deliver --reply-channel telegram --reply-to "@admin" ``` -## Flags +## Related -- `--local`: run locally (requires model provider API keys in your shell) -- `--deliver`: send the reply to the chosen channel -- `--channel`: delivery channel (`whatsapp|telegram|discord|googlechat|slack|signal|imessage`, default: `whatsapp`) -- `--reply-to`: delivery target override -- `--reply-channel`: delivery channel override -- `--reply-account`: delivery account id override -- `--thinking `: persist thinking level (GPT-5.2 + Codex models only) -- `--verbose `: persist verbose level -- `--timeout `: override agent timeout -- `--json`: output structured JSON +- [Agent CLI reference](/cli/agent) +- [Sub-agents](/tools/subagents) — background sub-agent spawning +- [Sessions](/concepts/session) — how session keys work diff --git a/docs/tools/creating-skills.md b/docs/tools/creating-skills.md index 964165ad0a2..69024038efc 100644 --- a/docs/tools/creating-skills.md +++ b/docs/tools/creating-skills.md @@ -6,53 +6,112 @@ read_when: - You need a quick starter workflow for SKILL.md-based skills --- -# Creating Custom Skills 🛠 +# Creating Skills -OpenClaw is designed to be easily extensible. "Skills" are the primary way to add new capabilities to your assistant. +Skills teach the agent how and when to use tools. Each skill is a directory +containing a `SKILL.md` file with YAML frontmatter and markdown instructions. -## What is a Skill? +For how skills are loaded and prioritized, see [Skills](/tools/skills). -A skill is a directory containing a `SKILL.md` file (which provides instructions and tool definitions to the LLM) and optionally some scripts or resources. +## Create your first skill -## Step-by-Step: Your First Skill + + + Skills live in your workspace. Create a new folder: -### 1. Create the Directory + ```bash + mkdir -p ~/.openclaw/workspace/skills/hello-world + ``` -Skills live in your workspace, usually `~/.openclaw/workspace/skills/`. Create a new folder for your skill: + -```bash -mkdir -p ~/.openclaw/workspace/skills/hello-world -``` + + Create `SKILL.md` inside that directory. The frontmatter defines metadata, + and the markdown body contains instructions for the agent. -### 2. Define the `SKILL.md` + ```markdown + --- + name: hello_world + description: A simple skill that says hello. + --- -Create a `SKILL.md` file in that directory. This file uses YAML frontmatter for metadata and Markdown for instructions. + # Hello World Skill -```markdown ---- -name: hello_world -description: A simple skill that says hello. ---- + When the user asks for a greeting, use the `echo` tool to say + "Hello from your custom skill!". + ``` -# Hello World Skill + -When the user asks for a greeting, use the `echo` tool to say "Hello from your custom skill!". -``` + + You can define custom tool schemas in the frontmatter or instruct the agent + to use existing system tools (like `exec` or `browser`). Skills can also + ship inside plugins alongside the tools they document. -### 3. Add Tools (Optional) + -You can define custom tools in the frontmatter or instruct the agent to use existing system tools (like `bash` or `browser`). + + Start a new session so OpenClaw picks up the skill: -### 4. Refresh OpenClaw + ```bash + # From chat + /new -Ask your agent to "refresh skills" or restart the gateway. OpenClaw will discover the new directory and index the `SKILL.md`. + # Or restart the gateway + openclaw gateway restart + ``` -## Best Practices + Verify the skill loaded: -- **Be Concise**: Instruct the model on _what_ to do, not how to be an AI. -- **Safety First**: If your skill uses `bash`, ensure the prompts don't allow arbitrary command injection from untrusted user input. -- **Test Locally**: Use `openclaw agent --message "use my new skill"` to test. + ```bash + openclaw skills list + ``` -## Shared Skills + -You can also browse and contribute skills to [ClawHub](https://clawhub.com). + + Send a message that should trigger the skill: + + ```bash + openclaw agent --message "give me a greeting" + ``` + + Or just chat with the agent and ask for a greeting. + + + + +## Skill metadata reference + +The YAML frontmatter supports these fields: + +| Field | Required | Description | +| ----------------------------------- | -------- | ------------------------------------------- | +| `name` | Yes | Unique identifier (snake_case) | +| `description` | Yes | One-line description shown to the agent | +| `metadata.openclaw.os` | No | OS filter (`["darwin"]`, `["linux"]`, etc.) | +| `metadata.openclaw.requires.bins` | No | Required binaries on PATH | +| `metadata.openclaw.requires.config` | No | Required config keys | + +## Best practices + +- **Be concise** — instruct the model on _what_ to do, not how to be an AI +- **Safety first** — if your skill uses `exec`, ensure prompts don't allow arbitrary command injection from untrusted input +- **Test locally** — use `openclaw agent --message "..."` to test before sharing +- **Use ClawHub** — browse and contribute skills at [ClawHub](https://clawhub.com) + +## Where skills live + +| Location | Precedence | Scope | +| ------------------------------- | ---------- | --------------------- | +| `\/skills/` | Highest | Per-agent | +| `~/.openclaw/skills/` | Medium | Shared (all agents) | +| Bundled (shipped with OpenClaw) | Lowest | Global | +| `skills.load.extraDirs` | Lowest | Custom shared folders | + +## Related + +- [Skills reference](/tools/skills) — loading, precedence, and gating rules +- [Skills config](/tools/skills-config) — `skills.*` config schema +- [ClawHub](/tools/clawhub) — public skill registry +- [Building Plugins](/plugins/building-plugins) — plugins can ship skills diff --git a/docs/tools/elevated.md b/docs/tools/elevated.md index c10b955ce2d..96a574f6fc9 100644 --- a/docs/tools/elevated.md +++ b/docs/tools/elevated.md @@ -1,63 +1,114 @@ --- -summary: "Elevated exec mode and /elevated directives" +summary: "Elevated exec mode: run commands on the gateway host from a sandboxed agent" read_when: - Adjusting elevated mode defaults, allowlists, or slash command behavior + - Understanding how sandboxed agents can access the host title: "Elevated Mode" --- -# Elevated Mode (/elevated directives) +# Elevated Mode -## What it does +When an agent runs inside a sandbox, its `exec` commands are confined to the +sandbox environment. **Elevated mode** lets the agent break out and run commands +on the gateway host instead, with configurable approval gates. -- `/elevated on` runs on the gateway host and keeps exec approvals (same as `/elevated ask`). -- `/elevated full` runs on the gateway host **and** auto-approves exec (skips exec approvals). -- `/elevated ask` runs on the gateway host but keeps exec approvals (same as `/elevated on`). -- `on`/`ask` do **not** force `exec.security=full`; configured security/ask policy still applies. -- Only changes behavior when the agent is **sandboxed** (otherwise exec already runs on the host). -- Directive forms: `/elevated on|off|ask|full`, `/elev on|off|ask|full`. -- Only `on|off|ask|full` are accepted; anything else returns a hint and does not change state. + + Elevated mode only changes behavior when the agent is **sandboxed**. For + unsandboxed agents, exec already runs on the host. + -## What it controls (and what it does not) +## Directives -- **Availability gates**: `tools.elevated` is the global baseline. `agents.list[].tools.elevated` can further restrict elevated per agent (both must allow). -- **Per-session state**: `/elevated on|off|ask|full` sets the elevated level for the current session key. -- **Inline directive**: `/elevated on|ask|full` 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 forces `exec` onto the gateway host; `full` also sets `security=full`. -- **Approvals**: `full` skips exec approvals; `on`/`ask` honor them when allowlist/ask rules require. -- **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. -- **Separate from `/exec`**: `/exec` adjusts per-session defaults for authorized senders and does not require elevated. +Control elevated mode per-session with slash commands: + +| Directive | What it does | +| ---------------- | --------------------------------------------------- | +| `/elevated on` | Run on the gateway host, keep exec approvals | +| `/elevated ask` | Same as `on` (alias) | +| `/elevated full` | Run on the gateway host **and** skip exec approvals | +| `/elevated off` | Return to sandbox-confined execution | + +Also available as `/elev on|off|ask|full`. + +Send `/elevated` with no argument to see the current level. + +## How it works + + + + Elevated must be enabled in config and the sender must be on the allowlist: + + ```json5 + { + tools: { + elevated: { + enabled: true, + allowFrom: { + discord: ["user-id-123"], + whatsapp: ["+15555550123"], + }, + }, + }, + } + ``` + + + + + Send a directive-only message to set the session default: + + ``` + /elevated full + ``` + + Or use it inline (applies to that message only): + + ``` + /elevated on run the deployment script + ``` + + + + + With elevated active, `exec` calls route to the gateway host instead of the + sandbox. In `full` mode, exec approvals are skipped. In `on`/`ask` mode, + configured approval rules still apply. + + ## Resolution order -1. Inline directive on the message (applies only to that message). -2. Session override (set by sending a directive-only message). -3. Global default (`agents.defaults.elevatedDefault` in config). +1. **Inline directive** on the message (applies only to that message) +2. **Session override** (set by sending a directive-only message) +3. **Global default** (`agents.defaults.elevatedDefault` in config) -## Setting a session default +## Availability and allowlists -- Send a message that is **only** the directive (whitespace allowed), e.g. `/elevated full`. -- Confirmation reply is sent (`Elevated mode set to full...` / `Elevated mode disabled.`). -- 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. +- **Global gate**: `tools.elevated.enabled` (must be `true`) +- **Sender allowlist**: `tools.elevated.allowFrom` with per-channel lists +- **Per-agent gate**: `agents.list[].tools.elevated.enabled` (can only further restrict) +- **Per-agent allowlist**: `agents.list[].tools.elevated.allowFrom` (sender must match both global + per-agent) +- **Discord fallback**: if `tools.elevated.allowFrom.discord` is omitted, `channels.discord.allowFrom` is used as fallback +- **All gates must pass**; otherwise elevated is treated as unavailable -## Availability + allowlists +Allowlist entry formats: -- Feature gate: `tools.elevated.enabled` (default can be off via config even if the code supports it). -- Sender allowlist: `tools.elevated.allowFrom` with per-provider allowlists (e.g. `discord`, `whatsapp`). -- Unprefixed allowlist entries match sender-scoped identity values only (`SenderId`, `SenderE164`, `From`); recipient routing fields are never used for elevated authorization. -- Mutable sender metadata requires explicit prefixes: - - `name:` matches `SenderName` - - `username:` matches `SenderUsername` - - `tag:` matches `SenderTag` - - `id:`, `from:`, `e164:` are available for explicit identity targeting -- Per-agent gate: `agents.list[].tools.elevated.enabled` (optional; can only further restrict). -- Per-agent allowlist: `agents.list[].tools.elevated.allowFrom` (optional; when set, the sender must match **both** global + per-agent allowlists). -- Discord fallback: if `tools.elevated.allowFrom.discord` is omitted, the `channels.discord.allowFrom` list is used as a fallback (legacy: `channels.discord.dm.allowFrom`). Set `tools.elevated.allowFrom.discord` (even `[]`) to override. Per-agent allowlists do **not** use the fallback. -- All gates must pass; otherwise elevated is treated as unavailable. +| Prefix | Matches | +| ----------------------- | ------------------------------- | +| (none) | Sender ID, E.164, or From field | +| `name:` | Sender display name | +| `username:` | Sender username | +| `tag:` | Sender tag | +| `id:`, `from:`, `e164:` | Explicit identity targeting | -## Logging + status +## What elevated does not control -- Elevated exec calls are logged at info level. -- Session status includes elevated mode (e.g. `elevated=ask`, `elevated=full`). +- **Tool policy**: if `exec` is denied by tool policy, elevated cannot override it +- **Separate from `/exec`**: the `/exec` directive adjusts per-session exec defaults for authorized senders and does not require elevated mode + +## Related + +- [Exec tool](/tools/exec) — shell command execution +- [Exec approvals](/tools/exec-approvals) — approval and allowlist system +- [Sandboxing](/gateway/sandboxing) — sandbox configuration +- [Sandbox vs Tool Policy vs Elevated](/gateway/sandbox-vs-tool-policy-vs-elevated) diff --git a/docs/tools/reactions.md b/docs/tools/reactions.md index 17f9cfbb7f9..56d6b5942e7 100644 --- a/docs/tools/reactions.md +++ b/docs/tools/reactions.md @@ -1,23 +1,64 @@ --- -summary: "Reaction semantics shared across channels" +summary: "Reaction tool semantics across all supported channels" read_when: - Working on reactions in any channel + - Understanding how emoji reactions differ across platforms title: "Reactions" --- -# Reaction tooling +# Reactions -Shared reaction semantics across channels: +The agent can add and remove emoji reactions on messages using the `message` +tool with the `react` action. Reaction behavior varies by channel. + +## How it works + +```json +{ + "action": "react", + "messageId": "msg-123", + "emoji": "thumbsup" +} +``` - `emoji` is required when adding a reaction. -- `emoji=""` removes the bot's reaction(s) when supported. -- `remove: true` removes the specified emoji when supported (requires `emoji`). +- Set `emoji` to an empty string (`""`) to remove the bot's reaction(s). +- Set `remove: true` to remove a specific emoji (requires non-empty `emoji`). -Channel notes: +## Channel behavior -- **Discord/Slack**: empty `emoji` removes all of the bot's reactions on the message; `remove: true` removes just that emoji. -- **Google Chat**: empty `emoji` removes the app's reactions on the message; `remove: true` removes just that emoji. -- **Telegram**: empty `emoji` removes the bot's reactions; `remove: true` also removes reactions but still requires a non-empty `emoji` for tool validation. -- **WhatsApp**: empty `emoji` removes the bot reaction; `remove: true` maps to empty emoji (still requires `emoji`). -- **Zalo Personal (`zalouser`)**: requires non-empty `emoji`; `remove: true` removes that specific emoji reaction. -- **Signal**: inbound reaction notifications emit system events when `channels.signal.reactionNotifications` is enabled. + + + - Empty `emoji` removes all of the bot's reactions on the message. + - `remove: true` removes just the specified emoji. + + + + - Empty `emoji` removes the app's reactions on the message. + - `remove: true` removes just the specified emoji. + + + + - Empty `emoji` removes the bot's reactions. + - `remove: true` also removes reactions but still requires a non-empty `emoji` for tool validation. + + + + - Empty `emoji` removes the bot reaction. + - `remove: true` maps to empty emoji internally (still requires `emoji` in the tool call). + + + + - Requires non-empty `emoji`. + - `remove: true` removes that specific emoji reaction. + + + + - Inbound reaction notifications emit system events when `channels.signal.reactionNotifications` is enabled. + + + +## Related + +- [Agent Send](/tools/agent-send) — the `message` tool that includes `react` +- [Channels](/channels) — channel-specific configuration