From 9c4eab69cca597d6ff7a14e652ef069ac06e8b8f Mon Sep 17 00:00:00 2001 From: Tyler Yust <64381258+tyler6204@users.noreply.github.com> Date: Tue, 3 Feb 2026 18:06:54 -0800 Subject: [PATCH] iMessage: promote BlueBubbles and refresh docs/skills (#8415) * feat: Make BlueBubbles the primary iMessage integration - Remove old imsg skill (skills/imsg/SKILL.md) - Create new BlueBubbles skill (skills/bluebubbles/SKILL.md) with message tool examples - Add keep-alive script documentation for VM/headless setups to docs/channels/bluebubbles.md - AppleScript that pokes Messages.app every 5 minutes - LaunchAgent configuration for automatic execution - Prevents Messages.app from going idle in VM environments - Update all documentation to prioritize BlueBubbles over legacy imsg: - Mark imsg channel as legacy throughout docs - Update README.md channel lists - Update wizard, hubs, pairing, and index docs - Update FAQ to recommend BlueBubbles for iMessage - Update RPC docs to note imsg as legacy pattern - Update Chinese documentation (zh-CN) - Replace imsg examples with generic macOS skill examples where appropriate BlueBubbles is now the recommended first-class iMessage integration, with the legacy imsg integration marked for potential future removal. * refactor: Update import paths and improve code formatting - Adjusted import paths in session-status-tool.ts, whatsapp-heartbeat.ts, and heartbeat-runner.ts for consistency. - Reformatted code for better readability by aligning and grouping related imports and function parameters. - Enhanced error messages and conditional checks for clarity in heartbeat-runner.ts. * skills: restore imsg skill and align bluebubbles skill * docs: update FAQ for clarity and formatting - Adjusted the formatting of the FAQ section to ensure consistent bullet point alignment. - No content changes were made, only formatting improvements for better readability. * style: oxfmt touched files * fix: preserve BlueBubbles developer reference (#8415) (thanks @tyler6204) --- CHANGELOG.md | 4 + README.md | 14 +- docs/channels/bluebubbles.md | 74 +++++ docs/channels/imessage.md | 10 +- docs/channels/index.md | 2 +- docs/help/faq.md | 364 ++++++++++----------- docs/index.md | 3 +- docs/reference/rpc.md | 10 +- docs/start/hubs.md | 3 +- docs/start/pairing.md | 3 +- docs/start/wizard.md | 5 +- docs/zh-CN/channels/index.md | 4 +- docs/zh-CN/help/faq.md | 2 +- extensions/bluebubbles/README.md | 45 +++ skills/bluebubbles/SKILL.md | 145 ++++++-- skills/imsg/SKILL.md | 50 ++- src/agents/tools/session-status-tool.ts | 32 +- src/channels/plugins/whatsapp-heartbeat.ts | 2 +- src/infra/heartbeat-runner.ts | 31 +- 19 files changed, 534 insertions(+), 269 deletions(-) create mode 100644 extensions/bluebubbles/README.md diff --git a/CHANGELOG.md b/CHANGELOG.md index e6766a1cf7..c62fb374cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,10 @@ Docs: https://docs.openclaw.ai ## 2026.2.2-2 +### Changes + +- Docs: promote BlueBubbles as the recommended iMessage integration; mark imsg channel as legacy. (#8415) Thanks @tyler6204. + ### Fixes - CLI status: resolve build-info from bundled dist output (fixes "unknown" commit in npm builds). diff --git a/README.md b/README.md index 3aad134905..7e24435689 100644 --- a/README.md +++ b/README.md @@ -120,7 +120,7 @@ Run `openclaw doctor` to surface risky/misconfigured DM policies. ## Highlights - **[Local-first Gateway](https://docs.openclaw.ai/gateway)** — single control plane for sessions, channels, tools, and events. -- **[Multi-channel inbox](https://docs.openclaw.ai/channels)** — WhatsApp, Telegram, Slack, Discord, Google Chat, Signal, iMessage, BlueBubbles, Microsoft Teams, Matrix, Zalo, Zalo Personal, WebChat, macOS, iOS/Android. +- **[Multi-channel inbox](https://docs.openclaw.ai/channels)** — WhatsApp, Telegram, Slack, Discord, Google Chat, Signal, BlueBubbles (iMessage), iMessage (legacy), Microsoft Teams, Matrix, Zalo, Zalo Personal, WebChat, macOS, iOS/Android. - **[Multi-agent routing](https://docs.openclaw.ai/gateway/configuration)** — route inbound channels/accounts/peers to isolated agents (workspaces + per-agent sessions). - **[Voice Wake](https://docs.openclaw.ai/nodes/voicewake) + [Talk Mode](https://docs.openclaw.ai/nodes/talk)** — always-on speech for macOS/iOS/Android with ElevenLabs. - **[Live Canvas](https://docs.openclaw.ai/platforms/mac/canvas)** — agent-driven visual workspace with [A2UI](https://docs.openclaw.ai/platforms/mac/canvas#canvas-a2ui). @@ -144,7 +144,7 @@ Run `openclaw doctor` to surface risky/misconfigured DM policies. ### Channels -- [Channels](https://docs.openclaw.ai/channels): [WhatsApp](https://docs.openclaw.ai/channels/whatsapp) (Baileys), [Telegram](https://docs.openclaw.ai/channels/telegram) (grammY), [Slack](https://docs.openclaw.ai/channels/slack) (Bolt), [Discord](https://docs.openclaw.ai/channels/discord) (discord.js), [Google Chat](https://docs.openclaw.ai/channels/googlechat) (Chat API), [Signal](https://docs.openclaw.ai/channels/signal) (signal-cli), [iMessage](https://docs.openclaw.ai/channels/imessage) (imsg), [BlueBubbles](https://docs.openclaw.ai/channels/bluebubbles) (extension), [Microsoft Teams](https://docs.openclaw.ai/channels/msteams) (extension), [Matrix](https://docs.openclaw.ai/channels/matrix) (extension), [Zalo](https://docs.openclaw.ai/channels/zalo) (extension), [Zalo Personal](https://docs.openclaw.ai/channels/zalouser) (extension), [WebChat](https://docs.openclaw.ai/web/webchat). +- [Channels](https://docs.openclaw.ai/channels): [WhatsApp](https://docs.openclaw.ai/channels/whatsapp) (Baileys), [Telegram](https://docs.openclaw.ai/channels/telegram) (grammY), [Slack](https://docs.openclaw.ai/channels/slack) (Bolt), [Discord](https://docs.openclaw.ai/channels/discord) (discord.js), [Google Chat](https://docs.openclaw.ai/channels/googlechat) (Chat API), [Signal](https://docs.openclaw.ai/channels/signal) (signal-cli), [BlueBubbles](https://docs.openclaw.ai/channels/bluebubbles) (iMessage, recommended), [iMessage](https://docs.openclaw.ai/channels/imessage) (legacy imsg), [Microsoft Teams](https://docs.openclaw.ai/channels/msteams) (extension), [Matrix](https://docs.openclaw.ai/channels/matrix) (extension), [Zalo](https://docs.openclaw.ai/channels/zalo) (extension), [Zalo Personal](https://docs.openclaw.ai/channels/zalouser) (extension), [WebChat](https://docs.openclaw.ai/web/webchat). - [Group routing](https://docs.openclaw.ai/concepts/group-messages): mention gating, reply tags, per-channel chunking and routing. Channel rules: [Channels](https://docs.openclaw.ai/channels). ### Apps + nodes @@ -375,9 +375,15 @@ Details: [Security guide](https://docs.openclaw.ai/gateway/security) · [Docker - Requires `signal-cli` and a `channels.signal` config section. -### [iMessage](https://docs.openclaw.ai/channels/imessage) +### [BlueBubbles (iMessage)](https://docs.openclaw.ai/channels/bluebubbles) -- macOS only; Messages must be signed in. +- **Recommended** iMessage integration. +- Configure `channels.bluebubbles.serverUrl` + `channels.bluebubbles.password` and a webhook (`channels.bluebubbles.webhookPath`). +- The BlueBubbles server runs on macOS; the Gateway can run on macOS or elsewhere. + +### [iMessage (legacy)](https://docs.openclaw.ai/channels/imessage) + +- Legacy macOS-only integration via `imsg` (Messages must be signed in). - If `channels.imessage.groups` is set, it becomes a group allowlist; include `"*"` to allow all. ### [Microsoft Teams](https://docs.openclaw.ai/channels/msteams) diff --git a/docs/channels/bluebubbles.md b/docs/channels/bluebubbles.md index 69063304d5..b40fc375da 100644 --- a/docs/channels/bluebubbles.md +++ b/docs/channels/bluebubbles.md @@ -42,6 +42,80 @@ Status: bundled plugin that talks to the BlueBubbles macOS server over HTTP. **R 4. Point BlueBubbles webhooks to your gateway (example: `https://your-gateway-host:3000/bluebubbles-webhook?password=`). 5. Start the gateway; it will register the webhook handler and start pairing. +## Keeping Messages.app alive (VM / headless setups) + +Some macOS VM / always-on setups can end up with Messages.app going “idle” (incoming events stop until the app is opened/foregrounded). A simple workaround is to **poke Messages every 5 minutes** using an AppleScript + LaunchAgent. + +### 1) Save the AppleScript + +Save this as: + +- `~/Scripts/poke-messages.scpt` + +Example script (non-interactive; does not steal focus): + +```applescript +try + tell application "Messages" + if not running then + launch + end if + + -- Touch the scripting interface to keep the process responsive. + set _chatCount to (count of chats) + end tell +on error + -- Ignore transient failures (first-run prompts, locked session, etc). +end try +``` + +### 2) Install a LaunchAgent + +Save this as: + +- `~/Library/LaunchAgents/com.user.poke-messages.plist` + +```xml + + + + + Label + com.user.poke-messages + + ProgramArguments + + /bin/bash + -lc + /usr/bin/osascript "$HOME/Scripts/poke-messages.scpt" + + + RunAtLoad + + + StartInterval + 300 + + StandardOutPath + /tmp/poke-messages.log + StandardErrorPath + /tmp/poke-messages.err + + +``` + +Notes: + +- This runs **every 300 seconds** and **on login**. +- The first run may trigger macOS **Automation** prompts (`osascript` → Messages). Approve them in the same user session that runs the LaunchAgent. + +Load it: + +```bash +launchctl unload ~/Library/LaunchAgents/com.user.poke-messages.plist 2>/dev/null || true +launchctl load ~/Library/LaunchAgents/com.user.poke-messages.plist +``` + ## Onboarding BlueBubbles is available in the interactive setup wizard: diff --git a/docs/channels/imessage.md b/docs/channels/imessage.md index e28e9340d3..5542b3190c 100644 --- a/docs/channels/imessage.md +++ b/docs/channels/imessage.md @@ -1,14 +1,18 @@ --- -summary: "iMessage support via imsg (JSON-RPC over stdio), setup, and chat_id routing" +summary: "Legacy iMessage support via imsg (JSON-RPC over stdio). New setups should use BlueBubbles." read_when: - Setting up iMessage support - Debugging iMessage send/receive title: iMessage --- -# iMessage (imsg) +# iMessage (legacy: imsg) -Status: external CLI integration. Gateway spawns `imsg rpc` (JSON-RPC over stdio). +> **Recommended:** Use [BlueBubbles](/channels/bluebubbles) for new iMessage setups. +> +> The `imsg` channel is a legacy external-CLI integration and may be removed in a future release. + +Status: legacy external CLI integration. Gateway spawns `imsg rpc` (JSON-RPC over stdio). ## Quick setup (beginner) diff --git a/docs/channels/index.md b/docs/channels/index.md index 1f161c9c6a..844af27505 100644 --- a/docs/channels/index.md +++ b/docs/channels/index.md @@ -22,7 +22,7 @@ Text is supported everywhere; media and reactions vary by channel. - [Mattermost](/channels/mattermost) — Bot API + WebSocket; channels, groups, DMs (plugin, installed separately). - [Signal](/channels/signal) — signal-cli; privacy-focused. - [BlueBubbles](/channels/bluebubbles) — **Recommended for iMessage**; uses the BlueBubbles macOS server REST API with full feature support (edit, unsend, effects, reactions, group management — edit currently broken on macOS 26 Tahoe). -- [iMessage](/channels/imessage) — macOS only; native integration via imsg (legacy, consider BlueBubbles for new setups). +- [iMessage (legacy)](/channels/imessage) — Legacy macOS integration via imsg CLI (deprecated, use BlueBubbles for new setups). - [Microsoft Teams](/channels/msteams) — Bot Framework; enterprise support (plugin, installed separately). - [LINE](/channels/line) — LINE Messaging API bot (plugin, installed separately). - [Nextcloud Talk](/channels/nextcloud-talk) — Self-hosted chat via Nextcloud Talk (plugin, installed separately). diff --git a/docs/help/faq.md b/docs/help/faq.md index 354290cf02..a9348b69f1 100644 --- a/docs/help/faq.md +++ b/docs/help/faq.md @@ -11,7 +11,7 @@ Quick answers plus deeper troubleshooting for real-world setups (local dev, VPS, - [Quick start and first-run setup](#quick-start-and-firstrun-setup) - [Im stuck whats the fastest way to get unstuck?](#im-stuck-whats-the-fastest-way-to-get-unstuck) - - [What’s the recommended way to install and set up OpenClaw?](#whats-the-recommended-way-to-install-and-set-up-openclaw) + - [What's the recommended way to install and set up OpenClaw?](#whats-the-recommended-way-to-install-and-set-up-openclaw) - [How do I open the dashboard after onboarding?](#how-do-i-open-the-dashboard-after-onboarding) - [How do I authenticate the dashboard (token) on localhost vs remote?](#how-do-i-authenticate-the-dashboard-token-on-localhost-vs-remote) - [What runtime do I need?](#what-runtime-do-i-need) @@ -21,13 +21,13 @@ Quick answers plus deeper troubleshooting for real-world setups (local dev, VPS, - [Can I migrate my setup to a new machine (Mac mini) without redoing onboarding?](#can-i-migrate-my-setup-to-a-new-machine-mac-mini-without-redoing-onboarding) - [Where do I see what is new in the latest version?](#where-do-i-see-what-is-new-in-the-latest-version) - [I can't access docs.openclaw.ai (SSL error). What now?](#i-cant-access-docsopenclawai-ssl-error-what-now) - - [What’s the difference between stable and beta?](#whats-the-difference-between-stable-and-beta) -- [How do I install the beta version, and what’s the difference between beta and dev?](#how-do-i-install-the-beta-version-and-whats-the-difference-between-beta-and-dev) + - [What's the difference between stable and beta?](#whats-the-difference-between-stable-and-beta) + - [How do I install the beta version, and what's the difference between beta and dev?](#how-do-i-install-the-beta-version-and-whats-the-difference-between-beta-and-dev) - [How do I try the latest bits?](#how-do-i-try-the-latest-bits) - [How long does install and onboarding usually take?](#how-long-does-install-and-onboarding-usually-take) - [Installer stuck? How do I get more feedback?](#installer-stuck-how-do-i-get-more-feedback) - [Windows install says git not found or openclaw not recognized](#windows-install-says-git-not-found-or-openclaw-not-recognized) - - [The docs didn’t answer my question - how do I get a better answer?](#the-docs-didnt-answer-my-question-how-do-i-get-a-better-answer) + - [The docs didn't answer my question - how do I get a better answer?](#the-docs-didnt-answer-my-question-how-do-i-get-a-better-answer) - [How do I install OpenClaw on Linux?](#how-do-i-install-openclaw-on-linux) - [How do I install OpenClaw on a VPS?](#how-do-i-install-openclaw-on-a-vps) - [Where are the cloud/VPS install guides?](#where-are-the-cloudvps-install-guides) @@ -53,7 +53,7 @@ Quick answers plus deeper troubleshooting for real-world setups (local dev, VPS, - [Can multiple people use one WhatsApp number with different OpenClaw instances?](#can-multiple-people-use-one-whatsapp-number-with-different-openclaw-instances) - [Can I run a "fast chat" agent and an "Opus for coding" agent?](#can-i-run-a-fast-chat-agent-and-an-opus-for-coding-agent) - [Does Homebrew work on Linux?](#does-homebrew-work-on-linux) - - [What’s the difference between the hackable (git) install and npm install?](#whats-the-difference-between-the-hackable-git-install-and-npm-install) + - [What's the difference between the hackable (git) install and npm install?](#whats-the-difference-between-the-hackable-git-install-and-npm-install) - [Can I switch between npm and git installs later?](#can-i-switch-between-npm-and-git-installs-later) - [Should I run the Gateway on my laptop or a VPS?](#should-i-run-the-gateway-on-my-laptop-or-a-vps) - [How important is it to run OpenClaw on a dedicated machine?](#how-important-is-it-to-run-openclaw-on-a-dedicated-machine) @@ -61,7 +61,7 @@ Quick answers plus deeper troubleshooting for real-world setups (local dev, VPS, - [Can I run OpenClaw in a VM and what are the requirements](#can-i-run-openclaw-in-a-vm-and-what-are-the-requirements) - [What is OpenClaw?](#what-is-openclaw) - [What is OpenClaw, in one paragraph?](#what-is-openclaw-in-one-paragraph) - - [What’s the value proposition?](#whats-the-value-proposition) + - [What's the value proposition?](#whats-the-value-proposition) - [I just set it up what should I do first](#i-just-set-it-up-what-should-i-do-first) - [What are the top five everyday use cases for OpenClaw](#what-are-the-top-five-everyday-use-cases-for-openclaw) - [Can OpenClaw help with lead gen outreach ads and blogs for a SaaS](#can-openclaw-help-with-lead-gen-outreach-ads-and-blogs-for-a-saas) @@ -88,10 +88,10 @@ Quick answers plus deeper troubleshooting for real-world setups (local dev, VPS, - [Is all data used with OpenClaw saved locally?](#is-all-data-used-with-openclaw-saved-locally) - [Where does OpenClaw store its data?](#where-does-openclaw-store-its-data) - [Where should AGENTS.md / SOUL.md / USER.md / MEMORY.md live?](#where-should-agentsmd-soulmd-usermd-memorymd-live) - - [What’s the recommended backup strategy?](#whats-the-recommended-backup-strategy) + - [What's the recommended backup strategy?](#whats-the-recommended-backup-strategy) - [How do I completely uninstall OpenClaw?](#how-do-i-completely-uninstall-openclaw) - [Can agents work outside the workspace?](#can-agents-work-outside-the-workspace) - - [I’m in remote mode - where is the session store?](#im-in-remote-mode-where-is-the-session-store) + - [I'm in remote mode - where is the session store?](#im-in-remote-mode-where-is-the-session-store) - [Config basics](#config-basics) - [What format is the config? Where is it?](#what-format-is-the-config-where-is-it) - [I set `gateway.bind: "lan"` (or `"tailnet"`) and now nothing listens / the UI says unauthorized](#i-set-gatewaybind-lan-or-tailnet-and-now-nothing-listens-the-ui-says-unauthorized) @@ -111,44 +111,44 @@ Quick answers plus deeper troubleshooting for real-world setups (local dev, VPS, - [Is there a benefit to using a node on my personal laptop instead of SSH from a VPS?](#is-there-a-benefit-to-using-a-node-on-my-personal-laptop-instead-of-ssh-from-a-vps) - [Do nodes run a gateway service?](#do-nodes-run-a-gateway-service) - [Is there an API / RPC way to apply config?](#is-there-an-api-rpc-way-to-apply-config) - - [What’s a minimal “sane” config for a first install?](#whats-a-minimal-sane-config-for-a-first-install) + - [What's a minimal "sane" config for a first install?](#whats-a-minimal-sane-config-for-a-first-install) - [How do I set up Tailscale on a VPS and connect from my Mac?](#how-do-i-set-up-tailscale-on-a-vps-and-connect-from-my-mac) - [How do I connect a Mac node to a remote Gateway (Tailscale Serve)?](#how-do-i-connect-a-mac-node-to-a-remote-gateway-tailscale-serve) - [Should I install on a second laptop or just add a node?](#should-i-install-on-a-second-laptop-or-just-add-a-node) - [Env vars and .env loading](#env-vars-and-env-loading) - [How does OpenClaw load environment variables?](#how-does-openclaw-load-environment-variables) - - [“I started the Gateway via the service and my env vars disappeared.” What now?](#i-started-the-gateway-via-the-service-and-my-env-vars-disappeared-what-now) - - [I set `COPILOT_GITHUB_TOKEN`, but models status shows “Shell env: off.” Why?](#i-set-copilotgithubtoken-but-models-status-shows-shell-env-off-why) + - ["I started the Gateway via the service and my env vars disappeared." What now?](#i-started-the-gateway-via-the-service-and-my-env-vars-disappeared-what-now) + - [I set `COPILOT_GITHUB_TOKEN`, but models status shows "Shell env: off." Why?](#i-set-copilotgithubtoken-but-models-status-shows-shell-env-off-why) - [Sessions & multiple chats](#sessions-multiple-chats) - [How do I start a fresh conversation?](#how-do-i-start-a-fresh-conversation) - [Do sessions reset automatically if I never send `/new`?](#do-sessions-reset-automatically-if-i-never-send-new) - [Is there a way to make a team of OpenClaw instances one CEO and many agents](#is-there-a-way-to-make-a-team-of-openclaw-instances-one-ceo-and-many-agents) - [Why did context get truncated mid-task? How do I prevent it?](#why-did-context-get-truncated-midtask-how-do-i-prevent-it) - [How do I completely reset OpenClaw but keep it installed?](#how-do-i-completely-reset-openclaw-but-keep-it-installed) - - [I’m getting “context too large” errors - how do I reset or compact?](#im-getting-context-too-large-errors-how-do-i-reset-or-compact) - - [Why am I seeing “LLM request rejected: messages.N.content.X.tool_use.input: Field required”?](#why-am-i-seeing-llm-request-rejected-messagesncontentxtooluseinput-field-required) + - [I'm getting "context too large" errors - how do I reset or compact?](#im-getting-context-too-large-errors-how-do-i-reset-or-compact) + - [Why am I seeing "LLM request rejected: messages.N.content.X.tool_use.input: Field required"?](#why-am-i-seeing-llm-request-rejected-messagesncontentxtooluseinput-field-required) - [Why am I getting heartbeat messages every 30 minutes?](#why-am-i-getting-heartbeat-messages-every-30-minutes) - - [Do I need to add a “bot account” to a WhatsApp group?](#do-i-need-to-add-a-bot-account-to-a-whatsapp-group) + - [Do I need to add a "bot account" to a WhatsApp group?](#do-i-need-to-add-a-bot-account-to-a-whatsapp-group) - [How do I get the JID of a WhatsApp group?](#how-do-i-get-the-jid-of-a-whatsapp-group) - - [Why doesn’t OpenClaw reply in a group?](#why-doesnt-openclaw-reply-in-a-group) + - [Why doesn't OpenClaw reply in a group?](#why-doesnt-openclaw-reply-in-a-group) - [Do groups/threads share context with DMs?](#do-groupsthreads-share-context-with-dms) - [How many workspaces and agents can I create?](#how-many-workspaces-and-agents-can-i-create) - [Can I run multiple bots or chats at the same time (Slack), and how should I set that up?](#can-i-run-multiple-bots-or-chats-at-the-same-time-slack-and-how-should-i-set-that-up) - [Models: defaults, selection, aliases, switching](#models-defaults-selection-aliases-switching) - - [What is the “default model”?](#what-is-the-default-model) + - [What is the "default model"?](#what-is-the-default-model) - [What model do you recommend?](#what-model-do-you-recommend) - [How do I switch models without wiping my config?](#how-do-i-switch-models-without-wiping-my-config) - [Can I use self-hosted models (llama.cpp, vLLM, Ollama)?](#can-i-use-selfhosted-models-llamacpp-vllm-ollama) - [What do OpenClaw, Flawd, and Krill use for models?](#what-do-openclaw-flawd-and-krill-use-for-models) - [How do I switch models on the fly (without restarting)?](#how-do-i-switch-models-on-the-fly-without-restarting) - [Can I use GPT 5.2 for daily tasks and Codex 5.2 for coding](#can-i-use-gpt-52-for-daily-tasks-and-codex-52-for-coding) - - [Why do I see “Model … is not allowed” and then no reply?](#why-do-i-see-model-is-not-allowed-and-then-no-reply) - - [Why do I see “Unknown model: minimax/MiniMax-M2.1”?](#why-do-i-see-unknown-model-minimaxminimaxm21) + - [Why do I see "Model … is not allowed" and then no reply?](#why-do-i-see-model-is-not-allowed-and-then-no-reply) + - [Why do I see "Unknown model: minimax/MiniMax-M2.1"?](#why-do-i-see-unknown-model-minimaxminimaxm21) - [Can I use MiniMax as my default and OpenAI for complex tasks?](#can-i-use-minimax-as-my-default-and-openai-for-complex-tasks) - - [Are opus / sonnet / gpt built‑in shortcuts?](#are-opus-sonnet-gpt-builtin-shortcuts) + - [Are opus / sonnet / gpt built-in shortcuts?](#are-opus-sonnet-gpt-builtin-shortcuts) - [How do I define/override model shortcuts (aliases)?](#how-do-i-defineoverride-model-shortcuts-aliases) - [How do I add models from other providers like OpenRouter or Z.AI?](#how-do-i-add-models-from-other-providers-like-openrouter-or-zai) -- [Model failover and “All models failed”](#model-failover-and-all-models-failed) +- [Model failover and "All models failed"](#model-failover-and-all-models-failed) - [How does failover work?](#how-does-failover-work) - [What does this error mean?](#what-does-this-error-mean) - [Fix checklist for `No credentials found for profile "anthropic:default"`](#fix-checklist-for-no-credentials-found-for-profile-anthropicdefault) @@ -157,17 +157,17 @@ Quick answers plus deeper troubleshooting for real-world setups (local dev, VPS, - [What is an auth profile?](#what-is-an-auth-profile) - [What are typical profile IDs?](#what-are-typical-profile-ids) - [Can I control which auth profile is tried first?](#can-i-control-which-auth-profile-is-tried-first) - - [OAuth vs API key: what’s the difference?](#oauth-vs-api-key-whats-the-difference) -- [Gateway: ports, “already running”, and remote mode](#gateway-ports-already-running-and-remote-mode) + - [OAuth vs API key: what's the difference?](#oauth-vs-api-key-whats-the-difference) +- [Gateway: ports, "already running", and remote mode](#gateway-ports-already-running-and-remote-mode) - [What port does the Gateway use?](#what-port-does-the-gateway-use) - [Why does `openclaw gateway status` say `Runtime: running` but `RPC probe: failed`?](#why-does-openclaw-gateway-status-say-runtime-running-but-rpc-probe-failed) - [Why does `openclaw gateway status` show `Config (cli)` and `Config (service)` different?](#why-does-openclaw-gateway-status-show-config-cli-and-config-service-different) - - [What does “another gateway instance is already listening” mean?](#what-does-another-gateway-instance-is-already-listening-mean) + - [What does "another gateway instance is already listening" mean?](#what-does-another-gateway-instance-is-already-listening-mean) - [How do I run OpenClaw in remote mode (client connects to a Gateway elsewhere)?](#how-do-i-run-openclaw-in-remote-mode-client-connects-to-a-gateway-elsewhere) - - [The Control UI says “unauthorized” (or keeps reconnecting). What now?](#the-control-ui-says-unauthorized-or-keeps-reconnecting-what-now) - - [I set `gateway.bind: "tailnet"` but it can’t bind / nothing listens](#i-set-gatewaybind-tailnet-but-it-cant-bind-nothing-listens) + - [The Control UI says "unauthorized" (or keeps reconnecting). What now?](#the-control-ui-says-unauthorized-or-keeps-reconnecting-what-now) + - [I set `gateway.bind: "tailnet"` but it can't bind / nothing listens](#i-set-gatewaybind-tailnet-but-it-cant-bind-nothing-listens) - [Can I run multiple Gateways on the same host?](#can-i-run-multiple-gateways-on-the-same-host) - - [What does “invalid handshake” / code 1008 mean?](#what-does-invalid-handshake-code-1008-mean) + - [What does "invalid handshake" / code 1008 mean?](#what-does-invalid-handshake-code-1008-mean) - [Logging and debugging](#logging-and-debugging) - [Where are logs?](#where-are-logs) - [How do I start/stop/restart the Gateway service?](#how-do-i-startstoprestart-the-gateway-service) @@ -178,7 +178,7 @@ Quick answers plus deeper troubleshooting for real-world setups (local dev, VPS, - [TUI shows no output. What should I check?](#tui-shows-no-output-what-should-i-check) - [How do I completely stop then start the Gateway?](#how-do-i-completely-stop-then-start-the-gateway) - [ELI5: `openclaw gateway restart` vs `openclaw gateway`](#eli5-openclaw-gateway-restart-vs-openclaw-gateway) - - [What’s the fastest way to get more details when something fails?](#whats-the-fastest-way-to-get-more-details-when-something-fails) + - [What's the fastest way to get more details when something fails?](#whats-the-fastest-way-to-get-more-details-when-something-fails) - [Media & attachments](#media-attachments) - [My skill generated an image/PDF, but nothing was sent](#my-skill-generated-an-imagepdf-but-nothing-was-sent) - [Security and access control](#security-and-access-control) @@ -187,13 +187,13 @@ Quick answers plus deeper troubleshooting for real-world setups (local dev, VPS, - [Should my bot have its own email GitHub account or phone number](#should-my-bot-have-its-own-email-github-account-or-phone-number) - [Can I give it autonomy over my text messages and is that safe](#can-i-give-it-autonomy-over-my-text-messages-and-is-that-safe) - [Can I use cheaper models for personal assistant tasks?](#can-i-use-cheaper-models-for-personal-assistant-tasks) - - [I ran `/start` in Telegram but didn’t get a pairing code](#i-ran-start-in-telegram-but-didnt-get-a-pairing-code) + - [I ran `/start` in Telegram but didn't get a pairing code](#i-ran-start-in-telegram-but-didnt-get-a-pairing-code) - [WhatsApp: will it message my contacts? How does pairing work?](#whatsapp-will-it-message-my-contacts-how-does-pairing-work) -- [Chat commands, aborting tasks, and “it won’t stop”](#chat-commands-aborting-tasks-and-it-wont-stop) +- [Chat commands, aborting tasks, and "it won't stop"](#chat-commands-aborting-tasks-and-it-wont-stop) - [How do I stop internal system messages from showing in chat](#how-do-i-stop-internal-system-messages-from-showing-in-chat) - [How do I stop/cancel a running task?](#how-do-i-stopcancel-a-running-task) - - [How do I send a Discord message from Telegram? (“Cross-context messaging denied”)](#how-do-i-send-a-discord-message-from-telegram-crosscontext-messaging-denied) - - [Why does it feel like the bot “ignores” rapid‑fire messages?](#why-does-it-feel-like-the-bot-ignores-rapidfire-messages) + - [How do I send a Discord message from Telegram? ("Cross-context messaging denied")](#how-do-i-send-a-discord-message-from-telegram-crosscontext-messaging-denied) + - [Why does it feel like the bot "ignores" rapid-fire messages?](#why-does-it-feel-like-the-bot-ignores-rapidfire-messages) ## First 60 seconds if something's broken @@ -330,11 +330,11 @@ pnpm ui:build # auto-installs UI deps on first run openclaw onboard ``` -If you don’t have a global install yet, run it via `pnpm openclaw onboard`. +If you don't have a global install yet, run it via `pnpm openclaw onboard`. ### How do I open the dashboard after onboarding -The wizard now opens your browser with a tokenized dashboard URL right after onboarding and also prints the full link (with token) in the summary. Keep that tab open; if it didn’t launch, copy/paste the printed URL on the same machine. Tokens stay local to your host-nothing is fetched from the browser. +The wizard now opens your browser with a tokenized dashboard URL right after onboarding and also prints the full link (with token) in the summary. Keep that tab open; if it didn't launch, copy/paste the printed URL on the same machine. Tokens stay local to your host-nothing is fetched from the browser. ### How do I authenticate the dashboard token on localhost vs remote @@ -361,7 +361,7 @@ Node **>= 22** is required. `pnpm` is recommended. Bun is **not recommended** fo Yes. The Gateway is lightweight - docs list **512MB-1GB RAM**, **1 core**, and about **500MB** disk as enough for personal use, and note that a **Raspberry Pi 4 can run it**. -If you want extra headroom (logs, media, other services), **2GB is recommended**, but it’s +If you want extra headroom (logs, media, other services), **2GB is recommended**, but it's not a hard minimum. Tip: a small Pi/VPS can host the Gateway, and you can pair **nodes** on your laptop/phone for @@ -410,7 +410,7 @@ is pointed at the right Gateway. See [Remote access](/gateway/remote). ### Can I migrate my setup to a new machine Mac mini without redoing onboarding Yes. Copy the **state directory** and **workspace**, then run Doctor once. This -keeps your bot “exactly the same” (memory, session history, auth, and channel +keeps your bot "exactly the same" (memory, session history, auth, and channel state) as long as you copy **both** locations: 1. Install OpenClaw on the new machine. @@ -418,10 +418,10 @@ state) as long as you copy **both** locations: 3. Copy your workspace (default: `~/.openclaw/workspace`). 4. Run `openclaw doctor` and restart the Gateway service. -That preserves config, auth profiles, WhatsApp creds, sessions, and memory. If you’re in +That preserves config, auth profiles, WhatsApp creds, sessions, and memory. If you're in remote mode, remember the gateway host owns the session store and workspace. -**Important:** if you only commit/push your workspace to GitHub, you’re backing +**Important:** if you only commit/push your workspace to GitHub, you're backing up **memory + bootstrap files**, but **not** session history or auth. Those live under `~/.openclaw/` (for example `~/.openclaw/agents//sessions/`). @@ -431,7 +431,7 @@ Related: [Migrating](/install/migrating), [Where things live on disk](/help/faq# ### Where do I see what is new in the latest version -Check the GitHub changelog: +Check the GitHub changelog: https://github.com/openclaw/openclaw/blob/main/CHANGELOG.md Newest entries are at the top. If the top section is marked **Unreleased**, the next dated @@ -450,24 +450,24 @@ https://github.com/openclaw/openclaw/tree/main/docs ### What's the difference between stable and beta -**Stable** and **beta** are **npm dist‑tags**, not separate code lines: +**Stable** and **beta** are **npm dist-tags**, not separate code lines: - `latest` = stable - `beta` = early build for testing We ship builds to **beta**, test them, and once a build is solid we **promote -that same version to `latest`**. That’s why beta and stable can point at the +that same version to `latest`**. That's why beta and stable can point at the **same version**. -See what changed: +See what changed: https://github.com/openclaw/openclaw/blob/main/CHANGELOG.md ### How do I install the beta version and whats the difference between beta and dev -**Beta** is the npm dist‑tag `beta` (may match `latest`). -**Dev** is the moving head of `main` (git); when published, it uses the npm dist‑tag `dev`. +**Beta** is the npm dist-tag `beta` (may match `latest`). +**Dev** is the moving head of `main` (git); when published, it uses the npm dist-tag `dev`. -One‑liners (macOS/Linux): +One-liners (macOS/Linux): ```bash curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash -s -- --beta @@ -591,7 +591,7 @@ Short answer: follow the Linux guide, then run the onboarding wizard. Any Linux VPS works. Install on the server, then use SSH/Tailscale to reach the Gateway. -Guides: [exe.dev](/platforms/exe-dev), [Hetzner](/platforms/hetzner), [Fly.io](/platforms/fly). +Guides: [exe.dev](/platforms/exe-dev), [Hetzner](/platforms/hetzner), [Fly.io](/platforms/fly). Remote access: [Gateway remote](/gateway/remote). ### Where are the cloudVPS install guides @@ -655,7 +655,7 @@ It also warns if your configured model is unknown or missing auth. ### Do I need a Claude or OpenAI subscription to run this No. You can run OpenClaw with **API keys** (Anthropic/OpenAI/others) or with -**local‑only models** so your data stays on your device. Subscriptions (Claude +**local-only models** so your data stays on your device. Subscriptions (Claude Pro/Max or OpenAI Codex) are optional ways to authenticate those providers. Docs: [Anthropic](/providers/anthropic), [OpenAI](/providers/openai), @@ -687,23 +687,23 @@ Copy the token it prints, then choose **Anthropic token (paste setup-token)** in ### Do you support Claude subscription auth (Claude Pro/Max) -Yes — via **setup-token**. OpenClaw no longer reuses Claude Code CLI OAuth tokens; use a setup-token or an Anthropic API key. Generate the token anywhere and paste it on the gateway host. See [Anthropic](/providers/anthropic) and [OAuth](/concepts/oauth). +Yes - via **setup-token**. OpenClaw no longer reuses Claude Code CLI OAuth tokens; use a setup-token or an Anthropic API key. Generate the token anywhere and paste it on the gateway host. See [Anthropic](/providers/anthropic) and [OAuth](/concepts/oauth). -Note: Claude subscription access is governed by Anthropic’s terms. For production or multi‑user workloads, API keys are usually the safer choice. +Note: Claude subscription access is governed by Anthropic's terms. For production or multi-user workloads, API keys are usually the safer choice. ### Why am I seeing HTTP 429 ratelimiterror from Anthropic That means your **Anthropic quota/rate limit** is exhausted for the current window. If you -use a **Claude subscription** (setup‑token or Claude Code OAuth), wait for the window to +use a **Claude subscription** (setup-token or Claude Code OAuth), wait for the window to reset or upgrade your plan. If you use an **Anthropic API key**, check the Anthropic Console for usage/billing and raise limits as needed. -Tip: set a **fallback model** so OpenClaw can keep replying while a provider is rate‑limited. +Tip: set a **fallback model** so OpenClaw can keep replying while a provider is rate-limited. See [Models](/cli/models) and [OAuth](/concepts/oauth). ### Is AWS Bedrock supported -Yes - via pi‑ai’s **Amazon Bedrock (Converse)** provider with **manual config**. You must supply AWS credentials/region on the gateway host and add a Bedrock provider entry in your models config. See [Amazon Bedrock](/bedrock) and [Model providers](/providers/models). If you prefer a managed key flow, an OpenAI‑compatible proxy in front of Bedrock is still a valid option. +Yes - via pi-ai's **Amazon Bedrock (Converse)** provider with **manual config**. You must supply AWS credentials/region on the gateway host and add a Bedrock provider entry in your models config. See [Amazon Bedrock](/bedrock) and [Model providers](/providers/models). If you prefer a managed key flow, an OpenAI-compatible proxy in front of Bedrock is still a valid option. ### How does Codex auth work @@ -738,38 +738,34 @@ Pick region-pinned endpoints. OpenRouter exposes US-hosted options for MiniMax, ### Do I have to buy a Mac Mini to install this No. OpenClaw runs on macOS or Linux (Windows via WSL2). A Mac mini is optional - some people -buy one as an always‑on host, but a small VPS, home server, or Raspberry Pi‑class box works too. +buy one as an always-on host, but a small VPS, home server, or Raspberry Pi-class box works too. -You only need a Mac **for macOS‑only tools**. For iMessage, you can keep the Gateway on Linux -and run `imsg` on any Mac over SSH by pointing `channels.imessage.cliPath` at an SSH wrapper. -If you want other macOS‑only tools, run the Gateway on a Mac or pair a macOS node. +You only need a Mac **for macOS-only tools**. For iMessage, use [BlueBubbles](/channels/bluebubbles) (recommended) - the BlueBubbles server runs on any Mac, and the Gateway can run on Linux or elsewhere. If you want other macOS-only tools, run the Gateway on a Mac or pair a macOS node. -Docs: [iMessage](/channels/imessage), [Nodes](/nodes), [Mac remote mode](/platforms/mac/remote). +Docs: [BlueBubbles](/channels/bluebubbles), [Nodes](/nodes), [Mac remote mode](/platforms/mac/remote). ### Do I need a Mac mini for iMessage support You need **some macOS device** signed into Messages. It does **not** have to be a Mac mini - -any Mac works. OpenClaw’s iMessage integrations run on macOS (BlueBubbles or `imsg`), while -the Gateway can run elsewhere. +any Mac works. **Use [BlueBubbles](/channels/bluebubbles)** (recommended) for iMessage - the BlueBubbles server runs on macOS, while the Gateway can run on Linux or elsewhere. Common setups: -- Run the Gateway on Linux/VPS, and point `channels.imessage.cliPath` at an SSH wrapper that - runs `imsg` on the Mac. +- Run the Gateway on Linux/VPS, and run the BlueBubbles server on any Mac signed into Messages. - Run everything on the Mac if you want the simplest single‑machine setup. -Docs: [iMessage](/channels/imessage), [BlueBubbles](/channels/bluebubbles), +Docs: [BlueBubbles](/channels/bluebubbles), [Nodes](/nodes), [Mac remote mode](/platforms/mac/remote). ### If I buy a Mac mini to run OpenClaw can I connect it to my MacBook Pro Yes. The **Mac mini can run the Gateway**, and your MacBook Pro can connect as a -**node** (companion device). Nodes don’t run the Gateway - they provide extra +**node** (companion device). Nodes don't run the Gateway - they provide extra capabilities like screen/camera/canvas and `system.run` on that device. Common pattern: -- Gateway on the Mac mini (always‑on). +- Gateway on the Mac mini (always-on). - MacBook Pro runs the macOS app or a node host and pairs to the Gateway. - Use `openclaw nodes status` / `openclaw nodes list` to see it. @@ -780,12 +776,12 @@ Docs: [Nodes](/nodes), [Nodes CLI](/cli/nodes). Bun is **not recommended**. We see runtime bugs, especially with WhatsApp and Telegram. Use **Node** for stable gateways. -If you still want to experiment with Bun, do it on a non‑production gateway +If you still want to experiment with Bun, do it on a non-production gateway without WhatsApp/Telegram. ### Telegram what goes in allowFrom -`channels.telegram.allowFrom` is **the human sender’s Telegram user ID** (numeric, recommended) or `@username`. It is not the bot username. +`channels.telegram.allowFrom` is **the human sender's Telegram user ID** (numeric, recommended) or `@username`. It is not the bot username. Safer (no third-party bot): @@ -803,11 +799,11 @@ See [/channels/telegram](/channels/telegram#access-control-dms--groups). ### Can multiple people use one WhatsApp number with different OpenClaw instances -Yes, via **multi‑agent routing**. Bind each sender’s WhatsApp **DM** (peer `kind: "dm"`, sender E.164 like `+15551234567`) to a different `agentId`, so each person gets their own workspace and session store. Replies still come from the **same WhatsApp account**, and DM access control (`channels.whatsapp.dmPolicy` / `channels.whatsapp.allowFrom`) is global per WhatsApp account. See [Multi-Agent Routing](/concepts/multi-agent) and [WhatsApp](/channels/whatsapp). +Yes, via **multi-agent routing**. Bind each sender's WhatsApp **DM** (peer `kind: "dm"`, sender E.164 like `+15551234567`) to a different `agentId`, so each person gets their own workspace and session store. Replies still come from the **same WhatsApp account**, and DM access control (`channels.whatsapp.dmPolicy` / `channels.whatsapp.allowFrom`) is global per WhatsApp account. See [Multi-Agent Routing](/concepts/multi-agent) and [WhatsApp](/channels/whatsapp). ### Can I run a fast chat agent and an Opus for coding agent -Yes. Use multi‑agent routing: give each agent its own default model, then bind inbound routes (provider account or specific peers) to each agent. Example config lives in [Multi-Agent Routing](/concepts/multi-agent). See also [Models](/concepts/models) and [Configuration](/gateway/configuration). +Yes. Use multi-agent routing: give each agent its own default model, then bind inbound routes (provider account or specific peers) to each agent. Example config lives in [Multi-Agent Routing](/concepts/multi-agent). See also [Models](/concepts/models) and [Configuration](/gateway/configuration). ### Does Homebrew work on Linux @@ -820,15 +816,15 @@ eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" brew install ``` -If you run OpenClaw via systemd, ensure the service PATH includes `/home/linuxbrew/.linuxbrew/bin` (or your brew prefix) so `brew`-installed tools resolve in non‑login shells. +If you run OpenClaw via systemd, ensure the service PATH includes `/home/linuxbrew/.linuxbrew/bin` (or your brew prefix) so `brew`-installed tools resolve in non-login shells. Recent builds also prepend common user bin dirs on Linux systemd services (for example `~/.local/bin`, `~/.npm-global/bin`, `~/.local/share/pnpm`, `~/.bun/bin`) and honor `PNPM_HOME`, `NPM_CONFIG_PREFIX`, `BUN_INSTALL`, `VOLTA_HOME`, `ASDF_DATA_DIR`, `NVM_DIR`, and `FNM_DIR` when set. ### What's the difference between the hackable git install and npm install - **Hackable (git) install:** full source checkout, editable, best for contributors. You run builds locally and can patch code/docs. -- **npm install:** global CLI install, no repo, best for “just run it.” - Updates come from npm dist‑tags. +- **npm install:** global CLI install, no repo, best for "just run it." + Updates come from npm dist-tags. Docs: [Getting started](/start/getting-started), [Updating](/install/updating). @@ -864,7 +860,7 @@ Backup tips: see [Backup strategy](/help/faq#whats-the-recommended-backup-strate ### Should I run the Gateway on my laptop or a VPS Short answer: **if you want 24/7 reliability, use a VPS**. If you want the -lowest friction and you’re okay with sleep/restarts, run it locally. +lowest friction and you're okay with sleep/restarts, run it locally. **Laptop (local Gateway)** @@ -873,18 +869,18 @@ lowest friction and you’re okay with sleep/restarts, run it locally. **VPS / cloud** -- **Pros:** always‑on, stable network, no laptop sleep issues, easier to keep running. +- **Pros:** always-on, stable network, no laptop sleep issues, easier to keep running. - **Cons:** often run headless (use screenshots), remote file access only, you must SSH for updates. **OpenClaw-specific note:** WhatsApp/Telegram/Slack/Mattermost (plugin)/Discord all work fine from a VPS. The only real trade-off is **headless browser** vs a visible window. See [Browser](/tools/browser). -**Recommended default:** VPS if you had gateway disconnects before. Local is great when you’re actively using the Mac and want local file access or UI automation with a visible browser. +**Recommended default:** VPS if you had gateway disconnects before. Local is great when you're actively using the Mac and want local file access or UI automation with a visible browser. ### How important is it to run OpenClaw on a dedicated machine Not required, but **recommended for reliability and isolation**. -- **Dedicated host (VPS/Mac mini/Pi):** always‑on, fewer sleep/reboot interruptions, cleaner permissions, easier to keep running. +- **Dedicated host (VPS/Mac mini/Pi):** always-on, fewer sleep/reboot interruptions, cleaner permissions, easier to keep running. - **Shared laptop/desktop:** totally fine for testing and active use, but expect pauses when the machine sleeps or updates. If you want the best of both worlds, keep the Gateway on a dedicated host and pair your laptop as a **node** for local screen/camera/exec tools. See [Nodes](/nodes). @@ -924,7 +920,7 @@ OpenClaw is a personal AI assistant you run on your own devices. It replies on t ### What's the value proposition -OpenClaw is not “just a Claude wrapper.” It’s a **local-first control plane** that lets you run a +OpenClaw is not "just a Claude wrapper." It's a **local-first control plane** that lets you run a capable assistant on **your own hardware**, reachable from the chat apps you already use, with stateful sessions, memory, and tools - without handing control of your workflows to a hosted SaaS. @@ -935,14 +931,14 @@ Highlights: workspace + session history local. - **Real channels, not a web sandbox:** WhatsApp/Telegram/Slack/Discord/Signal/iMessage/etc, plus mobile voice and Canvas on supported platforms. -- **Model-agnostic:** use Anthropic, OpenAI, MiniMax, OpenRouter, etc., with per‑agent routing +- **Model-agnostic:** use Anthropic, OpenAI, MiniMax, OpenRouter, etc., with per-agent routing and failover. - **Local-only option:** run local models so **all data can stay on your device** if you want. - **Multi-agent routing:** separate agents per channel, account, or task, each with its own workspace and defaults. -- **Open source and hackable:** inspect, extend, and self-host without vendor lock‑in. +- **Open source and hackable:** inspect, extend, and self-host without vendor lock-in. -Docs: [Gateway](/gateway), [Channels](/channels), [Multi‑agent](/concepts/multi-agent), +Docs: [Gateway](/gateway), [Channels](/channels), [Multi-agent](/concepts/multi-agent), [Memory](/concepts/memory). ### I just set it up what should I do first @@ -1049,7 +1045,7 @@ Docs: [Cron jobs](/automation/cron-jobs), [Cron vs Heartbeat](/automation/cron-v ### How do I install skills on Linux -Use **ClawHub** (CLI) or drop skills into your workspace. The macOS Skills UI isn’t available on Linux. +Use **ClawHub** (CLI) or drop skills into your workspace. The macOS Skills UI isn't available on Linux. Browse skills at https://clawhub.com. Install the ClawHub CLI (pick one package manager): @@ -1067,7 +1063,7 @@ pnpm add -g clawhub Yes. Use the Gateway scheduler: - **Cron jobs** for scheduled or recurring tasks (persist across restarts). -- **Heartbeat** for “main session” periodic checks. +- **Heartbeat** for "main session" periodic checks. - **Isolated jobs** for autonomous agents that post summaries or deliver to chats. Docs: [Cron jobs](/automation/cron-jobs), [Cron vs Heartbeat](/automation/cron-vs-heartbeat), @@ -1075,41 +1071,39 @@ Docs: [Cron jobs](/automation/cron-jobs), [Cron vs Heartbeat](/automation/cron-v **Can I run Apple macOS only skills from Linux** -Not directly. macOS skills are gated by `metadata.openclaw.os` plus required binaries, and skills only appear in the system prompt when they are eligible on the **Gateway host**. On Linux, `darwin`-only skills (like `imsg`, `apple-notes`, `apple-reminders`) will not load unless you override the gating. +Not directly. macOS skills are gated by `metadata.openclaw.os` plus required binaries, and skills only appear in the system prompt when they are eligible on the **Gateway host**. On Linux, `darwin`-only skills (like `apple-notes`, `apple-reminders`, `things-mac`) will not load unless you override the gating. You have three supported patterns: -**Option A - run the Gateway on a Mac (simplest).** +**Option A - run the Gateway on a Mac (simplest).** Run the Gateway where the macOS binaries exist, then connect from Linux in [remote mode](#how-do-i-run-openclaw-in-remote-mode-client-connects-to-a-gateway-elsewhere) or over Tailscale. The skills load normally because the Gateway host is macOS. -**Option B - use a macOS node (no SSH).** +**Option B - use a macOS node (no SSH).** Run the Gateway on Linux, pair a macOS node (menubar app), and set **Node Run Commands** to "Always Ask" or "Always Allow" on the Mac. OpenClaw can treat macOS-only skills as eligible when the required binaries exist on the node. The agent runs those skills via the `nodes` tool. If you choose "Always Ask", approving "Always Allow" in the prompt adds that command to the allowlist. -**Option C - proxy macOS binaries over SSH (advanced).** +**Option C - proxy macOS binaries over SSH (advanced).** Keep the Gateway on Linux, but make the required CLI binaries resolve to SSH wrappers that run on a Mac. Then override the skill to allow Linux so it stays eligible. -1. Create an SSH wrapper for the binary (example: `imsg`): +1. Create an SSH wrapper for the binary (example: `memo` for Apple Notes): ```bash #!/usr/bin/env bash set -euo pipefail - exec ssh -T user@mac-host /opt/homebrew/bin/imsg "$@" + exec ssh -T user@mac-host /opt/homebrew/bin/memo "$@" ``` -2. Put the wrapper on `PATH` on the Linux host (for example `~/bin/imsg`). +2. Put the wrapper on `PATH` on the Linux host (for example `~/bin/memo`). 3. Override the skill metadata (workspace or `~/.openclaw/skills`) to allow Linux: ```markdown --- - name: imsg - description: iMessage/SMS CLI for listing chats, history, watch, and sending. - metadata: { "openclaw": { "os": ["darwin", "linux"], "requires": { "bins": ["imsg"] } } } + name: apple-notes + description: Manage Apple Notes via the memo CLI on macOS. + metadata: { "openclaw": { "os": ["darwin", "linux"], "requires": { "bins": ["memo"] } } } --- ``` 4. Start a new session so the skills snapshot refreshes. -For iMessage specifically, you can also point `channels.imessage.cliPath` at an SSH wrapper (OpenClaw only needs stdio). See [iMessage](/channels/imessage). - ### Do you have a Notion or HeyGen integration -Not built‑in today. +Not built-in today. Options: @@ -1142,13 +1136,13 @@ openclaw browser extension install openclaw browser extension path ``` -Then Chrome → `chrome://extensions` → enable “Developer mode” → “Load unpacked” → pick that folder. +Then Chrome → `chrome://extensions` → enable "Developer mode" → "Load unpacked" → pick that folder. Full guide (including remote Gateway + security notes): [Chrome extension](/tools/chrome-extension) If the Gateway runs on the same machine as Chrome (default setup), you usually **do not** need anything extra. If the Gateway runs elsewhere, run a node host on the browser machine so the Gateway can proxy browser actions. -You still need to click the extension button on the tab you want to control (it doesn’t auto-attach). +You still need to click the extension button on the tab you want to control (it doesn't auto-attach). ## Sandboxing and memory @@ -1212,14 +1206,14 @@ does **not** grant embeddings access, so **signing in with Codex (OAuth or the Codex CLI login)** does not help for semantic memory search. OpenAI embeddings still need a real API key (`OPENAI_API_KEY` or `models.providers.openai.apiKey`). -If you don’t set a provider explicitly, OpenClaw auto-selects a provider when it +If you don't set a provider explicitly, OpenClaw auto-selects a provider when it can resolve an API key (auth profiles, `models.providers.*.apiKey`, or env vars). It prefers OpenAI if an OpenAI key resolves, otherwise Gemini if a Gemini key resolves. If neither key is available, memory search stays disabled until you configure it. If you have a local model path configured and present, OpenClaw prefers `local`. -If you’d rather stay local, set `memorySearch.provider = "local"` (and optionally +If you'd rather stay local, set `memorySearch.provider = "local"` (and optionally `memorySearch.fallback = "none"`). If you want Gemini embeddings, set `memorySearch.provider = "gemini"` and provide `GEMINI_API_KEY` (or `memorySearch.remote.apiKey`). We support **OpenAI, Gemini, or local** embedding @@ -1238,7 +1232,7 @@ Docs: [Memory](/concepts/memory), [Context](/concepts/context). ### Is all data used with OpenClaw saved locally -No - **OpenClaw’s state is local**, but **external services still see what you send them**. +No - **OpenClaw's state is local**, but **external services still see what you send them**. - **Local by default:** sessions, memory files, config, and workspace live on the Gateway host (`~/.openclaw` + your workspace directory). @@ -1246,7 +1240,7 @@ No - **OpenClaw’s state is local**, but **external services still see what you their APIs, and chat platforms (WhatsApp/Telegram/Slack/etc.) store message data on their servers. - **You control the footprint:** using local models keeps prompts on your machine, but channel - traffic still goes through the channel’s servers. + traffic still goes through the channel's servers. Related: [Agent workspace](/concepts/agent-workspace), [Memory](/concepts/memory). @@ -1261,11 +1255,11 @@ Everything lives under `$OPENCLAW_STATE_DIR` (default: `~/.openclaw`): | `$OPENCLAW_STATE_DIR/agents//agent/auth-profiles.json` | Auth profiles (OAuth + API keys) | | `$OPENCLAW_STATE_DIR/agents//agent/auth.json` | Runtime auth cache (managed automatically) | | `$OPENCLAW_STATE_DIR/credentials/` | Provider state (e.g. `whatsapp//creds.json`) | -| `$OPENCLAW_STATE_DIR/agents/` | Per‑agent state (agentDir + sessions) | +| `$OPENCLAW_STATE_DIR/agents/` | Per-agent state (agentDir + sessions) | | `$OPENCLAW_STATE_DIR/agents//sessions/` | Conversation history & state (per agent) | | `$OPENCLAW_STATE_DIR/agents//sessions/sessions.json` | Session metadata (per agent) | -Legacy single‑agent path: `~/.openclaw/agent/*` (migrated by `openclaw doctor`). +Legacy single-agent path: `~/.openclaw/agent/*` (migrated by `openclaw doctor`). Your **workspace** (AGENTS.md, memory files, skills, etc.) is separate and configured via `agents.defaults.workspace` (default: `~/.openclaw/workspace`). @@ -1286,8 +1280,8 @@ Default workspace is `~/.openclaw/workspace`, configurable via: } ``` -If the bot “forgets” after a restart, confirm the Gateway is using the same -workspace on every launch (and remember: remote mode uses the **gateway host’s** +If the bot "forgets" after a restart, confirm the Gateway is using the same +workspace on every launch (and remember: remote mode uses the **gateway host's** workspace, not your local laptop). Tip: if you want a durable behavior or preference, ask the bot to **write it into @@ -1299,7 +1293,7 @@ See [Agent workspace](/concepts/agent-workspace) and [Memory](/concepts/memory). Put your **agent workspace** in a **private** git repo and back it up somewhere private (for example GitHub private). This captures memory + AGENTS/SOUL/USER -files, and lets you restore the assistant’s “mind” later. +files, and lets you restore the assistant's "mind" later. Do **not** commit anything under `~/.openclaw` (credentials, sessions, tokens). If you need a full restore, back up both the workspace and the state directory @@ -1316,8 +1310,8 @@ See the dedicated guide: [Uninstall](/install/uninstall). Yes. The workspace is the **default cwd** and memory anchor, not a hard sandbox. Relative paths resolve inside the workspace, but absolute paths can access other host locations unless sandboxing is enabled. If you need isolation, use -[`agents.defaults.sandbox`](/gateway/sandboxing) or per‑agent sandbox settings. If you -want a repo to be the default working directory, point that agent’s +[`agents.defaults.sandbox`](/gateway/sandboxing) or per-agent sandbox settings. If you +want a repo to be the default working directory, point that agent's `workspace` to the repo root. The OpenClaw repo is just source code; keep the workspace separate unless you intentionally want the agent to work inside it. @@ -1335,7 +1329,7 @@ Example (repo as default cwd): ### Im in remote mode where is the session store -Session state is owned by the **gateway host**. If you’re in remote mode, the session store you care about is on the remote machine, not your local laptop. See [Session management](/concepts/session). +Session state is owned by the **gateway host**. If you're in remote mode, the session store you care about is on the remote machine, not your local laptop. See [Session management](/concepts/session). ## Config basics @@ -1347,7 +1341,7 @@ OpenClaw reads an optional **JSON5** config from `$OPENCLAW_CONFIG_PATH` (defaul $OPENCLAW_CONFIG_PATH ``` -If the file is missing, it uses safe‑ish defaults (including a default workspace of `~/.openclaw/workspace`). +If the file is missing, it uses safe-ish defaults (including a default workspace of `~/.openclaw/workspace`). ### I set gatewaybind lan or tailnet and now nothing listens the UI says unauthorized @@ -1378,9 +1372,9 @@ If you **really** want open loopback, remove `gateway.auth` from your config. Do ### Do I have to restart after changing config -The Gateway watches the config and supports hot‑reload: +The Gateway watches the config and supports hot-reload: -- `gateway.reload.mode: "hybrid"` (default): hot‑apply safe changes, restart for critical ones +- `gateway.reload.mode: "hybrid"` (default): hot-apply safe changes, restart for critical ones - `hot`, `restart`, `off` are also supported ### How do I enable web search and web fetch @@ -1421,15 +1415,15 @@ The common pattern is **one Gateway** (e.g. Raspberry Pi) plus **nodes** and **a - **Gateway (central):** owns channels (Signal/WhatsApp), routing, and sessions. - **Nodes (devices):** Macs/iOS/Android connect as peripherals and expose local tools (`system.run`, `canvas`, `camera`). -- **Agents (workers):** separate brains/workspaces for special roles (e.g. “Hetzner ops”, “Personal data”). -- **Sub‑agents:** spawn background work from a main agent when you want parallelism. +- **Agents (workers):** separate brains/workspaces for special roles (e.g. "Hetzner ops", "Personal data"). +- **Sub-agents:** spawn background work from a main agent when you want parallelism. - **TUI:** connect to the Gateway and switch agents/sessions. Docs: [Nodes](/nodes), [Remote access](/gateway/remote), [Multi-Agent Routing](/concepts/multi-agent), [Sub-agents](/tools/subagents), [TUI](/tui). ### Can the OpenClaw browser run headless -Yes. It’s a config option: +Yes. It's a config option: ```json5 { @@ -1442,12 +1436,12 @@ Yes. It’s a config option: } ``` -Default is `false` (headful). Headless is more likely to trigger anti‑bot checks on some sites. See [Browser](/tools/browser). +Default is `false` (headful). Headless is more likely to trigger anti-bot checks on some sites. See [Browser](/tools/browser). Headless uses the **same Chromium engine** and works for most automation (forms, clicks, scraping, logins). The main differences: - No visible browser window (use screenshots if you need visuals). -- Some sites are stricter about automation in headless mode (CAPTCHAs, anti‑bot). +- Some sites are stricter about automation in headless mode (CAPTCHAs, anti-bot). For example, X/Twitter often blocks headless sessions. ### How do I use Brave for browser control @@ -1464,7 +1458,7 @@ only then calls nodes over the **Gateway WebSocket** when a node tool is needed: Telegram → Gateway → Agent → `node.*` → Node → Gateway → Telegram -Nodes don’t see inbound provider traffic; they only receive node RPC calls. +Nodes don't see inbound provider traffic; they only receive node RPC calls. ### How can my agent access my computer if the Gateway is hosted remotely @@ -1473,7 +1467,7 @@ call `node.*` tools (screen, camera, system) on your local machine over the Gate Typical setup: -1. Run the Gateway on the always‑on host (VPS/home server). +1. Run the Gateway on the always-on host (VPS/home server). 2. Put the Gateway host + your computer on the same tailnet. 3. Ensure the Gateway WS is reachable (tailnet bind or SSH tunnel). 4. Open the macOS app locally and connect in **Remote over SSH** mode (or direct tailnet) @@ -1543,10 +1537,10 @@ use multiple agents or sub-agents. ### Is there a benefit to using a node on my personal laptop instead of SSH from a VPS -Yes - nodes are the first‑class way to reach your laptop from a remote Gateway, and they +Yes - nodes are the first-class way to reach your laptop from a remote Gateway, and they unlock more than shell access. The Gateway runs on macOS/Linux (Windows via WSL2) and is lightweight (a small VPS or Raspberry Pi-class box is fine; 4 GB RAM is plenty), so a common -setup is an always‑on host plus your laptop as a node. +setup is an always-on host plus your laptop as a node. - **No inbound SSH required.** Nodes connect out to the Gateway WebSocket and use device pairing. - **Safer execution controls.** `system.run` is gated by node allowlists/approvals on that laptop. @@ -1554,7 +1548,7 @@ setup is an always‑on host plus your laptop as a node. - **Local browser automation.** Keep the Gateway on a VPS, but run Chrome locally and relay control with the Chrome extension + a node host on the laptop. -SSH is fine for ad‑hoc shell access, but nodes are simpler for ongoing agent workflows and +SSH is fine for ad-hoc shell access, but nodes are simpler for ongoing agent workflows and device automation. Docs: [Nodes](/nodes), [Nodes CLI](/cli/nodes), [Chrome extension](/tools/chrome-extension). @@ -1572,7 +1566,7 @@ Docs: [Nodes](/nodes), [Nodes CLI](/cli/nodes), [Multiple gateways](/gateway/mul ### Do nodes run a gateway service No. Only **one gateway** should run per host unless you intentionally run isolated profiles (see [Multiple gateways](/gateway/multiple-gateways)). Nodes are peripherals that connect -to the gateway (iOS/Android nodes, or macOS “node mode” in the menubar app). For headless node +to the gateway (iOS/Android nodes, or macOS "node mode" in the menubar app). For headless node hosts and CLI control, see [Node host CLI](/cli/node). A full restart is required for `gateway`, `discovery`, and `canvasHost` changes. @@ -1681,8 +1675,8 @@ See [/environment](/environment) for full precedence and sources. Two common fixes: -1. Put the missing keys in `~/.openclaw/.env` so they’re picked up even when the service doesn’t inherit your shell env. -2. Enable shell import (opt‑in convenience): +1. Put the missing keys in `~/.openclaw/.env` so they're picked up even when the service doesn't inherit your shell env. +2. Enable shell import (opt-in convenience): ```json5 { @@ -1700,11 +1694,11 @@ This runs your login shell and imports only missing expected keys (never overrid ### I set COPILOTGITHUBTOKEN but models status shows Shell env off Why -`openclaw models status` reports whether **shell env import** is enabled. “Shell env: off” -does **not** mean your env vars are missing - it just means OpenClaw won’t load +`openclaw models status` reports whether **shell env import** is enabled. "Shell env: off" +does **not** mean your env vars are missing - it just means OpenClaw won't load your login shell automatically. -If the Gateway runs as a service (launchd/systemd), it won’t inherit your shell +If the Gateway runs as a service (launchd/systemd), it won't inherit your shell environment. Fix by doing one of these: 1. Put the token in `~/.openclaw/.env`: @@ -1851,7 +1845,7 @@ Per-agent overrides use `agents.list[].heartbeat`. Docs: [Heartbeat](/gateway/he ### Do I need to add a bot account to a WhatsApp group -No. OpenClaw runs on **your own account**, so if you’re in the group, OpenClaw can see it. +No. OpenClaw runs on **your own account**, so if you're in the group, OpenClaw can see it. By default, group replies are blocked until you allow senders (`groupPolicy: "allowlist"`). If you want only **you** to be able to trigger group replies: @@ -1891,7 +1885,7 @@ Docs: [WhatsApp](/channels/whatsapp), [Directory](/cli/directory), [Logs](/cli/l Two common causes: - Mention gating is on (default). You must @mention the bot (or match `mentionPatterns`). -- You configured `channels.whatsapp.groups` without `"*"` and the group isn’t allowlisted. +- You configured `channels.whatsapp.groups` without `"*"` and the group isn't allowlisted. See [Groups](/concepts/groups) and [Group messages](/concepts/group-messages). @@ -1915,28 +1909,28 @@ Tips: ### Can I run multiple bots or chats at the same time Slack and how should I set that up -Yes. Use **Multi‑Agent Routing** to run multiple isolated agents and route inbound messages by +Yes. Use **Multi-Agent Routing** to run multiple isolated agents and route inbound messages by channel/account/peer. Slack is supported as a channel and can be bound to specific agents. -Browser access is powerful but not “do anything a human can” - anti‑bot, CAPTCHAs, and MFA can +Browser access is powerful but not "do anything a human can" - anti-bot, CAPTCHAs, and MFA can still block automation. For the most reliable browser control, use the Chrome extension relay on the machine that runs the browser (and keep the Gateway anywhere). -Best‑practice setup: +Best-practice setup: -- Always‑on Gateway host (VPS/Mac mini). +- Always-on Gateway host (VPS/Mac mini). - One agent per role (bindings). - Slack channel(s) bound to those agents. - Local browser via extension relay (or a node) when needed. -Docs: [Multi‑Agent Routing](/concepts/multi-agent), [Slack](/channels/slack), +Docs: [Multi-Agent Routing](/concepts/multi-agent), [Slack](/channels/slack), [Browser](/tools/browser), [Chrome extension](/tools/chrome-extension), [Nodes](/nodes). ## Models: defaults, selection, aliases, switching ### What is the default model -OpenClaw’s default model is whatever you set as: +OpenClaw's default model is whatever you set as: ``` agents.defaults.model.primary @@ -1946,9 +1940,9 @@ Models are referenced as `provider/model` (example: `anthropic/claude-opus-4-5`) ### What model do you recommend -**Recommended default:** `anthropic/claude-opus-4-5`. -**Good alternative:** `anthropic/claude-sonnet-4-5`. -**Reliable (less character):** `openai/gpt-5.2` - nearly as good as Opus, just less personality. +**Recommended default:** `anthropic/claude-opus-4-5`. +**Good alternative:** `anthropic/claude-sonnet-4-5`. +**Reliable (less character):** `openai/gpt-5.2` - nearly as good as Opus, just less personality. **Budget:** `zai/glm-4.7`. MiniMax M2.1 has its own docs: [MiniMax](/providers/minimax) and @@ -2054,7 +2048,7 @@ See [Models](/concepts/models) and [Slash commands](/tools/slash-commands). ### Why do I see Model is not allowed and then no reply If `agents.defaults.models` is set, it becomes the **allowlist** for `/model` and any -session overrides. Choosing a model that isn’t in that list returns: +session overrides. Choosing a model that isn't in that list returns: ``` Model "provider/model" is not allowed. Use /model to list available models. @@ -2065,8 +2059,8 @@ That error is returned **instead of** a normal reply. Fix: add the model to ### Why do I see Unknown model minimaxMiniMaxM21 -This means the **provider isn’t configured** (no MiniMax provider config or auth -profile was found), so the model can’t be resolved. A fix for this detection is +This means the **provider isn't configured** (no MiniMax provider config or auth +profile was found), so the model can't be resolved. A fix for this detection is in **2026.1.12** (unreleased at the time of writing). Fix checklist: @@ -2074,7 +2068,7 @@ Fix checklist: 1. Upgrade to **2026.1.12** (or run from source `main`), then restart the gateway. 2. Make sure MiniMax is configured (wizard or JSON), or that a MiniMax API key exists in env/auth profiles so the provider can be injected. -3. Use the exact model id (case‑sensitive): `minimax/MiniMax-M2.1` or +3. Use the exact model id (case-sensitive): `minimax/MiniMax-M2.1` or `minimax/MiniMax-M2.1-lightning`. 4. Run: ```bash @@ -2087,7 +2081,7 @@ See [MiniMax](/providers/minimax) and [Models](/concepts/models). ### Can I use MiniMax as my default and OpenAI for complex tasks Yes. Use **MiniMax as the default** and switch models **per session** when needed. -Fallbacks are for **errors**, not “hard tasks,” so use `/model` or a separate agent. +Fallbacks are for **errors**, not "hard tasks," so use `/model` or a separate agent. **Option A: switch per session** @@ -2156,7 +2150,7 @@ Then `/model sonnet` (or `/` when supported) resolves to that model ID. ### How do I add models from other providers like OpenRouter or ZAI -OpenRouter (pay‑per‑token; many models): +OpenRouter (pay-per-token; many models): ```json5 { @@ -2184,7 +2178,7 @@ Z.AI (GLM models): } ``` -If you reference a provider/model but the required provider key is missing, you’ll get a runtime auth error (e.g. `No API key found for provider "zai"`). +If you reference a provider/model but the required provider key is missing, you'll get a runtime auth error (e.g. `No API key found for provider "zai"`). **No API key found for provider after adding a new agent** @@ -2198,11 +2192,11 @@ stored in: Fix options: - Run `openclaw agents add ` and configure auth during the wizard. -- Or copy `auth-profiles.json` from the main agent’s `agentDir` into the new agent’s `agentDir`. +- Or copy `auth-profiles.json` from the main agent's `agentDir` into the new agent's `agentDir`. Do **not** reuse `agentDir` across agents; it causes auth/session collisions. -## Model failover and “All models failed” +## Model failover and "All models failed" ### How does failover work @@ -2211,7 +2205,7 @@ Failover happens in two stages: 1. **Auth profile rotation** within the same provider. 2. **Model fallback** to the next model in `agents.defaults.model.fallbacks`. -Cooldowns apply to failing profiles (exponential backoff), so OpenClaw can keep responding even when a provider is rate‑limited or temporarily failing. +Cooldowns apply to failing profiles (exponential backoff), so OpenClaw can keep responding even when a provider is rate-limited or temporarily failing. ### What does this error mean @@ -2228,15 +2222,15 @@ It means the system attempted to use the auth profile ID `anthropic:default`, bu - Legacy: `~/.openclaw/agent/*` (migrated by `openclaw doctor`) - **Confirm your env var is loaded by the Gateway** - If you set `ANTHROPIC_API_KEY` in your shell but run the Gateway via systemd/launchd, it may not inherit it. Put it in `~/.openclaw/.env` or enable `env.shellEnv`. -- **Make sure you’re editing the correct agent** - - Multi‑agent setups mean there can be multiple `auth-profiles.json` files. -- **Sanity‑check model/auth status** +- **Make sure you're editing the correct agent** + - Multi-agent setups mean there can be multiple `auth-profiles.json` files. +- **Sanity-check model/auth status** - Use `openclaw models status` to see configured models and whether providers are authenticated. **Fix checklist for No credentials found for profile anthropic** This means the run is pinned to an Anthropic auth profile, but the Gateway -can’t find it in its auth store. +can't find it in its auth store. - **Use a setup-token** - Run `claude setup-token`, then paste it with `openclaw models auth setup-token --provider anthropic`. @@ -2247,14 +2241,14 @@ can’t find it in its auth store. ```bash openclaw models auth order clear --provider anthropic ``` -- **Confirm you’re running commands on the gateway host** +- **Confirm you're running commands on the gateway host** - In remote mode, auth profiles live on the gateway machine, not your laptop. ### Why did it also try Google Gemini and fail -If your model config includes Google Gemini as a fallback (or you switched to a Gemini shorthand), OpenClaw will try it during model fallback. If you haven’t configured Google credentials, you’ll see `No API key found for provider "google"`. +If your model config includes Google Gemini as a fallback (or you switched to a Gemini shorthand), OpenClaw will try it during model fallback. If you haven't configured Google credentials, you'll see `No API key found for provider "google"`. -Fix: either provide Google auth, or remove/avoid Google models in `agents.defaults.model.fallbacks` / aliases so fallback doesn’t route there. +Fix: either provide Google auth, or remove/avoid Google models in `agents.defaults.model.fallbacks` / aliases so fallback doesn't route there. **LLM request rejected message thinking signature required google antigravity** @@ -2277,7 +2271,7 @@ An auth profile is a named credential record (OAuth or API key) tied to a provid ### What are typical profile IDs -OpenClaw uses provider‑prefixed IDs like: +OpenClaw uses provider-prefixed IDs like: - `anthropic:default` (common when no email identity exists) - `anthropic:` for OAuth identities @@ -2287,9 +2281,9 @@ OpenClaw uses provider‑prefixed IDs like: Yes. Config supports optional metadata for profiles and an ordering per provider (`auth.order.`). This does **not** store secrets; it maps IDs to provider/mode and sets rotation order. -OpenClaw may temporarily skip a profile if it’s in a short **cooldown** (rate limits/timeouts/auth failures) or a longer **disabled** state (billing/insufficient credits). To inspect this, run `openclaw models status --json` and check `auth.unusableProfiles`. Tuning: `auth.cooldowns.billingBackoffHours*`. +OpenClaw may temporarily skip a profile if it's in a short **cooldown** (rate limits/timeouts/auth failures) or a longer **disabled** state (billing/insufficient credits). To inspect this, run `openclaw models status --json` and check `auth.unusableProfiles`. Tuning: `auth.cooldowns.billingBackoffHours*`. -You can also set a **per-agent** order override (stored in that agent’s `auth-profiles.json`) via the CLI: +You can also set a **per-agent** order override (stored in that agent's `auth-profiles.json`) via the CLI: ```bash # Defaults to the configured default agent (omit --agent) @@ -2316,11 +2310,11 @@ openclaw models auth order set --provider anthropic --agent main anthropic:defau OpenClaw supports both: - **OAuth** often leverages subscription access (where applicable). -- **API keys** use pay‑per‑token billing. +- **API keys** use pay-per-token billing. The wizard explicitly supports Anthropic setup-token and OpenAI Codex OAuth and can store API keys for you. -## Gateway: ports, “already running”, and remote mode +## Gateway: ports, "already running", and remote mode ### What port does the Gateway use @@ -2334,17 +2328,17 @@ Precedence: ### Why does openclaw gateway status say Runtime running but RPC probe failed -Because “running” is the **supervisor’s** view (launchd/systemd/schtasks). The RPC probe is the CLI actually connecting to the gateway WebSocket and calling `status`. +Because "running" is the **supervisor's** view (launchd/systemd/schtasks). The RPC probe is the CLI actually connecting to the gateway WebSocket and calling `status`. Use `openclaw gateway status` and trust these lines: - `Probe target:` (the URL the probe actually used) -- `Listening:` (what’s actually bound on the port) -- `Last gateway error:` (common root cause when the process is alive but the port isn’t listening) +- `Listening:` (what's actually bound on the port) +- `Last gateway error:` (common root cause when the process is alive but the port isn't listening) ### Why does openclaw gateway status show Config cli and Config service different -You’re editing one config file while the service is running another (often a `--profile` / `OPENCLAW_STATE_DIR` mismatch). +You're editing one config file while the service is running another (often a `--profile` / `OPENCLAW_STATE_DIR` mismatch). Fix: @@ -2394,7 +2388,7 @@ Facts (from code): Fix: - Fastest: `openclaw dashboard` (prints + copies tokenized link, tries to open; shows SSH hint if headless). -- If you don’t have a token yet: `openclaw doctor --generate-gateway-token`. +- If you don't have a token yet: `openclaw doctor --generate-gateway-token`. - If remote, tunnel first: `ssh -N -L 18789:127.0.0.1:18789 user@host` then open `http://127.0.0.1:18789/?token=...`. - Set `gateway.auth.token` (or `OPENCLAW_GATEWAY_TOKEN`) on the gateway host. - In the Control UI settings, paste the same token (or refresh with a one-time `?token=...` link). @@ -2402,7 +2396,7 @@ Fix: ### I set gatewaybind tailnet but it cant bind nothing listens -`tailnet` bind picks a Tailscale IP from your network interfaces (100.64.0.0/10). If the machine isn’t on Tailscale (or the interface is down), there’s nothing to bind to. +`tailnet` bind picks a Tailscale IP from your network interfaces (100.64.0.0/10). If the machine isn't on Tailscale (or the interface is down), there's nothing to bind to. Fix: @@ -2417,8 +2411,8 @@ Usually no - one Gateway can run multiple messaging channels and agents. Use mul Yes, but you must isolate: -- `OPENCLAW_CONFIG_PATH` (per‑instance config) -- `OPENCLAW_STATE_DIR` (per‑instance state) +- `OPENCLAW_CONFIG_PATH` (per-instance config) +- `OPENCLAW_STATE_DIR` (per-instance state) - `agents.defaults.workspace` (workspace isolation) - `gateway.port` (unique ports) @@ -2441,15 +2435,15 @@ Common causes: - You opened the **HTTP** URL in a browser (`http://...`) instead of a WS client. - You used the wrong port or path. -- A proxy or tunnel stripped auth headers or sent a non‑Gateway request. +- A proxy or tunnel stripped auth headers or sent a non-Gateway request. Quick fixes: 1. Use the WS URL: `ws://:18789` (or `wss://...` if HTTPS). -2. Don’t open the WS port in a normal browser tab. +2. Don't open the WS port in a normal browser tab. 3. If auth is on, include the token/password in the `connect` frame. -If you’re using the CLI or TUI, the URL should look like: +If you're using the CLI or TUI, the URL should look like: ``` openclaw tui --url ws://:18789 --token @@ -2611,7 +2605,7 @@ openclaw gateway start This stops/starts the **supervised service** (launchd on macOS, systemd on Linux). Use this when the Gateway runs in the background as a daemon. -If you’re running in the foreground, stop with Ctrl‑C, then: +If you're running in the foreground, stop with Ctrl-C, then: ```bash openclaw gateway run @@ -2645,8 +2639,8 @@ openclaw message send --target +15555550123 --message "Here you go" --media /pat Also check: -- The target channel supports outbound media and isn’t blocked by allowlists. -- The file is within the provider’s size limits (images are resized to max 2048px). +- The target channel supports outbound media and isn't blocked by allowlists. +- The file is within the provider's size limits (images are resized to max 2048px). See [Images](/nodes/images). @@ -2656,11 +2650,11 @@ See [Images](/nodes/images). Treat inbound DMs as untrusted input. Defaults are designed to reduce risk: -- Default behavior on DM‑capable channels is **pairing**: +- Default behavior on DM-capable channels is **pairing**: - Unknown senders receive a pairing code; the bot does not process their message. - Approve with: `openclaw pairing approve ` - - Pending requests are capped at **3 per channel**; check `openclaw pairing list ` if a code didn’t arrive. -- Opening DMs publicly requires explicit opt‑in (`dmPolicy: "open"` and allowlist `"*"`). + - Pending requests are capped at **3 per channel**; check `openclaw pairing list ` if a code didn't arrive. +- Opening DMs publicly requires explicit opt-in (`dmPolicy: "open"` and allowlist `"*"`). Run `openclaw doctor` to surface risky DM policies. @@ -2712,7 +2706,7 @@ tools and run inside a sandbox. See [Security](/gateway/security). ### I ran start in Telegram but didnt get a pairing code Pairing codes are sent **only** when an unknown sender messages the bot and -`dmPolicy: "pairing"` is enabled. `/start` by itself doesn’t generate a code. +`dmPolicy: "pairing"` is enabled. `/start` by itself doesn't generate a code. Check pending requests: @@ -2739,9 +2733,9 @@ List pending requests: openclaw pairing list whatsapp ``` -Wizard phone number prompt: it’s used to set your **allowlist/owner** so your own DMs are permitted. It’s not used for auto-sending. If you run on your personal WhatsApp number, use that number and enable `channels.whatsapp.selfChatMode`. +Wizard phone number prompt: it's used to set your **allowlist/owner** so your own DMs are permitted. It's not used for auto-sending. If you run on your personal WhatsApp number, use that number and enable `channels.whatsapp.selfChatMode`. -## Chat commands, aborting tasks, and “it won’t stop” +## Chat commands, aborting tasks, and "it won't stop" ### How do I stop internal system messages from showing in chat @@ -2788,10 +2782,10 @@ Most commands must be sent as a **standalone** message that starts with `/`, but ### How do I send a Discord message from Telegram Crosscontext messaging denied -OpenClaw blocks **cross‑provider** messaging by default. If a tool call is bound -to Telegram, it won’t send to Discord unless you explicitly allow it. +OpenClaw blocks **cross-provider** messaging by default. If a tool call is bound +to Telegram, it won't send to Discord unless you explicitly allow it. -Enable cross‑provider messaging for the agent: +Enable cross-provider messaging for the agent: ```json5 { @@ -2815,7 +2809,7 @@ agent, set it under `agents.list[].tools.message` instead. ### Why does it feel like the bot ignores rapidfire messages -Queue mode controls how new messages interact with an in‑flight run. Use `/queue` to change modes: +Queue mode controls how new messages interact with an in-flight run. Use `/queue` to change modes: - `steer` - new messages redirect the current task - `followup` - run messages one at a time @@ -2827,9 +2821,9 @@ You can add options like `debounce:2s cap:25 drop:summarize` for followup modes. ## Answer the exact question from the screenshot/chat log -**Q: “What’s the default model for Anthropic with an API key?”** +**Q: "What's the default model for Anthropic with an API key?"** -**A:** In OpenClaw, credentials and model selection are separate. Setting `ANTHROPIC_API_KEY` (or storing an Anthropic API key in auth profiles) enables authentication, but the actual default model is whatever you configure in `agents.defaults.model.primary` (for example, `anthropic/claude-sonnet-4-5` or `anthropic/claude-opus-4-5`). If you see `No credentials found for profile "anthropic:default"`, it means the Gateway couldn’t find Anthropic credentials in the expected `auth-profiles.json` for the agent that’s running. +**A:** In OpenClaw, credentials and model selection are separate. Setting `ANTHROPIC_API_KEY` (or storing an Anthropic API key in auth profiles) enables authentication, but the actual default model is whatever you configure in `agents.defaults.model.primary` (for example, `anthropic/claude-sonnet-4-5` or `anthropic/claude-opus-4-5`). If you see `No credentials found for profile "anthropic:default"`, it means the Gateway couldn't find Anthropic credentials in the expected `auth-profiles.json` for the agent that's running. --- diff --git a/docs/index.md b/docs/index.md index e12db7d91d..357bafaa1d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -210,7 +210,8 @@ Example: - [Telegram](/channels/telegram) - [Discord](/channels/discord) - [Mattermost (plugin)](/channels/mattermost) - - [iMessage](/channels/imessage) + - [BlueBubbles (iMessage)](/channels/bluebubbles) + - [iMessage (legacy)](/channels/imessage) - [Groups](/concepts/groups) - [WhatsApp group messages](/concepts/group-messages) - [Media: images](/nodes/images) diff --git a/docs/reference/rpc.md b/docs/reference/rpc.md index 218d1f7dda..ff79bc855a 100644 --- a/docs/reference/rpc.md +++ b/docs/reference/rpc.md @@ -1,5 +1,5 @@ --- -summary: "RPC adapters for external CLIs (signal-cli, imsg) and gateway patterns" +summary: "RPC adapters for external CLIs (signal-cli, legacy imsg) and gateway patterns" read_when: - Adding or changing external CLI integrations - Debugging RPC adapters (signal-cli, imsg) @@ -19,9 +19,11 @@ OpenClaw integrates external CLIs via JSON-RPC. Two patterns are used today. See [Signal](/channels/signal) for setup and endpoints. -## Pattern B: stdio child process (imsg) +## Pattern B: stdio child process (legacy: imsg) -- OpenClaw spawns `imsg rpc` as a child process. +> **Note:** For new iMessage setups, use [BlueBubbles](/channels/bluebubbles) instead. + +- OpenClaw spawns `imsg rpc` as a child process (legacy iMessage integration). - JSON-RPC is line-delimited over stdin/stdout (one JSON object per line). - No TCP port, no daemon required. @@ -32,7 +34,7 @@ Core methods used: - `send` - `chats.list` (probe/diagnostics) -See [iMessage](/channels/imessage) for setup and addressing (`chat_id` preferred). +See [iMessage](/channels/imessage) for legacy setup and addressing (`chat_id` preferred). ## Adapter guidelines diff --git a/docs/start/hubs.md b/docs/start/hubs.md index 3e3027acd7..f992b2dc93 100644 --- a/docs/start/hubs.md +++ b/docs/start/hubs.md @@ -71,7 +71,8 @@ Use these hubs to discover every page, including deep dives and reference docs t - [Discord](/channels/discord) - [Mattermost](/channels/mattermost) (plugin) - [Signal](/channels/signal) -- [iMessage](/channels/imessage) +- [BlueBubbles (iMessage)](/channels/bluebubbles) +- [iMessage (legacy)](/channels/imessage) - [Location parsing](/channels/location) - [WebChat](/web/webchat) - [Webhooks](/automation/webhook) diff --git a/docs/start/pairing.md b/docs/start/pairing.md index f842290f0c..b11373c933 100644 --- a/docs/start/pairing.md +++ b/docs/start/pairing.md @@ -80,6 +80,7 @@ Stored under `~/.openclaw/devices/`: - Telegram: [Telegram](/channels/telegram) - WhatsApp: [WhatsApp](/channels/whatsapp) - Signal: [Signal](/channels/signal) - - iMessage: [iMessage](/channels/imessage) + - BlueBubbles (iMessage): [BlueBubbles](/channels/bluebubbles) + - iMessage (legacy): [iMessage](/channels/imessage) - Discord: [Discord](/channels/discord) - Slack: [Slack](/channels/slack) diff --git a/docs/start/wizard.md b/docs/start/wizard.md index 7a8d249dd3..501d686a81 100644 --- a/docs/start/wizard.md +++ b/docs/start/wizard.md @@ -127,7 +127,8 @@ Tip: `--json` does **not** imply non-interactive mode. Use `--non-interactive` ( - [Google Chat](/channels/googlechat): service account JSON + webhook audience. - [Mattermost](/channels/mattermost) (plugin): bot token + base URL. - [Signal](/channels/signal): optional `signal-cli` install + account config. - - [iMessage](/channels/imessage): local `imsg` CLI path + DB access. + - [BlueBubbles](/channels/bluebubbles): **recommended for iMessage**; server URL + password + webhook. + - [iMessage](/channels/imessage): legacy `imsg` CLI path + DB access. - DM security: default is pairing. First DM sends a code; approve via `openclaw pairing approve ` or use allowlists. 6. **Daemon install** @@ -329,5 +330,5 @@ will prompt to install it (npm or a local path) before it can be configured. - macOS app onboarding: [Onboarding](/start/onboarding) - Config reference: [Gateway configuration](/gateway/configuration) -- Providers: [WhatsApp](/channels/whatsapp), [Telegram](/channels/telegram), [Discord](/channels/discord), [Google Chat](/channels/googlechat), [Signal](/channels/signal), [iMessage](/channels/imessage) +- Providers: [WhatsApp](/channels/whatsapp), [Telegram](/channels/telegram), [Discord](/channels/discord), [Google Chat](/channels/googlechat), [Signal](/channels/signal), [BlueBubbles](/channels/bluebubbles) (iMessage), [iMessage](/channels/imessage) (legacy) - Skills: [Skills](/tools/skills), [Skills config](/tools/skills-config) diff --git a/docs/zh-CN/channels/index.md b/docs/zh-CN/channels/index.md index fcf0aadf47..c48670711f 100644 --- a/docs/zh-CN/channels/index.md +++ b/docs/zh-CN/channels/index.md @@ -28,8 +28,8 @@ OpenClaw 可以在你已经使用的任何聊天应用上与你交流。每个 - [Google Chat](/channels/googlechat) — 通过 HTTP webhook 的 Google Chat API 应用。 - [Mattermost](/channels/mattermost) — Bot API + WebSocket;频道、群组、私信(插件,需单独安装)。 - [Signal](/channels/signal) — signal-cli;注重隐私。 -- [BlueBubbles](/channels/bluebubbles) — **iMessage 推荐方案**;使用 BlueBubbles macOS 服务器 REST API,完整功能支持(编辑、撤回、特效、表情回应、群组管理——编辑功能目前在 macOS 26 Tahoe 上存在问题)。 -- [iMessage](/channels/imessage) — 仅限 macOS;通过 imsg 原生集成(旧版方案,新部署建议使用 BlueBubbles)。 +- [BlueBubbles](/channels/bluebubbles) — **推荐用于 iMessage**;使用 BlueBubbles macOS 服务器 REST API,功能完整(编辑、撤回、特效、回应、群组管理——编辑功能在 macOS 26 Tahoe 上目前不可用)。 +- [iMessage(旧版)](/channels/imessage) — 通过 imsg CLI 的旧版 macOS 集成(已弃用,新设置请使用 BlueBubbles)。 - [Microsoft Teams](/channels/msteams) — Bot Framework;企业支持(插件,需单独安装)。 - [LINE](/channels/line) — LINE Messaging API 机器人(插件,需单独安装)。 - [Nextcloud Talk](/channels/nextcloud-talk) — 通过 Nextcloud Talk 的自托管聊天(插件,需单独安装)。 diff --git a/docs/zh-CN/help/faq.md b/docs/zh-CN/help/faq.md index 80673ded67..2b15d16412 100644 --- a/docs/zh-CN/help/faq.md +++ b/docs/zh-CN/help/faq.md @@ -1008,7 +1008,7 @@ pnpm add -g clawhub **能否从 Linux 运行仅限 Apple/macOS 的 Skills** -不能直接运行。macOS Skills 受 `metadata.openclaw.os` 和所需二进制文件限制,Skills 只有在 **Gateway 网关主机**上符合条件时才会出现在系统提示中。在 Linux 上,`darwin` 专用 Skills(如 `imsg`、`apple-notes`、`apple-reminders`)不会加载,除非你覆盖限制。 +不能直接运行。macOS Skills 受 `metadata.openclaw.os` 和所需二进制文件限制,Skills 只有在 **Gateway 网关主机**上符合条件时才会出现在系统提示中。在 Linux 上,`darwin` 专用 Skills(如 `apple-notes`、`apple-reminders`、`things-mac`)不会加载,除非你覆盖限制。 你有三种支持的模式: diff --git a/extensions/bluebubbles/README.md b/extensions/bluebubbles/README.md new file mode 100644 index 0000000000..bd79f25024 --- /dev/null +++ b/extensions/bluebubbles/README.md @@ -0,0 +1,45 @@ +# BlueBubbles extension (developer reference) + +This directory contains the **BlueBubbles external channel plugin** for OpenClaw. + +If you’re looking for **how to use BlueBubbles as an agent/tool user**, see: + +- `skills/bluebubbles/SKILL.md` + +## Layout + +- Extension package: `extensions/bluebubbles/` (entry: `index.ts`). +- Channel implementation: `extensions/bluebubbles/src/channel.ts`. +- Webhook handling: `extensions/bluebubbles/src/monitor.ts` (register via `api.registerHttpHandler`). +- REST helpers: `extensions/bluebubbles/src/send.ts` + `extensions/bluebubbles/src/probe.ts`. +- Runtime bridge: `extensions/bluebubbles/src/runtime.ts` (set via `api.runtime`). +- Catalog entry for onboarding: `src/channels/plugins/catalog.ts`. + +## Internal helpers (use these, not raw API calls) + +- `probeBlueBubbles` in `extensions/bluebubbles/src/probe.ts` for health checks. +- `sendMessageBlueBubbles` in `extensions/bluebubbles/src/send.ts` for text delivery. +- `resolveChatGuidForTarget` in `extensions/bluebubbles/src/send.ts` for chat lookup. +- `sendBlueBubblesReaction` in `extensions/bluebubbles/src/reactions.ts` for tapbacks. +- `sendBlueBubblesTyping` + `markBlueBubblesChatRead` in `extensions/bluebubbles/src/chat.ts`. +- `downloadBlueBubblesAttachment` in `extensions/bluebubbles/src/attachments.ts` for inbound media. +- `buildBlueBubblesApiUrl` + `blueBubblesFetchWithTimeout` in `extensions/bluebubbles/src/types.ts` for shared REST plumbing. + +## Webhooks + +- BlueBubbles posts JSON to the gateway HTTP server. +- Normalize sender/chat IDs defensively (payloads vary by version). +- Skip messages marked as from self. +- Route into core reply pipeline via the plugin runtime (`api.runtime`) and `openclaw/plugin-sdk` helpers. +- For attachments/stickers, use `` placeholders when text is empty and attach media paths via `MediaUrl(s)` in the inbound context. + +## Config (core) + +- `channels.bluebubbles.serverUrl` (base URL), `channels.bluebubbles.password`, `channels.bluebubbles.webhookPath`. +- Action gating: `channels.bluebubbles.actions.reactions` (default true). + +## Message tool notes + +- **Reactions:** the `react` action requires a `target` (phone number or chat identifier) in addition to `messageId`. + Example: + `action=react target=+15551234567 messageId=ABC123 emoji=❤️` diff --git a/skills/bluebubbles/SKILL.md b/skills/bluebubbles/SKILL.md index 929a75e7d3..bc03be4710 100644 --- a/skills/bluebubbles/SKILL.md +++ b/skills/bluebubbles/SKILL.md @@ -1,44 +1,131 @@ --- name: bluebubbles -description: Build or update the BlueBubbles external channel plugin for OpenClaw (extension package, REST send/probe, webhook inbound). +description: Use when you need to send or manage iMessages via BlueBubbles (recommended iMessage integration). Calls go through the generic message tool with channel="bluebubbles". +metadata: { "openclaw": { "emoji": "🫧", "requires": { "config": ["channels.bluebubbles"] } } } --- -# BlueBubbles plugin +# BlueBubbles Actions -Use this skill when working on the BlueBubbles channel plugin. +## Overview -## Layout +BlueBubbles is OpenClaw’s recommended iMessage integration. Use the `message` tool with `channel: "bluebubbles"` to send messages and manage iMessage conversations: send texts and attachments, react (tapbacks), edit/unsend, reply in threads, and manage group participants/names/icons. -- Extension package: `extensions/bluebubbles/` (entry: `index.ts`). -- Channel implementation: `extensions/bluebubbles/src/channel.ts`. -- Webhook handling: `extensions/bluebubbles/src/monitor.ts` (register via `api.registerHttpHandler`). -- REST helpers: `extensions/bluebubbles/src/send.ts` + `extensions/bluebubbles/src/probe.ts`. -- Runtime bridge: `extensions/bluebubbles/src/runtime.ts` (set via `api.runtime`). -- Catalog entry for onboarding: `src/channels/plugins/catalog.ts`. +## Inputs to collect -## Internal helpers (use these, not raw API calls) +- `target` (prefer `chat_guid:...`; also `+15551234567` in E.164 or `user@example.com`) +- `message` text for send/edit/reply +- `messageId` for react/edit/unsend/reply +- Attachment `path` for local files, or `buffer` + `filename` for base64 -- `probeBlueBubbles` in `extensions/bluebubbles/src/probe.ts` for health checks. -- `sendMessageBlueBubbles` in `extensions/bluebubbles/src/send.ts` for text delivery. -- `resolveChatGuidForTarget` in `extensions/bluebubbles/src/send.ts` for chat lookup. -- `sendBlueBubblesReaction` in `extensions/bluebubbles/src/reactions.ts` for tapbacks. -- `sendBlueBubblesTyping` + `markBlueBubblesChatRead` in `extensions/bluebubbles/src/chat.ts`. -- `downloadBlueBubblesAttachment` in `extensions/bluebubbles/src/attachments.ts` for inbound media. -- `buildBlueBubblesApiUrl` + `blueBubblesFetchWithTimeout` in `extensions/bluebubbles/src/types.ts` for shared REST plumbing. +If the user is vague ("text my mom"), ask for the recipient handle or chat guid and the exact message content. -## Webhooks +## Actions -- BlueBubbles posts JSON to the gateway HTTP server. -- Normalize sender/chat IDs defensively (payloads vary by version). -- Skip messages marked as from self. -- Route into core reply pipeline via the plugin runtime (`api.runtime`) and `openclaw/plugin-sdk` helpers. -- For attachments/stickers, use `` placeholders when text is empty and attach media paths via `MediaUrl(s)` in the inbound context. +### Send a message -## Config (core) +```json +{ + "action": "send", + "channel": "bluebubbles", + "target": "+15551234567", + "message": "hello from OpenClaw" +} +``` -- `channels.bluebubbles.serverUrl` (base URL), `channels.bluebubbles.password`, `channels.bluebubbles.webhookPath`. -- Action gating: `channels.bluebubbles.actions.reactions` (default true). +### React (tapback) -## Message tool notes +```json +{ + "action": "react", + "channel": "bluebubbles", + "target": "+15551234567", + "messageId": "", + "emoji": "❤️" +} +``` -- **Reactions:** The `react` action requires a `target` (phone number or chat identifier) in addition to `messageId`. Example: `action=react target=+15551234567 messageId=ABC123 emoji=❤️` +### Remove a reaction + +```json +{ + "action": "react", + "channel": "bluebubbles", + "target": "+15551234567", + "messageId": "", + "emoji": "❤️", + "remove": true +} +``` + +### Edit a previously sent message + +```json +{ + "action": "edit", + "channel": "bluebubbles", + "target": "+15551234567", + "messageId": "", + "message": "updated text" +} +``` + +### Unsend a message + +```json +{ + "action": "unsend", + "channel": "bluebubbles", + "target": "+15551234567", + "messageId": "" +} +``` + +### Reply to a specific message + +```json +{ + "action": "reply", + "channel": "bluebubbles", + "target": "+15551234567", + "replyTo": "", + "message": "replying to that" +} +``` + +### Send an attachment + +```json +{ + "action": "sendAttachment", + "channel": "bluebubbles", + "target": "+15551234567", + "path": "/tmp/photo.jpg", + "caption": "here you go" +} +``` + +### Send with an iMessage effect + +```json +{ + "action": "sendWithEffect", + "channel": "bluebubbles", + "target": "+15551234567", + "message": "big news", + "effect": "balloons" +} +``` + +## Notes + +- Requires gateway config `channels.bluebubbles` (serverUrl/password/webhookPath). +- Prefer `chat_guid` targets when you have them (especially for group chats). +- BlueBubbles supports rich actions, but some are macOS-version dependent (for example, edit may be broken on macOS 26 Tahoe). +- The gateway may expose both short and full message ids; full ids are more durable across restarts. +- Developer reference for the underlying plugin lives in `extensions/bluebubbles/README.md`. + +## Ideas to try + +- React with a tapback to acknowledge a request. +- Reply in-thread when a user references a specific message. +- Send a file attachment with a short caption. diff --git a/skills/imsg/SKILL.md b/skills/imsg/SKILL.md index 6df5f84712..776baa8a37 100644 --- a/skills/imsg/SKILL.md +++ b/skills/imsg/SKILL.md @@ -23,24 +23,52 @@ metadata: } --- -# imsg +# imsg Actions + +## Overview Use `imsg` to read and send Messages.app iMessage/SMS on macOS. -Requirements +Requirements: Messages.app signed in, Full Disk Access for your terminal, and Automation permission to control Messages.app for sending. -- Messages.app signed in -- Full Disk Access for your terminal -- Automation permission to control Messages.app (for sending) +## Inputs to collect -Common commands +- Recipient handle (phone/email) for `send` +- `chatId` for history/watch (from `imsg chats --limit 10 --json`) +- `text` and optional `file` path for sends -- List chats: `imsg chats --limit 10 --json` -- History: `imsg history --chat-id 1 --limit 20 --attachments --json` -- Watch: `imsg watch --chat-id 1 --attachments` -- Send: `imsg send --to "+14155551212" --text "hi" --file /path/pic.jpg` +## Actions -Notes +### List chats + +```bash +imsg chats --limit 10 --json +``` + +### Fetch chat history + +```bash +imsg history --chat-id 1 --limit 20 --attachments --json +``` + +### Watch a chat + +```bash +imsg watch --chat-id 1 --attachments +``` + +### Send a message + +```bash +imsg send --to "+14155551212" --text "hi" --file /path/pic.jpg +``` + +## Notes - `--service imessage|sms|auto` controls delivery. - Confirm recipient + message before sending. + +## Ideas to try + +- Use `imsg chats --limit 10 --json` to discover chat ids. +- Watch a high-signal chat to stream incoming messages. diff --git a/src/agents/tools/session-status-tool.ts b/src/agents/tools/session-status-tool.ts index 798cf6bada..71547a8340 100644 --- a/src/agents/tools/session-status-tool.ts +++ b/src/agents/tools/session-status-tool.ts @@ -1,22 +1,6 @@ import { Type } from "@sinclair/typebox"; import type { OpenClawConfig } from "../../config/config.js"; import type { AnyAgentTool } from "./common.js"; -import { resolveAgentDir } from "../../agents/agent-scope.js"; -import { - ensureAuthProfileStore, - resolveAuthProfileDisplayLabel, - resolveAuthProfileOrder, -} from "../../agents/auth-profiles.js"; -import { getCustomProviderApiKey, resolveEnvApiKey } from "../../agents/model-auth.js"; -import { loadModelCatalog } from "../../agents/model-catalog.js"; -import { - buildAllowedModelSet, - buildModelAliasIndex, - modelKey, - normalizeProviderId, - resolveDefaultModelForAgent, - resolveModelRefFromString, -} from "../../agents/model-selection.js"; import { normalizeGroupActivation } from "../../auto-reply/group-activation.js"; import { getFollowupQueueDepth, resolveQueueSettings } from "../../auto-reply/reply/queue.js"; import { buildStatusMessage } from "../../auto-reply/status.js"; @@ -39,7 +23,23 @@ import { resolveAgentIdFromSessionKey, } from "../../routing/session-key.js"; import { applyModelOverrideToSessionEntry } from "../../sessions/model-overrides.js"; +import { resolveAgentDir } from "../agent-scope.js"; +import { + ensureAuthProfileStore, + resolveAuthProfileDisplayLabel, + resolveAuthProfileOrder, +} from "../auth-profiles.js"; import { formatUserTime, resolveUserTimeFormat, resolveUserTimezone } from "../date-time.js"; +import { getCustomProviderApiKey, resolveEnvApiKey } from "../model-auth.js"; +import { loadModelCatalog } from "../model-catalog.js"; +import { + buildAllowedModelSet, + buildModelAliasIndex, + modelKey, + normalizeProviderId, + resolveDefaultModelForAgent, + resolveModelRefFromString, +} from "../model-selection.js"; import { readStringParam } from "./common.js"; import { shouldResolveSessionIdInput, diff --git a/src/channels/plugins/whatsapp-heartbeat.ts b/src/channels/plugins/whatsapp-heartbeat.ts index 0710ab15e3..9d6e4a48a5 100644 --- a/src/channels/plugins/whatsapp-heartbeat.ts +++ b/src/channels/plugins/whatsapp-heartbeat.ts @@ -1,7 +1,7 @@ import type { OpenClawConfig } from "../../config/config.js"; -import { normalizeChatChannelId } from "../../channels/registry.js"; import { loadSessionStore, resolveStorePath } from "../../config/sessions.js"; import { normalizeE164 } from "../../utils.js"; +import { normalizeChatChannelId } from "../registry.js"; type HeartbeatRecipientsResult = { recipients: string[]; source: string }; type HeartbeatRecipientsOpts = { to?: string; all?: boolean }; diff --git a/src/infra/heartbeat-runner.ts b/src/infra/heartbeat-runner.ts index 9b6b77aa51..4390298f85 100644 --- a/src/infra/heartbeat-runner.ts +++ b/src/infra/heartbeat-runner.ts @@ -34,13 +34,12 @@ import { saveSessionStore, updateSessionStore, } from "../config/sessions.js"; -import { formatErrorMessage } from "../infra/errors.js"; -import { peekSystemEvents } from "../infra/system-events.js"; import { createSubsystemLogger } from "../logging/subsystem.js"; import { getQueueSize } from "../process/command-queue.js"; import { CommandLane } from "../process/lanes.js"; import { normalizeAgentId, toAgentStoreSessionKey } from "../routing/session-key.js"; import { defaultRuntime, type RuntimeEnv } from "../runtime.js"; +import { formatErrorMessage } from "./errors.js"; import { emitHeartbeatEvent, resolveIndicatorType } from "./heartbeat-events.js"; import { resolveHeartbeatVisibility } from "./heartbeat-visibility.js"; import { @@ -54,6 +53,7 @@ import { resolveHeartbeatDeliveryTarget, resolveHeartbeatSenderContext, } from "./outbound/targets.js"; +import { peekSystemEvents } from "./system-events.js"; type HeartbeatDeps = OutboundSendDeps & ChannelHeartbeatDeps & { @@ -349,7 +349,9 @@ function resolveHeartbeatSession( const mainSessionKey = scope === "global" ? "global" : resolveAgentMainSessionKey({ cfg, agentId: resolvedAgentId }); const storeAgentId = scope === "global" ? resolveDefaultAgentId(cfg) : resolvedAgentId; - const storePath = resolveStorePath(sessionCfg?.store, { agentId: storeAgentId }); + const storePath = resolveStorePath(sessionCfg?.store, { + agentId: storeAgentId, + }); const store = loadSessionStore(storePath); const mainEntry = store[mainSessionKey]; @@ -380,7 +382,12 @@ function resolveHeartbeatSession( if (canonical !== "global") { const sessionAgentId = resolveAgentIdFromSessionKey(canonical); if (sessionAgentId === normalizeAgentId(resolvedAgentId)) { - return { sessionKey: canonical, storePath, store, entry: store[canonical] }; + return { + sessionKey: canonical, + storePath, + store, + entry: store[canonical], + }; } } @@ -709,7 +716,11 @@ export async function runHeartbeatOnce(opts: { } if (!visibility.showAlerts) { - await restoreHeartbeatUpdatedAt({ storePath, sessionKey, updatedAt: previousUpdatedAt }); + await restoreHeartbeatUpdatedAt({ + storePath, + sessionKey, + updatedAt: previousUpdatedAt, + }); emitHeartbeatEvent({ status: "skipped", reason: "alerts-disabled", @@ -908,10 +919,16 @@ export function startHeartbeatRunner(opts: { const run: HeartbeatWakeHandler = async (params) => { if (!heartbeatsEnabled) { - return { status: "skipped", reason: "disabled" } satisfies HeartbeatRunResult; + return { + status: "skipped", + reason: "disabled", + } satisfies HeartbeatRunResult; } if (state.agents.size === 0) { - return { status: "skipped", reason: "disabled" } satisfies HeartbeatRunResult; + return { + status: "skipped", + reason: "disabled", + } satisfies HeartbeatRunResult; } const reason = params?.reason;