Merge branch 'openclaw:main' into qianfan

This commit is contained in:
ide-rea
2026-02-05 12:43:21 +08:00
committed by GitHub
219 changed files with 5306 additions and 2225 deletions

View File

@@ -8,98 +8,63 @@ Input
- If missing: use the most recent PR mentioned in the conversation.
- If ambiguous: ask.
Do (review-only)
Goal: produce a thorough review and a clear recommendation (READY for /landpr vs NEEDS WORK). Do NOT merge, do NOT push, do NOT make changes in the repo as part of this command.
Do (end-to-end)
Goal: PR must end in GitHub state = MERGED (never CLOSED). Use `gh pr merge` with `--rebase` or `--squash`.
1. Identify PR meta + context
1. Repo clean: `git status`.
2. Identify PR meta (author + head branch):
```sh
gh pr view <PR> --json number,title,state,isDraft,author,baseRefName,headRefName,headRepository,url,body,labels,assignees,reviewRequests,files,additions,deletions --jq '{number,title,url,state,isDraft,author:.author.login,base:.baseRefName,head:.headRefName,headRepo:.headRepository.nameWithOwner,additions,deletions,files:.files|length}'
gh pr view <PR> --json number,title,author,headRefName,baseRefName,headRepository --jq '{number,title,author:.author.login,head:.headRefName,base:.baseRefName,headRepo:.headRepository.nameWithOwner}'
contrib=$(gh pr view <PR> --json author --jq .author.login)
head=$(gh pr view <PR> --json headRefName --jq .headRefName)
head_repo_url=$(gh pr view <PR> --json headRepository --jq .headRepository.url)
```
2. Read the PR description carefully
- Summarize the stated goal, scope, and any “why now?” rationale.
- Call out any missing context: motivation, alternatives considered, rollout/compat notes, risk.
3. Fast-forward base:
- `git checkout main`
- `git pull --ff-only`
4. Create temp base branch from main:
- `git checkout -b temp/landpr-<ts-or-pr>`
5. Check out PR branch locally:
- `gh pr checkout <PR>`
6. Rebase PR branch onto temp base:
- `git rebase temp/landpr-<ts-or-pr>`
- Fix conflicts; keep history tidy.
7. Fix + tests + changelog:
- Implement fixes + add/adjust tests
- Update `CHANGELOG.md` and mention `#<PR>` + `@$contrib`
8. Decide merge strategy:
- Rebase if we want to preserve commit history
- Squash if we want a single clean commit
- If unclear, ask
9. Full gate (BEFORE commit):
- `pnpm lint && pnpm build && pnpm test`
10. Commit via committer (include # + contributor in commit message):
- `committer "fix: <summary> (#<PR>) (thanks @$contrib)" CHANGELOG.md <changed files>`
- `land_sha=$(git rev-parse HEAD)`
11. Push updated PR branch (rebase => usually needs force):
3. Read the diff thoroughly (prefer full diff)
```sh
git remote add prhead "$head_repo_url.git" 2>/dev/null || git remote set-url prhead "$head_repo_url.git"
git push --force-with-lease prhead HEAD:$head
```
```sh
gh pr diff <PR>
# If you need more surrounding context for files:
gh pr checkout <PR> # optional; still review-only
git show --stat
```
12. Merge PR (must show MERGED on GitHub):
- Rebase: `gh pr merge <PR> --rebase`
- Squash: `gh pr merge <PR> --squash`
- Never `gh pr close` (closing is wrong)
13. Sync main:
- `git checkout main`
- `git pull --ff-only`
14. Comment on PR with what we did + SHAs + thanks:
4. Validate the change is needed / valuable
- What user/customer/dev pain does this solve?
- Is this change the smallest reasonable fix?
- Are we introducing complexity for marginal benefit?
- Are we changing behavior/contract in a way that needs docs or a release note?
```sh
merge_sha=$(gh pr view <PR> --json mergeCommit --jq '.mergeCommit.oid')
gh pr comment <PR> --body "Landed via temp rebase onto main.\n\n- Gate: pnpm lint && pnpm build && pnpm test\n- Land commit: $land_sha\n- Merge commit: $merge_sha\n\nThanks @$contrib!"
```
5. Evaluate implementation quality + optimality
- Correctness: edge cases, error handling, null/undefined, concurrency, ordering.
- Design: is the abstraction/architecture appropriate or over/under-engineered?
- Performance: hot paths, allocations, queries, network, N+1s, caching.
- Security/privacy: authz/authn, input validation, secrets, logging PII.
- Backwards compatibility: public APIs, config, migrations.
- Style consistency: formatting, naming, patterns used elsewhere.
6. Tests & verification
- Identify whats covered by tests (unit/integration/e2e).
- Are there regression tests for the bug fixed / scenario added?
- Missing tests? Call out exact cases that should be added.
- If tests are present, do they actually assert the important behavior (not just snapshots / happy path)?
7. Follow-up refactors / cleanup suggestions
- Any code that should be simplified before merge?
- Any TODOs that should be tickets vs addressed now?
- Any deprecations, docs, types, or lint rules we should adjust?
8. Key questions to answer explicitly
- Can we fix everything ourselves in a follow-up, or does the contributor need to update this PR?
- Any blocking concerns (must-fix before merge)?
- Is this PR ready to land, or does it need work?
9. Output (structured)
Produce a review with these sections:
A) TL;DR recommendation
- One of: READY FOR /landpr | NEEDS WORK | NEEDS DISCUSSION
- 13 sentence rationale.
B) What changed
- Brief bullet summary of the diff/behavioral changes.
C) Whats good
- Bullets: correctness, simplicity, tests, docs, ergonomics, etc.
D) Concerns / questions (actionable)
- Numbered list.
- Mark each item as:
- BLOCKER (must fix before merge)
- IMPORTANT (should fix before merge)
- NIT (optional)
- For each: point to the file/area and propose a concrete fix or alternative.
E) Tests
- What exists.
- Whats missing (specific scenarios).
F) Follow-ups (optional)
- Non-blocking refactors/tickets to open later.
G) Suggested PR comment (optional)
- Offer: “Want me to draft a PR comment to the author?”
- If yes, provide a ready-to-paste comment summarizing the above, with clear asks.
Rules / Guardrails
- Review only: do not merge (`gh pr merge`), do not push branches, do not edit code.
- If you need clarification, ask questions rather than guessing.
15. Verify PR state == MERGED:
- `gh pr view <PR> --json state --jq .state`
16. Delete temp branch:
- `git branch -D temp/landpr-<ts-or-pr>`

View File

@@ -6,9 +6,14 @@ Docs: https://docs.openclaw.ai
### Changes
- Telegram: remove last `@ts-nocheck` from `bot-handlers.ts`, use Grammy types directly, deduplicate `StickerMetadata`. Zero `@ts-nocheck` remaining in `src/telegram/`. (#9206)
- Telegram: remove `@ts-nocheck` from `bot-message.ts`, type deps via `Omit<BuildTelegramMessageContextParams>`, widen `allMedia` to `TelegramMediaRef[]`. (#9180)
- Telegram: remove `@ts-nocheck` from `bot.ts`, fix duplicate `bot.catch` error handler (Grammy overrides), remove dead reaction `message_thread_id` routing, harden sticker cache guard. (#9077)
- Onboarding: add Cloudflare AI Gateway provider setup and docs. (#7914) Thanks @roerohan.
- Onboarding: add Moonshot (.cn) auth choice and keep the China base URL when preserving defaults. (#7180) Thanks @waynelwz.
- Docs: clarify tmux send-keys for TUI by splitting text and Enter. (#7737) Thanks @Wangnov.
- Docs: mirror the landing page revamp for zh-CN (features, quickstart, docs directory, network model, credits). (#8994) Thanks @joshp123.
- Messages: add per-channel and per-account responsePrefix overrides across channels. (#9001) Thanks @mudrii.
- Cron: add announce delivery mode for isolated jobs (CLI + Control UI) and delivery mode config.
- Cron: default isolated jobs to announce delivery; accept ISO 8601 `schedule.at` in tool inputs.
- Cron: hard-migrate isolated jobs to announce/none delivery; drop legacy post-to-main/payload delivery fields and `atMs` inputs.
@@ -18,15 +23,25 @@ Docs: https://docs.openclaw.ai
### Fixes
- Heartbeat: allow explicit accountId routing for multi-account channels. (#8702) Thanks @lsh411.
- TUI/Gateway: handle non-streaming finals, refresh history for non-local chat runs, and avoid event gap warnings for targeted tool streams. (#8432) Thanks @gumadeiras.
- Shell completion: auto-detect and migrate slow dynamic patterns to cached files for faster terminal startup; add completion health checks to doctor/update/onboard.
- Telegram: honor session model overrides in inline model selection. (#8193) Thanks @gildo.
- Web UI: fix agent model selection saves for default/non-default agents and wrap long workspace paths. Thanks @Takhoffman.
- Web UI: resolve header logo path when `gateway.controlUi.basePath` is set. (#7178) Thanks @Yeom-JinHo.
- Web UI: apply button styling to the new-messages indicator.
- Onboarding: infer auth choice from non-interactive API key flags. (#8484) Thanks @f-trycua.
- Security: keep untrusted channel metadata out of system prompts (Slack/Discord). Thanks @KonstantinMirin.
- Security: enforce sandboxed media paths for message tool attachments. (#9182) Thanks @victormier.
- Security: require explicit credentials for gateway URL overrides to prevent credential leakage. (#8113) Thanks @victormier.
- Security: gate `whatsapp_login` tool to owner senders and default-deny non-owner contexts. (#8768) Thanks @victormier.
- Voice call: harden webhook verification with host allowlists/proxy trust and keep ngrok loopback bypass.
- Voice call: add regression coverage for anonymous inbound caller IDs with allowlist policy. (#8104) Thanks @victormier.
- Cron: accept epoch timestamps and 0ms durations in CLI `--at` parsing.
- Cron: reload store data when the store file is recreated or mtime changes.
- Cron: deliver announce runs directly, honor delivery mode, and respect wakeMode for summaries. (#8540) Thanks @tyler6204.
- Telegram: include forward_from_chat metadata in forwarded messages and harden cron delivery target checks. (#8392) Thanks @Glucksberg.
- macOS: fix cron payload summary rendering and ISO 8601 formatter concurrency safety.
## 2026.2.2-3

View File

@@ -2,6 +2,56 @@
<rss xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle" version="2.0">
<channel>
<title>OpenClaw</title>
<item>
<title>2026.2.3</title>
<pubDate>Wed, 04 Feb 2026 17:47:10 -0800</pubDate>
<link>https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml</link>
<sparkle:version>8900</sparkle:version>
<sparkle:shortVersionString>2026.2.3</sparkle:shortVersionString>
<sparkle:minimumSystemVersion>15.0</sparkle:minimumSystemVersion>
<description><![CDATA[<h2>OpenClaw 2026.2.3</h2>
<h3>Changes</h3>
<ul>
<li>Telegram: remove last <code>@ts-nocheck</code> from <code>bot-handlers.ts</code>, use Grammy types directly, deduplicate <code>StickerMetadata</code>. Zero <code>@ts-nocheck</code> remaining in <code>src/telegram/</code>. (#9206)</li>
<li>Telegram: remove <code>@ts-nocheck</code> from <code>bot-message.ts</code>, type deps via <code>Omit<BuildTelegramMessageContextParams></code>, widen <code>allMedia</code> to <code>TelegramMediaRef[]</code>. (#9180)</li>
<li>Telegram: remove <code>@ts-nocheck</code> from <code>bot.ts</code>, fix duplicate <code>bot.catch</code> error handler (Grammy overrides), remove dead reaction <code>message_thread_id</code> routing, harden sticker cache guard. (#9077)</li>
<li>Onboarding: add Cloudflare AI Gateway provider setup and docs. (#7914) Thanks @roerohan.</li>
<li>Onboarding: add Moonshot (.cn) auth choice and keep the China base URL when preserving defaults. (#7180) Thanks @waynelwz.</li>
<li>Docs: clarify tmux send-keys for TUI by splitting text and Enter. (#7737) Thanks @Wangnov.</li>
<li>Docs: mirror the landing page revamp for zh-CN (features, quickstart, docs directory, network model, credits). (#8994) Thanks @joshp123.</li>
<li>Messages: add per-channel and per-account responsePrefix overrides across channels. (#9001) Thanks @mudrii.</li>
<li>Cron: add announce delivery mode for isolated jobs (CLI + Control UI) and delivery mode config.</li>
<li>Cron: default isolated jobs to announce delivery; accept ISO 8601 <code>schedule.at</code> in tool inputs.</li>
<li>Cron: hard-migrate isolated jobs to announce/none delivery; drop legacy post-to-main/payload delivery fields and <code>atMs</code> inputs.</li>
<li>Cron: delete one-shot jobs after success by default; add <code>--keep-after-run</code> for CLI.</li>
<li>Cron: suppress messaging tools during announce delivery so summaries post consistently.</li>
<li>Cron: avoid duplicate deliveries when isolated runs send messages directly.</li>
</ul>
<h3>Fixes</h3>
<ul>
<li>Heartbeat: allow explicit accountId routing for multi-account channels. (#8702) Thanks @lsh411.</li>
<li>TUI/Gateway: handle non-streaming finals, refresh history for non-local chat runs, and avoid event gap warnings for targeted tool streams. (#8432) Thanks @gumadeiras.</li>
<li>Shell completion: auto-detect and migrate slow dynamic patterns to cached files for faster terminal startup; add completion health checks to doctor/update/onboard.</li>
<li>Telegram: honor session model overrides in inline model selection. (#8193) Thanks @gildo.</li>
<li>Web UI: fix agent model selection saves for default/non-default agents and wrap long workspace paths. Thanks @Takhoffman.</li>
<li>Web UI: resolve header logo path when <code>gateway.controlUi.basePath</code> is set. (#7178) Thanks @Yeom-JinHo.</li>
<li>Web UI: apply button styling to the new-messages indicator.</li>
<li>Security: keep untrusted channel metadata out of system prompts (Slack/Discord). Thanks @KonstantinMirin.</li>
<li>Security: enforce sandboxed media paths for message tool attachments. (#9182) Thanks @victormier.</li>
<li>Security: require explicit credentials for gateway URL overrides to prevent credential leakage. (#8113) Thanks @victormier.</li>
<li>Security: gate <code>whatsapp_login</code> tool to owner senders and default-deny non-owner contexts. (#8768) Thanks @victormier.</li>
<li>Voice call: harden webhook verification with host allowlists/proxy trust and keep ngrok loopback bypass.</li>
<li>Voice call: add regression coverage for anonymous inbound caller IDs with allowlist policy. (#8104) Thanks @victormier.</li>
<li>Cron: accept epoch timestamps and 0ms durations in CLI <code>--at</code> parsing.</li>
<li>Cron: reload store data when the store file is recreated or mtime changes.</li>
<li>Cron: deliver announce runs directly, honor delivery mode, and respect wakeMode for summaries. (#8540) Thanks @tyler6204.</li>
<li>Telegram: include forward_from_chat metadata in forwarded messages and harden cron delivery target checks. (#8392) Thanks @Glucksberg.</li>
<li>macOS: fix cron payload summary rendering and ISO 8601 formatter concurrency safety.</li>
</ul>
<p><a href="https://github.com/openclaw/openclaw/blob/main/CHANGELOG.md">View full changelog</a></p>
]]></description>
<enclosure url="https://github.com/openclaw/openclaw/releases/download/v2026.2.3/OpenClaw-2026.2.3.zip" length="22530161" type="application/octet-stream" sparkle:edSignature="7eHUaQC6cx87HWbcaPh9T437+LqfE9VtQBf4p9JBjIyBrqGYxxp9KPvI5unEjg55j9j2djCXhseSMeyyRmvYBg=="/>
</item>
<item>
<title>2026.2.2</title>
<pubDate>Tue, 03 Feb 2026 17:04:17 -0800</pubDate>
@@ -112,50 +162,5 @@
]]></description>
<enclosure url="https://github.com/openclaw/openclaw/releases/download/v2026.2.1/OpenClaw-2026.2.1.zip" length="22458919" type="application/octet-stream" sparkle:edSignature="kA/8VQlVdtYphcB1iuFrhWczwWKgkVZMfDfQ7T9WD405D8JKTv5CZ1n8lstIVkpk4xog3UhrfaaoTG8Bf8DMAQ=="/>
</item>
<item>
<title>2026.1.30</title>
<pubDate>Sat, 31 Jan 2026 14:29:57 +0100</pubDate>
<link>https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml</link>
<sparkle:version>8469</sparkle:version>
<sparkle:shortVersionString>2026.1.30</sparkle:shortVersionString>
<sparkle:minimumSystemVersion>15.0</sparkle:minimumSystemVersion>
<description><![CDATA[<h2>OpenClaw 2026.1.30</h2>
<h3>Changes</h3>
<ul>
<li>CLI: add <code>completion</code> command (Zsh/Bash/PowerShell/Fish) and auto-setup during postinstall/onboarding.</li>
<li>CLI: add per-agent <code>models status</code> (<code>--agent</code> filter). (#4780) Thanks @jlowin.</li>
<li>Agents: add Kimi K2.5 to the synthetic model catalog. (#4407) Thanks @manikv12.</li>
<li>Auth: switch Kimi Coding to built-in provider; normalize OAuth profile email.</li>
<li>Auth: add MiniMax OAuth plugin + onboarding option. (#4521) Thanks @Maosghoul.</li>
<li>Agents: update pi SDK/API usage and dependencies.</li>
<li>Web UI: refresh sessions after chat commands and improve session display names.</li>
<li>Build: move TypeScript builds to <code>tsdown</code> + <code>tsgo</code> (faster builds, CI typechecks), update tsconfig target, and clean up lint rules.</li>
<li>Build: align npm tar override and bin metadata so the <code>openclaw</code> CLI entrypoint is preserved in npm publishes.</li>
<li>Docs: add pi/pi-dev docs and update OpenClaw branding + install links.</li>
</ul>
<h3>Fixes</h3>
<ul>
<li>Security: restrict local path extraction in media parser to prevent LFI. (#4880)</li>
<li>Gateway: prevent token defaults from becoming the literal "undefined". (#4873) Thanks @Hisleren.</li>
<li>Control UI: fix assets resolution for npm global installs. (#4909) Thanks @YuriNachos.</li>
<li>macOS: avoid stderr pipe backpressure in gateway discovery. (#3304) Thanks @abhijeet117.</li>
<li>Telegram: normalize account token lookup for non-normalized IDs. (#5055) Thanks @jasonsschin.</li>
<li>Telegram: preserve delivery thread fallback and fix threadId handling in delivery context.</li>
<li>Telegram: fix HTML nesting for overlapping styles/links. (#4578) Thanks @ThanhNguyxn.</li>
<li>Telegram: accept numeric messageId/chatId in react actions. (#4533) Thanks @Ayush10.</li>
<li>Telegram: honor per-account proxy dispatcher via undici fetch. (#4456) Thanks @spiceoogway.</li>
<li>Telegram: scope skill commands to bound agent per bot. (#4360) Thanks @robhparker.</li>
<li>BlueBubbles: debounce by messageId to preserve attachments in text+image messages. (#4984)</li>
<li>Routing: prefer requesterOrigin over stale session entries for sub-agent announce delivery. (#4957)</li>
<li>Extensions: restore embedded extension discovery typings.</li>
<li>CLI: fix <code>tui:dev</code> port resolution.</li>
<li>LINE: fix status command TypeError. (#4651)</li>
<li>OAuth: skip expired-token warnings when refresh tokens are still valid. (#4593)</li>
<li>Build: skip redundant UI install step in Dockerfile. (#4584) Thanks @obviyus.</li>
</ul>
<p><a href="https://github.com/openclaw/openclaw/blob/main/CHANGELOG.md">View full changelog</a></p>
]]></description>
<enclosure url="https://github.com/openclaw/openclaw/releases/download/v2026.1.30/OpenClaw-2026.1.30.zip" length="22458594" type="application/octet-stream" sparkle:edSignature="77/GuEcruKGgu2CJyMq+OVwzaJ2v1VzRQC9NmOirKO3uH5Nn5HaoouwrOHnOanrzlD4OvPW0FS5GH2E4Ntu4CQ=="/>
</item>
</channel>
</rss>

View File

@@ -97,25 +97,21 @@ enum CronSchedule: Codable, Equatable {
static func parseAtDate(_ value: String) -> Date? {
let trimmed = value.trimmingCharacters(in: .whitespacesAndNewlines)
if trimmed.isEmpty { return nil }
if let date = isoFormatterWithFractional.date(from: trimmed) { return date }
return isoFormatter.date(from: trimmed)
if let date = makeIsoFormatter(withFractional: true).date(from: trimmed) { return date }
return makeIsoFormatter(withFractional: false).date(from: trimmed)
}
static func formatIsoDate(_ date: Date) -> String {
isoFormatter.string(from: date)
makeIsoFormatter(withFractional: false).string(from: date)
}
private static let isoFormatter: ISO8601DateFormatter = {
private static func makeIsoFormatter(withFractional: Bool) -> ISO8601DateFormatter {
let formatter = ISO8601DateFormatter()
formatter.formatOptions = [.withInternetDateTime]
formatter.formatOptions = withFractional
? [.withInternetDateTime, .withFractionalSeconds]
: [.withInternetDateTime]
return formatter
}()
private static let isoFormatterWithFractional: ISO8601DateFormatter = {
let formatter = ISO8601DateFormatter()
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
return formatter
}()
}
}
enum CronPayload: Codable, Equatable {

View File

@@ -207,7 +207,7 @@ extension CronSettings {
func payloadSummary(_ job: CronJob) -> some View {
let payload = job.payload
VStack(alignment: .leading, spacing: 6) {
return VStack(alignment: .leading, spacing: 6) {
Text("Payload")
.font(.caption.weight(.semibold))
.foregroundStyle(.secondary)

View File

@@ -39,6 +39,26 @@
"source": "Getting started",
"target": "入门指南"
},
{
"source": "Quick start",
"target": "快速开始"
},
{
"source": "Quick Start",
"target": "快速开始"
},
{
"source": "Docs directory",
"target": "文档目录"
},
{
"source": "Credits",
"target": "致谢"
},
{
"source": "Features",
"target": "功能"
},
{
"source": "DMs",
"target": "私信"

View File

@@ -1,53 +0,0 @@
title: "OpenClaw Docs"
description: "A TypeScript/Node gateway + macOS/iOS/Android companions for WhatsApp (web) and Telegram (bot)."
markdown: kramdown
highlighter: rouge
# Keep GitHub Pages' default page URLs (e.g. /gateway.html). Many docs links
# are written as relative *.md links and are rewritten during the build.
plugins:
- jekyll-relative-links
relative_links:
enabled: true
collections: true
defaults:
- scope:
path: ""
values:
layout: default
nav:
- title: "Home"
url: "/"
- title: "OpenClaw Assistant"
url: "/start/openclaw/"
- title: "Gateway"
url: "/gateway/"
- title: "Remote"
url: "/gateway/remote/"
- title: "Discovery"
url: "/gateway/discovery/"
- title: "Configuration"
url: "/gateway/configuration/"
- title: "WebChat"
url: "/web/webchat/"
- title: "macOS App"
url: "/platforms/macos/"
- title: "iOS App"
url: "/platforms/ios/"
- title: "Android App"
url: "/platforms/android/"
- title: "Telegram"
url: "/channels/telegram/"
- title: "Security"
url: "/gateway/security/"
- title: "Troubleshooting"
url: "/gateway/troubleshooting/"
kramdown:
input: GFM
hard_wrap: false
syntax_highlighter: rouge

View File

@@ -1,145 +0,0 @@
<!doctype html>
<html lang="en" data-theme="auto">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="color-scheme" content="light dark" />
<title>
{% if page.url == "/" %}{{ site.title }}{% else %}{{ page.title | default: page.path | split: "/" | last | replace: ".md", "" }} · {{ site.title }}{% endif %}
</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Pixelify+Sans:wght@400..700&family=Fragment+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap"
rel="stylesheet"
/>
<script>
(() => {
try {
const stored = localStorage.getItem("openclaw:theme");
if (stored === "light" || stored === "dark") document.documentElement.dataset.theme = stored;
} catch {
// ignore
}
})();
</script>
<link rel="stylesheet" href="{{ "/assets/terminal.css" | relative_url }}" />
<link rel="stylesheet" href="{{ "/assets/markdown.css" | relative_url }}" />
<script defer src="{{ "/assets/theme.js" | relative_url }}"></script>
</head>
<body>
<a class="skip-link" href="#content">Skip to content</a>
<header class="shell">
<div class="shell__frame" role="banner">
<div class="shell__titlebar">
<div class="brand" aria-label="OpenClaw docs terminal">
<img
class="brand__logo"
src="{{ "/assets/pixel-lobster.svg" | relative_url }}"
alt=""
width="40"
height="40"
decoding="async"
/>
<div class="brand__text">
<div class="brand__name">OpenClaw</div>
<div class="brand__hint">docs // lobster terminal</div>
</div>
</div>
<div class="titlebar__actions">
<a class="titlebar__cta" href="https://github.com/openclaw/openclaw">
<span class="titlebar__cta-label">GitHub</span>
<span class="titlebar__cta-meta">repo</span>
</a>
<a class="titlebar__cta titlebar__cta--accent" href="https://github.com/openclaw/openclaw/releases/latest">
<span class="titlebar__cta-label">Download</span>
<span class="titlebar__cta-meta">latest</span>
</a>
</div>
</div>
<div class="shell__nav" aria-label="Primary">
<nav class="nav">
{% assign nav = site.nav | default: empty %}
{% for item in nav %}
{% assign item_url = item.url | relative_url %}
<a class="nav__link" href="{{ item_url }}">
<span class="nav__chev"></span>{{ item.title }}
</a>
{% endfor %}
</nav>
<div class="shell__status" aria-hidden="true">
<span class="status__dot"></span>
<span class="status__text">
{% if page.url == "/" %}
ready
{% else %}
viewing: {{ page.path }}
{% endif %}
</span>
</div>
</div>
</div>
</header>
<main id="content" class="content" role="main">
<div class="terminal">
<div class="terminal__prompt" aria-hidden="true">
<span class="prompt__user">openclaw</span>@<span class="prompt__host">openclaw</span>:<span class="prompt__path">~/docs</span>$<span class="prompt__cmd">
{% if page.url == "/" %}cat index.md{% else %}less {{ page.path }}{% endif %}
</span>
</div>
{% if page.summary %}
<p class="terminal__summary">{{ page.summary }}</p>
{% endif %}
{% if page.read_when %}
<details class="terminal__meta">
<summary>Read when…</summary>
<ul>
{% for hint in page.read_when %}
<li>{{ hint }}</li>
{% endfor %}
</ul>
</details>
{% endif %}
<article class="markdown">
{{ content }}
</article>
<footer class="terminal__footer" role="contentinfo">
<div class="footer__line">
<span class="footer__sig">openclaw.ai</span>
<span class="footer__sep">·</span>
<a href="https://github.com/openclaw/openclaw">source</a>
<span class="footer__sep">·</span>
<a href="https://github.com/openclaw/openclaw/releases">releases</a>
</div>
<div class="footer__hint" aria-hidden="true">
tip: press <kbd>F2</kbd> (Mac: <kbd>fn</kbd>+<kbd>F2</kbd>) to flip
the universe
</div>
<div class="footer__actions">
<button
class="theme-toggle"
type="button"
data-theme-toggle
aria-label="Toggle theme (F2; on Mac: fn+F2)"
aria-pressed="false"
>
<span class="theme-toggle__key">F2</span>
<span class="theme-toggle__label" data-theme-label>theme</span>
</button>
</div>
</footer>
</div>
</main>
</body>
</html>

View File

@@ -1,179 +0,0 @@
.markdown {
margin-top: 18px;
line-height: 1.7;
}
.mdx-content > h1:first-of-type {
display: none;
}
.markdown h1,
.markdown h2,
.markdown h3,
.markdown h4 {
font-family: var(--font-pixel);
letter-spacing: 0.04em;
line-height: 1.15;
}
.markdown h1 {
font-size: clamp(28px, 4vw, 44px);
margin: 26px 0 10px;
}
.markdown h2 {
font-size: 22px;
margin: 26px 0 10px;
}
.markdown h3 {
font-size: 18px;
margin: 22px 0 8px;
}
.markdown p {
margin: 0 0 14px;
}
.markdown a {
color: var(--link);
text-decoration: none;
border-bottom: 1px dotted color-mix(in oklab, var(--link) 65%, transparent);
}
.markdown a:hover {
color: var(--link2);
border-bottom-color: color-mix(in oklab, var(--link2) 75%, transparent);
}
.markdown hr {
border: 0;
height: 1px;
background: linear-gradient(
90deg,
transparent,
color-mix(in oklab, var(--frame-border) 30%, transparent),
transparent
);
margin: 26px 0;
}
.markdown blockquote {
margin: 18px 0;
padding: 14px 14px;
border-radius: var(--radius-sm);
background: color-mix(in oklab, var(--panel) 70%, transparent);
border-left: 6px solid color-mix(in oklab, var(--accent) 60%, transparent);
color: var(--muted);
}
.markdown ul,
.markdown ol {
margin: 0 0 14px 22px;
}
.markdown li {
margin: 4px 0;
}
.markdown img {
max-width: 100%;
height: auto;
border-radius: 12px;
border: 1px solid color-mix(in oklab, var(--frame-border) 20%, transparent);
box-shadow: 0 12px 0 -8px rgba(0, 0, 0, 0.18);
}
.showcase-link {
position: relative;
display: inline-flex;
align-items: center;
gap: 6px;
}
.showcase-preview {
position: absolute;
left: 50%;
top: 100%;
width: min(420px, 80vw);
padding: 8px;
border-radius: 14px;
background: color-mix(in oklab, var(--panel) 92%, transparent);
border: 1px solid color-mix(in oklab, var(--frame-border) 30%, transparent);
box-shadow: 0 18px 40px -18px rgba(0, 0, 0, 0.55);
transform: translate(-50%, 10px) scale(0.98);
opacity: 0;
visibility: hidden;
pointer-events: none;
z-index: 20;
transition: opacity 0.18s ease, transform 0.18s ease, visibility 0.18s ease;
}
.showcase-preview img {
width: 100%;
height: auto;
border-radius: 10px;
border: 1px solid color-mix(in oklab, var(--frame-border) 25%, transparent);
box-shadow: none;
}
.showcase-link:hover .showcase-preview,
.showcase-link:focus-within .showcase-preview {
opacity: 1;
visibility: visible;
transform: translate(-50%, 6px) scale(1);
}
@media (hover: none) {
.showcase-preview {
display: none;
}
}
.markdown code {
font-family: var(--font-body);
font-size: 0.95em;
padding: 0.15em 0.35em;
border-radius: 8px;
background: color-mix(in oklab, var(--panel) 70%, var(--code-bg));
border: 1px solid color-mix(in oklab, var(--frame-border) 18%, transparent);
}
.markdown pre {
background: var(--code-bg);
color: var(--code-fg);
padding: 14px 14px;
border-radius: var(--radius-sm);
border: 1px solid color-mix(in oklab, var(--frame-border) 18%, transparent);
overflow-x: auto;
box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--code-accent) 12%, transparent);
}
.markdown pre code {
background: transparent;
border: 0;
padding: 0;
color: inherit;
}
.markdown table {
width: 100%;
border-collapse: collapse;
margin: 16px 0 22px;
border: 1px solid color-mix(in oklab, var(--frame-border) 20%, transparent);
border-radius: var(--radius-sm);
overflow: hidden;
}
.markdown th,
.markdown td {
padding: 10px 10px;
border-bottom: 1px solid color-mix(in oklab, var(--frame-border) 15%, transparent);
vertical-align: top;
}
.markdown th {
background: color-mix(in oklab, var(--panel2) 85%, transparent);
font-family: var(--font-pixel);
letter-spacing: 0.06em;
}

View File

@@ -1,473 +0,0 @@
:root {
--font-body: "Fragment Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
--font-pixel: "Pixelify Sans", system-ui, sans-serif;
--radius: 14px;
--radius-sm: 10px;
--border: 2px;
--shadow-px: 0 0 0 var(--border) var(--frame-border), 0 12px 0 -4px rgba(0, 0, 0, 0.25);
--scanline-size: 6px;
--scanline-opacity: 0.08;
}
html[data-theme="light"],
html[data-theme="auto"] {
--bg0: #fbf4e7;
--bg1: #fffaf0;
--panel: #fffdf8;
--panel2: #fff6e5;
--text: #10221c;
--muted: #3e5a50;
--faint: #6b7f77;
--link: #0f6b4c;
--link2: #ff4f40;
--accent: #ff4f40;
--accent2: #00b88a;
--frame-border: #1b2e27;
--code-bg: #0b1713;
--code-fg: #eafff6;
--code-accent: #67ff9b;
}
html[data-theme="dark"] {
--bg0: #0b1a22;
--bg1: #0a1720;
--panel: #0e231f;
--panel2: #102a24;
--text: #c9eadc;
--muted: #8ab8aa;
--faint: #699b8d;
--link: #6fe8c7;
--link2: #ff7b63;
--accent: #ff4f40;
--accent2: #5fdfa2;
--frame-border: #6fbfa8;
--code-bg: #091814;
--code-fg: #d7f5e8;
--code-accent: #5fdfa2;
}
@media (prefers-color-scheme: dark) {
html[data-theme="auto"] {
--bg0: #0b1a22;
--bg1: #0a1720;
--panel: #0e231f;
--panel2: #102a24;
--text: #c9eadc;
--muted: #8ab8aa;
--faint: #699b8d;
--link: #6fe8c7;
--link2: #ff7b63;
--accent: #ff4f40;
--accent2: #5fdfa2;
--frame-border: #6fbfa8;
--code-bg: #091814;
--code-fg: #d7f5e8;
--code-accent: #5fdfa2;
}
}
* {
box-sizing: border-box;
}
html {
height: 100%;
}
body {
min-height: 100%;
}
body {
margin: 0;
font-family: var(--font-body);
color: var(--text);
background:
radial-gradient(1100px 700px at 20% -10%, color-mix(in oklab, var(--accent) 18%, transparent), transparent 55%),
radial-gradient(900px 600px at 95% 10%, color-mix(in oklab, var(--accent2) 14%, transparent), transparent 60%),
radial-gradient(900px 600px at 50% 120%, color-mix(in oklab, var(--link) 10%, transparent), transparent 55%),
linear-gradient(180deg, var(--bg0), var(--bg1));
overflow-x: hidden;
}
body::before,
body::after {
display: none;
}
.skip-link {
position: absolute;
top: 10px;
left: 10px;
z-index: 10;
padding: 10px 12px;
border-radius: 999px;
background: var(--panel);
color: var(--text);
text-decoration: none;
transform: translateY(-130%);
box-shadow: var(--shadow-px);
}
.skip-link:focus {
transform: translateY(0);
outline: none;
}
.shell {
position: sticky;
top: 0;
z-index: 100;
padding: 22px 16px 10px;
}
.shell__frame {
max-width: 1120px;
margin: 0 auto;
border-radius: var(--radius);
background:
linear-gradient(180deg, color-mix(in oklab, var(--panel2) 88%, transparent), color-mix(in oklab, var(--panel) 92%, transparent));
box-shadow: var(--shadow-px);
border: var(--border) solid var(--frame-border);
overflow: hidden;
}
.shell__titlebar {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 14px 14px 12px;
background:
linear-gradient(90deg, color-mix(in oklab, var(--accent) 26%, transparent), transparent 42%),
linear-gradient(180deg, color-mix(in oklab, var(--panel) 90%, #000 10%), color-mix(in oklab, var(--panel2) 90%, #000 10%));
}
.brand {
display: flex;
align-items: center;
gap: 12px;
min-width: 0;
}
.brand__logo {
flex: 0 0 auto;
width: 40px;
height: 40px;
image-rendering: pixelated;
filter: drop-shadow(0 2px 0 color-mix(in oklab, var(--frame-border) 80%, transparent));
}
.brand__text {
min-width: 0;
}
.brand__name {
font-family: var(--font-pixel);
letter-spacing: 0.14em;
font-weight: 700;
font-size: 18px;
line-height: 1.1;
text-shadow: 0 1px 0 color-mix(in oklab, var(--frame-border) 55%, transparent);
}
.brand__hint {
margin-top: 2px;
font-size: 12px;
color: var(--muted);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.titlebar__actions {
display: flex;
align-items: center;
gap: 10px;
}
.titlebar__cta {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 8px 12px 8px 10px;
border-radius: 12px;
background:
linear-gradient(140deg, color-mix(in oklab, var(--accent) 10%, transparent), transparent 60%),
color-mix(in oklab, var(--panel) 92%, transparent);
border: var(--border) solid color-mix(in oklab, var(--frame-border) 80%, transparent);
color: var(--text);
text-decoration: none;
box-shadow:
0 6px 0 -3px rgba(0, 0, 0, 0.25),
inset 0 0 0 1px color-mix(in oklab, var(--panel2) 55%, transparent);
}
.titlebar__cta:hover {
border-color: color-mix(in oklab, var(--accent2) 45%, transparent);
box-shadow:
0 0 0 2px color-mix(in oklab, var(--accent2) 30%, transparent),
0 6px 0 -3px rgba(0, 0, 0, 0.25);
}
.titlebar__cta:active {
transform: translateY(1px);
box-shadow: 0 4px 0 -3px rgba(0, 0, 0, 0.25);
}
.titlebar__cta:focus-visible {
outline: 3px solid color-mix(in oklab, var(--accent2) 60%, transparent);
outline-offset: 2px;
}
.titlebar__cta--accent {
background:
linear-gradient(120deg, color-mix(in oklab, var(--accent) 22%, transparent), transparent 70%),
color-mix(in oklab, var(--panel) 88%, transparent);
border-color: color-mix(in oklab, var(--accent) 60%, var(--frame-border));
}
.titlebar__cta-label {
font-family: var(--font-pixel);
letter-spacing: 0.12em;
font-size: 12px;
text-transform: uppercase;
}
.titlebar__cta-meta {
display: inline-flex;
align-items: center;
justify-content: center;
height: 20px;
padding: 0 8px;
border-radius: 999px;
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.08em;
background: var(--code-bg);
color: var(--code-accent);
border: 1px solid color-mix(in oklab, var(--code-accent) 30%, transparent);
box-shadow: inset 0 0 12px color-mix(in oklab, var(--code-accent) 25%, transparent);
}
.theme-toggle {
display: inline-flex;
align-items: center;
gap: 10px;
padding: 9px 10px;
border-radius: 12px;
background: color-mix(in oklab, var(--panel) 92%, transparent);
border: var(--border) solid var(--frame-border);
color: var(--text);
cursor: pointer;
box-shadow: 0 6px 0 -3px rgba(0, 0, 0, 0.25);
user-select: none;
}
.theme-toggle:active {
transform: translateY(1px);
box-shadow: 0 4px 0 -3px rgba(0, 0, 0, 0.25);
}
.theme-toggle__key {
display: inline-flex;
align-items: center;
justify-content: center;
width: 36px;
height: 28px;
border-radius: 9px;
background: var(--code-bg);
color: var(--code-accent);
border: 1px solid color-mix(in oklab, var(--code-accent) 30%, transparent);
font-weight: 700;
font-size: 12px;
letter-spacing: 0.06em;
text-shadow: 0 0 14px color-mix(in oklab, var(--code-accent) 55%, transparent);
}
.theme-toggle__label {
font-family: var(--font-pixel);
letter-spacing: 0.12em;
font-size: 12px;
text-transform: uppercase;
}
.theme-toggle:focus-visible {
outline: 3px solid color-mix(in oklab, var(--accent2) 60%, transparent);
outline-offset: 2px;
}
.shell__nav {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
padding: 10px 14px 12px;
border-top: 1px solid color-mix(in oklab, var(--frame-border) 25%, transparent);
background: linear-gradient(180deg, transparent, color-mix(in oklab, var(--panel2) 78%, transparent));
}
.nav {
display: flex;
flex-wrap: wrap;
gap: 12px;
}
.nav__link {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 6px 10px;
border-radius: 999px;
text-decoration: none;
color: var(--text);
background: color-mix(in oklab, var(--panel) 85%, transparent);
border: 1px solid color-mix(in oklab, var(--frame-border) 20%, transparent);
}
.nav__link:hover {
border-color: color-mix(in oklab, var(--accent2) 45%, transparent);
box-shadow: 0 0 0 2px color-mix(in oklab, var(--accent2) 30%, transparent);
}
.nav__chev {
color: var(--accent);
font-weight: 700;
}
.shell__status {
display: inline-flex;
align-items: center;
gap: 10px;
color: var(--muted);
font-size: 12px;
white-space: nowrap;
}
.status__dot {
width: 10px;
height: 10px;
border-radius: 999px;
background: radial-gradient(circle at 30% 30%, var(--accent2), color-mix(in oklab, var(--accent2) 30%, #000));
box-shadow: 0 0 0 2px color-mix(in oklab, var(--accent2) 18%, transparent), 0 0 18px color-mix(in oklab, var(--accent2) 50%, transparent);
}
.content {
padding: 18px 16px 48px;
}
.terminal {
position: relative;
max-width: 1120px;
margin: 0 auto;
border-radius: var(--radius);
border: var(--border) solid var(--frame-border);
background: linear-gradient(180deg, color-mix(in oklab, var(--panel) 92%, transparent), color-mix(in oklab, var(--panel2) 86%, transparent));
box-shadow: var(--shadow-px);
padding: 18px 16px 16px;
}
.terminal__prompt {
display: block;
padding: 10px 12px;
border-radius: var(--radius-sm);
background: var(--code-bg);
color: var(--code-fg);
border: 1px solid color-mix(in oklab, var(--frame-border) 18%, transparent);
overflow-x: auto;
white-space: nowrap;
}
.prompt__user {
color: var(--code-accent);
text-shadow: 0 0 16px color-mix(in oklab, var(--code-accent) 52%, transparent);
}
.prompt__host {
color: color-mix(in oklab, var(--code-fg) 92%, var(--accent2));
}
.prompt__path {
color: color-mix(in oklab, var(--code-fg) 78%, var(--link));
}
.prompt__cmd {
margin-left: 8px;
color: color-mix(in oklab, var(--code-fg) 90%, var(--accent));
}
.terminal__summary {
margin: 12px 2px 0;
color: var(--muted);
font-size: 14px;
line-height: 1.5;
}
.terminal__meta {
margin: 12px 2px 0;
padding: 12px 12px;
border-radius: var(--radius-sm);
border: 1px dashed color-mix(in oklab, var(--frame-border) 25%, transparent);
background: color-mix(in oklab, var(--panel) 76%, transparent);
color: var(--faint);
font-size: 13px;
}
.terminal__meta summary {
cursor: pointer;
font-family: var(--font-pixel);
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--text);
}
.terminal__meta ul {
margin: 10px 0 0 18px;
}
.terminal__footer {
margin-top: 22px;
padding-top: 16px;
border-top: 1px solid color-mix(in oklab, var(--frame-border) 20%, transparent);
color: var(--muted);
font-size: 13px;
}
.footer__actions {
margin-top: 14px;
display: flex;
justify-content: flex-end;
}
.terminal__footer a {
color: var(--link);
text-decoration: none;
border-bottom: 1px dotted color-mix(in oklab, var(--link) 55%, transparent);
}
.terminal__footer a:hover {
color: var(--link2);
border-bottom-color: color-mix(in oklab, var(--link2) 75%, transparent);
}
.footer__hint {
margin-top: 8px;
color: var(--faint);
}
kbd {
font-family: var(--font-body);
font-size: 0.9em;
padding: 2px 6px;
border-radius: 8px;
border: 1px solid color-mix(in oklab, var(--frame-border) 18%, transparent);
background: color-mix(in oklab, var(--panel) 65%, transparent);
box-shadow: 0 6px 0 -4px rgba(0, 0, 0, 0.18);
}
@supports not (color: color-mix(in oklab, black, white)) {
body::before,
body::after {
opacity: 0.2;
}
}

View File

@@ -1,55 +0,0 @@
const THEME_STORAGE_KEY = "openclaw:theme";
function safeGet(key) {
try {
return localStorage.getItem(key);
} catch {
return null;
}
}
function safeSet(key, value) {
try {
localStorage.setItem(key, value);
} catch {
// ignore
}
}
function preferredTheme() {
const stored = safeGet(THEME_STORAGE_KEY);
if (stored === "light" || stored === "dark") return stored;
return window.matchMedia?.("(prefers-color-scheme: dark)").matches ? "dark" : "light";
}
function applyTheme(theme) {
document.documentElement.dataset.theme = theme;
const toggle = document.querySelector("[data-theme-toggle]");
const label = document.querySelector("[data-theme-label]");
if (toggle instanceof HTMLButtonElement) toggle.setAttribute("aria-pressed", theme === "dark" ? "true" : "false");
if (label) label.textContent = theme === "dark" ? "dark" : "light";
}
function toggleTheme() {
const current = document.documentElement.dataset.theme === "dark" ? "dark" : "light";
const next = current === "dark" ? "light" : "dark";
safeSet(THEME_STORAGE_KEY, next);
applyTheme(next);
}
applyTheme(preferredTheme());
document.addEventListener("click", (event) => {
const target = event.target;
const button = target instanceof Element ? target.closest("[data-theme-toggle]") : null;
if (button) toggleTheme();
});
document.addEventListener("keydown", (event) => {
if (event.key === "F2") {
event.preventDefault();
toggleTheme();
}
});

View File

@@ -61,6 +61,9 @@ openclaw devices revoke --device <deviceId> --role node
- `--timeout <ms>`: RPC timeout.
- `--json`: JSON output (recommended for scripting).
Note: when you set `--url`, the CLI does not fall back to config or environment credentials.
Pass `--token` or `--password` explicitly. Missing explicit credentials is an error.
## Notes
- Token rotation returns a new token (sensitive). Treat it like a secret.

View File

@@ -78,6 +78,9 @@ Shared options (where supported):
- `--timeout <ms>`: timeout/budget (varies per command).
- `--expect-final`: wait for a “final” response (agent calls).
Note: when you set `--url`, the CLI does not fall back to config or environment credentials.
Pass `--token` or `--password` explicitly. Missing explicit credentials is an error.
### `gateway health`
```bash

View File

@@ -715,6 +715,8 @@ openclaw logs --no-color
### `gateway <subcommand>`
Gateway CLI helpers (use `--url`, `--token`, `--password`, `--timeout`, `--expect-final` for RPC subcommands).
When you pass `--url`, the CLI does not auto-apply config or environment credentials.
Include `--token` or `--password` explicitly. Missing explicit credentials is an error.
Subcommands:

53
docs/concepts/features.md Normal file
View File

@@ -0,0 +1,53 @@
---
summary: "OpenClaw capabilities across channels, routing, media, and UX."
read_when:
- You want a full list of what OpenClaw supports
title: "Features"
---
## Highlights
<Columns>
<Card title="Channels" icon="message-square">
WhatsApp, Telegram, Discord, and iMessage with a single Gateway.
</Card>
<Card title="Plugins" icon="plug">
Add Mattermost and more with extensions.
</Card>
<Card title="Routing" icon="route">
Multi-agent routing with isolated sessions.
</Card>
<Card title="Media" icon="image">
Images, audio, and documents in and out.
</Card>
<Card title="Apps and UI" icon="monitor">
Web Control UI and macOS companion app.
</Card>
<Card title="Mobile nodes" icon="smartphone">
iOS and Android nodes with Canvas support.
</Card>
</Columns>
## Full list
- WhatsApp integration via WhatsApp Web (Baileys)
- Telegram bot support (grammY)
- Discord bot support (channels.discord.js)
- Mattermost bot support (plugin)
- iMessage integration via local imsg CLI (macOS)
- Agent bridge for Pi in RPC mode with tool streaming
- Streaming and chunking for long responses
- Multi-agent routing for isolated sessions per workspace or sender
- Subscription auth for Anthropic and OpenAI via OAuth
- Sessions: direct chats collapse into shared `main`; groups are isolated
- Group chat support with mention based activation
- Media support for images, audio, and documents
- Optional voice note transcription hook
- WebChat and macOS menu bar app
- iOS node with pairing and Canvas surface
- Android node with pairing, Canvas, chat, and camera
<Note>
Legacy Claude, Codex, Gemini, and Opencode paths have been removed. Pi is the only
coding agent path.
</Note>

View File

@@ -148,7 +148,7 @@ Details: [Thinking + reasoning directives](/tools/thinking) and [Token use](/tok
Outbound message formatting is centralized in `messages`:
- `messages.responsePrefix` (outbound prefix) and `channels.whatsapp.messagePrefix` (WhatsApp inbound prefix)
- `messages.responsePrefix`, `channels.<channel>.responsePrefix`, and `channels.<channel>.accounts.<id>.responsePrefix` (outbound prefix cascade), plus `channels.whatsapp.messagePrefix` (WhatsApp inbound prefix)
- Reply threading via `replyToMode` and per-channel defaults
Details: [Configuration](/gateway/configuration#messages) and channel docs.

4
docs/custom.css Normal file
View File

@@ -0,0 +1,4 @@
#content-area h1:first-of-type,
.prose h1:first-of-type {
display: none !important;
}

View File

@@ -2,28 +2,41 @@
"$schema": "https://mintlify.com/docs.json",
"name": "OpenClaw",
"theme": "mint",
"icons": {
"library": "lucide"
},
"logo": {
"light": "/assets/pixel-lobster.svg",
"dark": "/assets/pixel-lobster.svg"
},
"fonts": {
"body": {
"family": "Fragment Mono"
},
"heading": {
"family": "DM Sans"
}
},
"favicon": "/assets/pixel-lobster.svg",
"colors": {
"primary": "#FF5A36"
"primary": "#FF5A36",
"dark": "#FF5A36",
"light": "#FF8A6B"
},
"navbar": {
"links": [
{
"label": "GitHub",
"href": "https://github.com/openclaw/openclaw",
"icon": "github"
},
{
"label": "Releases",
"href": "https://github.com/openclaw/openclaw/releases",
"icon": "package"
}
]
},
"topbarLinks": [
{
"name": "中文",
"url": "/zh-CN"
},
{
"name": "GitHub",
"url": "https://github.com/openclaw/openclaw"
},
{
"name": "Releases",
"url": "https://github.com/openclaw/openclaw/releases"
}
],
"redirects": [
{
"source": "/cron",
@@ -720,7 +733,7 @@
"groups": [
{
"group": "Overview",
"pages": ["index", "start/showcase", "start/lore"]
"pages": ["index", "concepts/features", "start/showcase", "start/lore"]
},
{
"group": "Installation",
@@ -740,12 +753,14 @@
"group": "Setup",
"pages": [
"start/getting-started",
"start/quickstart",
"start/wizard",
"start/setup",
"start/onboarding",
"start/pairing",
"start/openclaw",
"start/hubs"
"start/hubs",
"start/docs-directory"
]
},
{
@@ -988,7 +1003,12 @@
},
{
"group": "Networking and discovery",
"pages": ["gateway/pairing", "gateway/discovery", "gateway/bonjour"]
"pages": [
"gateway/network-model",
"gateway/pairing",
"gateway/discovery",
"gateway/bonjour"
]
}
]
},
@@ -1114,6 +1134,10 @@
"token-use"
]
},
{
"group": "Project",
"pages": ["reference/credits"]
},
{
"group": "Release notes",
"pages": ["reference/RELEASING", "reference/test"]

View File

@@ -1517,6 +1517,25 @@ See [Messages](/concepts/messages) for queueing, sessions, and streaming context
`responsePrefix` is applied to **all outbound replies** (tool summaries, block
streaming, final replies) across channels unless already present.
Overrides can be configured per channel and per account:
- `channels.<channel>.responsePrefix`
- `channels.<channel>.accounts.<id>.responsePrefix`
Resolution order (most specific wins):
1. `channels.<channel>.accounts.<id>.responsePrefix`
2. `channels.<channel>.responsePrefix`
3. `messages.responsePrefix`
Semantics:
- `undefined` falls through to the next level.
- `""` explicitly disables the prefix and stops the cascade.
- `"auto"` derives `[{identity.name}]` for the routed agent.
Overrides apply to all channels, including extensions, and to every outbound reply kind.
If `messages.responsePrefix` is unset, no prefix is applied by default. WhatsApp self-chat
replies are the exception: they default to `[{identity.name}]` when set, otherwise
`[openclaw]`, so same-phone conversations stay legible.

View File

@@ -87,6 +87,7 @@ and logged; a message that is only `HEARTBEAT_OK` is dropped.
includeReasoning: false, // default: false (deliver separate Reasoning: message when available)
target: "last", // last | none | <channel id> (core or plugin, e.g. "bluebubbles")
to: "+15551234567", // optional channel-specific override
accountId: "ops-bot", // optional multi-account channel id
prompt: "Read HEARTBEAT.md if it exists (workspace context). Follow it strictly. Do not infer or repeat old tasks from prior chats. If nothing needs attention, reply HEARTBEAT_OK.",
ackMaxChars: 300, // max chars allowed after HEARTBEAT_OK
},
@@ -136,6 +137,35 @@ Example: two agents, only the second agent runs heartbeats.
}
```
### Multi account example
Use `accountId` to target a specific account on multi-account channels like Telegram:
```json5
{
agents: {
list: [
{
id: "ops",
heartbeat: {
every: "1h",
target: "telegram",
to: "12345678",
accountId: "ops-bot",
},
},
],
},
channels: {
telegram: {
accounts: {
"ops-bot": { botToken: "YOUR_TELEGRAM_BOT_TOKEN" },
},
},
},
}
```
### Field notes
- `every`: heartbeat interval (duration string; default unit = minutes).
@@ -150,6 +180,7 @@ Example: two agents, only the second agent runs heartbeats.
- explicit channel: `whatsapp` / `telegram` / `discord` / `googlechat` / `slack` / `msteams` / `signal` / `imessage`.
- `none`: run the heartbeat but **do not deliver** externally.
- `to`: optional recipient override (channel-specific id, e.g. E.164 for WhatsApp or a Telegram chat id).
- `accountId`: optional account id for multi-account channels. When `target: "last"`, the account id applies to the resolved last channel if it supports accounts; otherwise it is ignored. If the account id does not match a configured account for the resolved channel, delivery is skipped.
- `prompt`: overrides the default prompt body (not merged).
- `ackMaxChars`: max chars allowed after `HEARTBEAT_OK` before delivery.

View File

@@ -0,0 +1,17 @@
---
summary: "How the Gateway, nodes, and canvas host connect."
read_when:
- You want a concise view of the Gateway networking model
title: "Network model"
---
Most operations flow through the Gateway (`openclaw gateway`), a single long-running
process that owns channel connections and the WebSocket control plane.
## Core rules
- One Gateway per host is recommended. It is the only process allowed to own the WhatsApp Web session. For rescue bots or strict isolation, run multiple gateways with isolated profiles and ports. See [Multiple gateways](/gateway/multiple-gateways).
- Loopback first: the Gateway WS defaults to `ws://127.0.0.1:18789`. The wizard generates a gateway token by default, even for loopback. For tailnet access, run `openclaw gateway --bind tailnet --token ...` because tokens are required for non-loopback binds.
- Nodes connect to the Gateway WS over LAN, tailnet, or SSH as needed. The legacy TCP bridge is deprecated.
- Canvas host is an HTTP file server on `canvasHost.port` (default `18793`) serving `/__openclaw__/canvas/` for node WebViews. See [Gateway configuration](/gateway/configuration) (`canvasHost`).
- Remote use is typically SSH tunnel or tailnet VPN. See [Remote access](/gateway/remote) and [Discovery](/gateway/discovery).

View File

@@ -80,6 +80,8 @@ With the tunnel up:
- `openclaw gateway {status,health,send,agent,call}` can also target the forwarded URL via `--url` when needed.
Note: replace `18789` with your configured `gateway.port` (or `--port`/`OPENCLAW_GATEWAY_PORT`).
Note: when you pass `--url`, the CLI does not fall back to config or environment credentials.
Include `--token` or `--password` explicitly. Missing explicit credentials is an error.
## CLI remote defaults

View File

@@ -1,5 +1,5 @@
---
summary: "Top-level overview of OpenClaw, features, and purpose"
summary: "OpenClaw is a multi-channel gateway for AI agents that runs on any OS."
read_when:
- Introducing OpenClaw to newcomers
title: "OpenClaw"
@@ -7,8 +7,6 @@ title: "OpenClaw"
# OpenClaw 🦞
> _"EXFOLIATE! EXFOLIATE!"_ — A space lobster, probably
<p align="center">
<img
src="/assets/openclaw-logo-text-dark.png"
@@ -24,143 +22,98 @@ title: "OpenClaw"
/>
</p>
<p align="center">
<strong>Any OS + WhatsApp/Telegram/Discord/iMessage gateway for AI agents (Pi).</strong><br />
Plugins add Mattermost and more.
Send a message, get an agent response — from your pocket.
</p>
> _"EXFOLIATE! EXFOLIATE!"_ — A space lobster, probably
<p align="center">
<a href="https://github.com/openclaw/openclaw">GitHub</a> ·
<a href="https://github.com/openclaw/openclaw/releases">Releases</a> ·
<a href="/">Docs</a> ·
<a href="/start/openclaw">OpenClaw assistant setup</a>
<strong>Any OS gateway for AI agents across WhatsApp, Telegram, Discord, iMessage, and more.</strong><br />
Send a message, get an agent response from your pocket. Plugins add Mattermost and more.
</p>
OpenClaw bridges WhatsApp (via WhatsApp Web / Baileys), Telegram (Bot API / grammY), Discord (Bot API / channels.discord.js), and iMessage (imsg CLI) to coding agents like [Pi](https://github.com/badlogic/pi-mono). Plugins add Mattermost (Bot API + WebSocket) and more.
OpenClaw also powers the OpenClaw assistant.
<Columns>
<Card title="Get Started" href="/start/getting-started" icon="rocket">
Install OpenClaw and bring up the Gateway in minutes.
</Card>
<Card title="Run the Wizard" href="/start/wizard" icon="sparkles">
Guided setup with `openclaw onboard` and pairing flows.
</Card>
<Card title="Open the Control UI" href="/web/control-ui" icon="layout-dashboard">
Launch the browser dashboard for chat, config, and sessions.
</Card>
</Columns>
## Start here
OpenClaw connects chat apps to coding agents like Pi through a single Gateway process. It powers the OpenClaw assistant and supports local or remote setups.
- **New install from zero:** [Getting Started](/start/getting-started)
- **Guided setup (recommended):** [Wizard](/start/wizard) (`openclaw onboard`)
- **Open the dashboard (local Gateway):** http://127.0.0.1:18789/ (or http://localhost:18789/)
## How it works
If the Gateway is running on the same computer, that link opens the browser Control UI
immediately. If it fails, start the Gateway first: `openclaw gateway`.
```mermaid
flowchart LR
A["Chat apps + plugins"] --> B["Gateway"]
B --> C["Pi agent"]
B --> D["CLI"]
B --> E["Web Control UI"]
B --> F["macOS app"]
B --> G["iOS and Android nodes"]
```
## Dashboard (browser Control UI)
The Gateway is the single source of truth for sessions, routing, and channel connections.
The dashboard is the browser Control UI for chat, config, nodes, sessions, and more.
Local default: http://127.0.0.1:18789/
Remote access: [Web surfaces](/web) and [Tailscale](/gateway/tailscale)
## Key capabilities
<Columns>
<Card title="Multi-channel gateway" icon="network">
WhatsApp, Telegram, Discord, and iMessage with a single Gateway process.
</Card>
<Card title="Plugin channels" icon="plug">
Add Mattermost and more with extension packages.
</Card>
<Card title="Multi-agent routing" icon="route">
Isolated sessions per agent, workspace, or sender.
</Card>
<Card title="Media support" icon="image">
Send and receive images, audio, and documents.
</Card>
<Card title="Web Control UI" icon="monitor">
Browser dashboard for chat, config, sessions, and nodes.
</Card>
<Card title="Mobile nodes" icon="smartphone">
Pair iOS and Android nodes with Canvas support.
</Card>
</Columns>
## Quick start
<Steps>
<Step title="Install OpenClaw">
```bash
npm install -g openclaw@latest
```
</Step>
<Step title="Onboard and install the service">
```bash
openclaw onboard --install-daemon
```
</Step>
<Step title="Pair WhatsApp and start the Gateway">
```bash
openclaw channels login
openclaw gateway --port 18789
```
</Step>
</Steps>
Need the full install and dev setup? See [Quick start](/start/quickstart).
## Dashboard
Open the browser Control UI after the Gateway starts.
- Local default: http://127.0.0.1:18789/
- Remote access: [Web surfaces](/web) and [Tailscale](/gateway/tailscale)
<p align="center">
<img src="whatsapp-openclaw.jpg" alt="OpenClaw" width="420" />
</p>
## How it works
```
WhatsApp / Telegram / Discord / iMessage (+ plugins)
┌───────────────────────────┐
│ Gateway │ ws://127.0.0.1:18789 (loopback-only)
│ (single source) │
│ │ http://<gateway-host>:18793
│ │ /__openclaw__/canvas/ (Canvas host)
└───────────┬───────────────┘
├─ Pi agent (RPC)
├─ CLI (openclaw …)
├─ Chat UI (SwiftUI)
├─ macOS app (OpenClaw.app)
├─ iOS node via Gateway WS + pairing
└─ Android node via Gateway WS + pairing
```
Most operations flow through the **Gateway** (`openclaw gateway`), a single long-running process that owns channel connections and the WebSocket control plane.
## Network model
- **One Gateway per host (recommended)**: it is the only process allowed to own the WhatsApp Web session. If you need a rescue bot or strict isolation, run multiple gateways with isolated profiles and ports; see [Multiple gateways](/gateway/multiple-gateways).
- **Loopback-first**: Gateway WS defaults to `ws://127.0.0.1:18789`.
- The wizard now generates a gateway token by default (even for loopback).
- For Tailnet access, run `openclaw gateway --bind tailnet --token ...` (token is required for non-loopback binds).
- **Nodes**: connect to the Gateway WebSocket (LAN/tailnet/SSH as needed); legacy TCP bridge is deprecated/removed.
- **Canvas host**: HTTP file server on `canvasHost.port` (default `18793`), serving `/__openclaw__/canvas/` for node WebViews; see [Gateway configuration](/gateway/configuration) (`canvasHost`).
- **Remote use**: SSH tunnel or tailnet/VPN; see [Remote access](/gateway/remote) and [Discovery](/gateway/discovery).
## Features (high level)
- 📱 **WhatsApp Integration** — Uses Baileys for WhatsApp Web protocol
- ✈️ **Telegram Bot** — DMs + groups via grammY
- 🎮 **Discord Bot** — DMs + guild channels via channels.discord.js
- 🧩 **Mattermost Bot (plugin)** — Bot token + WebSocket events
- 💬 **iMessage** — Local imsg CLI integration (macOS)
- 🤖 **Agent bridge** — Pi (RPC mode) with tool streaming
- ⏱️ **Streaming + chunking** — Block streaming + Telegram draft streaming details ([/concepts/streaming](/concepts/streaming))
- 🧠 **Multi-agent routing** — Route provider accounts/peers to isolated agents (workspace + per-agent sessions)
- 🔐 **Subscription auth** — Anthropic (Claude Pro/Max) + OpenAI (ChatGPT/Codex) via OAuth
- 💬 **Sessions** — Direct chats collapse into shared `main` (default); groups are isolated
- 👥 **Group Chat Support** — Mention-based by default; owner can toggle `/activation always|mention`
- 📎 **Media Support** — Send and receive images, audio, documents
- 🎤 **Voice notes** — Optional transcription hook
- 🖥️ **WebChat + macOS app** — Local UI + menu bar companion for ops and voice wake
- 📱 **iOS node** — Pairs as a node and exposes a Canvas surface
- 📱 **Android node** — Pairs as a node and exposes Canvas + Chat + Camera
Note: legacy Claude/Codex/Gemini/Opencode paths have been removed; Pi is the only coding-agent path.
## Quick start
Runtime requirement: **Node ≥ 22**.
```bash
# Recommended: global install (npm/pnpm)
npm install -g openclaw@latest
# or: pnpm add -g openclaw@latest
# Onboard + install the service (launchd/systemd user service)
openclaw onboard --install-daemon
# Pair WhatsApp Web (shows QR)
openclaw channels login
# Gateway runs via the service after onboarding; manual run is still possible:
openclaw gateway --port 18789
```
Switching between npm and git installs later is easy: install the other flavor and run `openclaw doctor` to update the gateway service entrypoint.
From source (development):
```bash
git clone https://github.com/openclaw/openclaw.git
cd openclaw
pnpm install
pnpm ui:build # auto-installs UI deps on first run
pnpm build
openclaw onboard --install-daemon
```
If you dont have a global install yet, run the onboarding step via `pnpm openclaw ...` from the repo.
Multi-instance quickstart (optional):
```bash
OPENCLAW_CONFIG_PATH=~/.openclaw/a.json \
OPENCLAW_STATE_DIR=~/.openclaw-a \
openclaw gateway --port 19001
```
Send a test message (requires a running Gateway):
```bash
openclaw message send --target +15555550123 --message "Hello from OpenClaw"
```
## Configuration (optional)
Config lives at `~/.openclaw/openclaw.json`.
@@ -182,77 +135,45 @@ Example:
}
```
## Docs
## Start here
- Start here:
- [Docs hubs (all pages linked)](/start/hubs)
- [Help](/help) ← _common fixes + troubleshooting_
- [Configuration](/gateway/configuration)
- [Configuration examples](/gateway/configuration-examples)
- [Slash commands](/tools/slash-commands)
- [Multi-agent routing](/concepts/multi-agent)
- [Updating / rollback](/install/updating)
- [Pairing (DM + nodes)](/start/pairing)
- [Nix mode](/install/nix)
- [OpenClaw assistant setup](/start/openclaw)
- [Skills](/tools/skills)
- [Skills config](/tools/skills-config)
- [Workspace templates](/reference/templates/AGENTS)
- [RPC adapters](/reference/rpc)
- [Gateway runbook](/gateway)
- [Nodes (iOS/Android)](/nodes)
- [Web surfaces (Control UI)](/web)
- [Discovery + transports](/gateway/discovery)
- [Remote access](/gateway/remote)
- Providers and UX:
- [WebChat](/web/webchat)
- [Control UI (browser)](/web/control-ui)
- [Telegram](/channels/telegram)
- [Discord](/channels/discord)
- [Mattermost (plugin)](/channels/mattermost)
- [BlueBubbles (iMessage)](/channels/bluebubbles)
- [iMessage (legacy)](/channels/imessage)
- [Groups](/concepts/groups)
- [WhatsApp group messages](/concepts/group-messages)
- [Media: images](/nodes/images)
- [Media: audio](/nodes/audio)
- Companion apps:
- [macOS app](/platforms/macos)
- [iOS app](/platforms/ios)
- [Android app](/platforms/android)
- [Windows (WSL2)](/platforms/windows)
- [Linux app](/platforms/linux)
- Ops and safety:
- [Sessions](/concepts/session)
- [Cron jobs](/automation/cron-jobs)
- [Webhooks](/automation/webhook)
- [Gmail hooks (Pub/Sub)](/automation/gmail-pubsub)
- [Security](/gateway/security)
- [Troubleshooting](/gateway/troubleshooting)
<Columns>
<Card title="Docs hubs" href="/start/hubs" icon="book-open">
All docs and guides, organized by use case.
</Card>
<Card title="Configuration" href="/gateway/configuration" icon="settings">
Core Gateway settings, tokens, and provider config.
</Card>
<Card title="Remote access" href="/gateway/remote" icon="globe">
SSH and tailnet access patterns.
</Card>
<Card title="Channels" href="/channels/telegram" icon="message-square">
Channel-specific setup for WhatsApp, Telegram, Discord, and more.
</Card>
<Card title="Nodes" href="/nodes" icon="smartphone">
iOS and Android nodes with pairing and Canvas.
</Card>
<Card title="Help" href="/help" icon="life-buoy">
Common fixes and troubleshooting entry point.
</Card>
</Columns>
## The name
## Learn more
**OpenClaw = CLAW + TARDIS** — because every space lobster needs a time-and-space machine.
---
_"We're all just playing with our own prompts."_ — an AI, probably high on tokens
## Credits
- **Peter Steinberger** ([@steipete](https://x.com/steipete)) — Creator, lobster whisperer
- **Mario Zechner** ([@badlogicc](https://x.com/badlogicgames)) — Pi creator, security pen-tester
- **Clawd** — The space lobster who demanded a better name
## Core Contributors
- **Maxim Vovshin** (@Hyaxia, 36747317+Hyaxia@users.noreply.github.com) — Blogwatcher skill
- **Nacho Iacovino** (@nachoiacovino, nacho.iacovino@gmail.com) — Location parsing (Telegram + WhatsApp)
## License
MIT — Free as a lobster in the ocean 🦞
---
_"We're all just playing with our own prompts."_ — An AI, probably high on tokens
<Columns>
<Card title="Full feature list" href="/concepts/features" icon="list">
Complete channel, routing, and media capabilities.
</Card>
<Card title="Multi-agent routing" href="/concepts/multi-agent" icon="route">
Workspace isolation and per-agent sessions.
</Card>
<Card title="Security" href="/gateway/security" icon="shield">
Tokens, allowlists, and safety controls.
</Card>
<Card title="Troubleshooting" href="/gateway/troubleshooting" icon="wrench">
Gateway diagnostics and common errors.
</Card>
<Card title="About and credits" href="/reference/credits" icon="info">
Project origins, contributors, and license.
</Card>
</Columns>

27
docs/reference/credits.md Normal file
View File

@@ -0,0 +1,27 @@
---
summary: "Project origin, contributors, and license."
read_when:
- You want the project backstory or contributor credits
title: "Credits"
---
## The name
OpenClaw = CLAW + TARDIS, because every space lobster needs a time and space machine.
## Credits
- **Peter Steinberger** ([@steipete](https://x.com/steipete)) - Creator, lobster whisperer
- **Mario Zechner** ([@badlogicc](https://x.com/badlogicgames)) - Pi creator, security pen tester
- **Clawd** - The space lobster who demanded a better name
## Core contributors
- **Maxim Vovshin** (@Hyaxia, 36747317+Hyaxia@users.noreply.github.com) - Blogwatcher skill
- **Nacho Iacovino** (@nachoiacovino, nacho.iacovino@gmail.com) - Location parsing (Telegram and WhatsApp)
## License
MIT - Free as a lobster in the ocean.
> "We are all just playing with our own prompts." (An AI, probably high on tokens)

View File

@@ -0,0 +1,63 @@
---
summary: "Curated links to the most used OpenClaw docs."
read_when:
- You want quick access to key docs pages
title: "Docs directory"
---
<Note>
For a complete map of the docs, see [Docs hubs](/start/hubs).
</Note>
## Start here
- [Docs hubs (all pages linked)](/start/hubs)
- [Help](/help)
- [Configuration](/gateway/configuration)
- [Configuration examples](/gateway/configuration-examples)
- [Slash commands](/tools/slash-commands)
- [Multi-agent routing](/concepts/multi-agent)
- [Updating and rollback](/install/updating)
- [Pairing (DM and nodes)](/start/pairing)
- [Nix mode](/install/nix)
- [OpenClaw assistant setup](/start/openclaw)
- [Skills](/tools/skills)
- [Skills config](/tools/skills-config)
- [Workspace templates](/reference/templates/AGENTS)
- [RPC adapters](/reference/rpc)
- [Gateway runbook](/gateway)
- [Nodes (iOS and Android)](/nodes)
- [Web surfaces (Control UI)](/web)
- [Discovery and transports](/gateway/discovery)
- [Remote access](/gateway/remote)
## Providers and UX
- [WebChat](/web/webchat)
- [Control UI (browser)](/web/control-ui)
- [Telegram](/channels/telegram)
- [Discord](/channels/discord)
- [Mattermost (plugin)](/channels/mattermost)
- [BlueBubbles (iMessage)](/channels/bluebubbles)
- [iMessage (legacy)](/channels/imessage)
- [Groups](/concepts/groups)
- [WhatsApp group messages](/concepts/group-messages)
- [Media images](/nodes/images)
- [Media audio](/nodes/audio)
## Companion apps
- [macOS app](/platforms/macos)
- [iOS app](/platforms/ios)
- [Android app](/platforms/android)
- [Windows (WSL2)](/platforms/windows)
- [Linux app](/platforms/linux)
## Operations and safety
- [Sessions](/concepts/session)
- [Cron jobs](/automation/cron-jobs)
- [Webhooks](/automation/webhook)
- [Gmail hooks (Pub/Sub)](/automation/gmail-pubsub)
- [Security](/gateway/security)
- [Troubleshooting](/gateway/troubleshooting)

View File

@@ -13,11 +13,13 @@ Use these hubs to discover every page, including deep dives and reference docs t
- [Index](/)
- [Getting Started](/start/getting-started)
- [Quick start](/start/quickstart)
- [Onboarding](/start/onboarding)
- [Wizard](/start/wizard)
- [Setup](/start/setup)
- [Dashboard (local Gateway)](http://127.0.0.1:18789/)
- [Help](/help)
- [Docs directory](/start/docs-directory)
- [Configuration](/gateway/configuration)
- [Configuration examples](/gateway/configuration-examples)
- [OpenClaw assistant](/start/openclaw)
@@ -34,6 +36,7 @@ Use these hubs to discover every page, including deep dives and reference docs t
## Core concepts
- [Architecture](/concepts/architecture)
- [Features](/concepts/features)
- [Network hub](/network)
- [Agent runtime](/concepts/agent)
- [Agent workspace](/concepts/agent-workspace)
@@ -81,6 +84,7 @@ Use these hubs to discover every page, including deep dives and reference docs t
## Gateway + operations
- [Gateway runbook](/gateway)
- [Network model](/gateway/network-model)
- [Gateway pairing](/gateway/pairing)
- [Gateway lock](/gateway/gateway-lock)
- [Background process](/gateway/background-process)
@@ -178,6 +182,10 @@ Use these hubs to discover every page, including deep dives and reference docs t
- [Research: memory](/experiments/research/memory)
- [Model config exploration](/experiments/proposals/model-config)
## Project
- [Credits](/reference/credits)
## Testing + release
- [Testing](/reference/test)

81
docs/start/quickstart.md Normal file
View File

@@ -0,0 +1,81 @@
---
summary: "Install OpenClaw, onboard the Gateway, and pair your first channel."
read_when:
- You want the fastest path from install to a working Gateway
title: "Quick start"
---
<Note>
OpenClaw requires Node 22 or newer.
</Note>
## Install
<Tabs>
<Tab title="npm">
```bash
npm install -g openclaw@latest
```
</Tab>
<Tab title="pnpm">
```bash
pnpm add -g openclaw@latest
```
</Tab>
</Tabs>
## Onboard and run the Gateway
<Steps>
<Step title="Onboard and install the service">
```bash
openclaw onboard --install-daemon
```
</Step>
<Step title="Pair WhatsApp">
```bash
openclaw channels login
```
</Step>
<Step title="Start the Gateway">
```bash
openclaw gateway --port 18789
```
</Step>
</Steps>
After onboarding, the Gateway runs via the user service. You can still run it manually with `openclaw gateway`.
<Info>
Switching between npm and git installs later is easy. Install the other flavor and run
`openclaw doctor` to update the gateway service entrypoint.
</Info>
## From source (development)
```bash
git clone https://github.com/openclaw/openclaw.git
cd openclaw
pnpm install
pnpm ui:build # auto-installs UI deps on first run
pnpm build
openclaw onboard --install-daemon
```
If you do not have a global install yet, run onboarding via `pnpm openclaw ...` from the repo.
## Multi instance quickstart (optional)
```bash
OPENCLAW_CONFIG_PATH=~/.openclaw/a.json \
OPENCLAW_STATE_DIR=~/.openclaw-a \
openclaw gateway --port 19001
```
## Send a test message
Requires a running Gateway.
```bash
openclaw message send --target +15555550123 --message "Hello from OpenClaw"
```

View File

@@ -465,6 +465,9 @@ Gateway-backed tools (`canvas`, `nodes`, `cron`):
- `gatewayToken` (if auth enabled)
- `timeoutMs`
Note: when `gatewayUrl` is set, include `gatewayToken` explicitly. Tools do not inherit config
or environment credentials for overrides, and missing explicit credentials is an error.
Browser tool:
- `profile` (optional; defaults to `browser.defaultProfile`)

View File

@@ -142,6 +142,9 @@ Other Gateway slash commands (for example, `/context`) are forwarded to the Gate
- `--thinking <level>`: Override thinking level for sends
- `--timeout-ms <ms>`: Agent timeout in ms (defaults to `agents.defaults.timeoutSeconds`)
Note: when you set `--url`, the TUI does not fall back to config or environment credentials.
Pass `--token` or `--password` explicitly. Missing explicit credentials is an error.
## Troubleshooting
No output after sending a message:

View File

@@ -201,6 +201,8 @@ Notes:
- `gatewayUrl` is stored in localStorage after load and removed from the URL.
- `token` is stored in localStorage; `password` is kept in memory only.
- When `gatewayUrl` is set, the UI does not fall back to config or environment credentials.
Provide `token` (or `password`) explicitly. Missing explicit credentials is an error.
- Use `wss://` when the Gateway is behind TLS (Tailscale Serve, HTTPS proxy, etc.).
- `gatewayUrl` is only accepted in a top-level window (not embedded) to prevent clickjacking.
- For cross-origin dev setups (e.g. `pnpm ui:dev` to a remote Gateway), add the UI

View File

@@ -0,0 +1,59 @@
---
read_when:
- 你想了解 OpenClaw 支持的完整功能列表
summary: OpenClaw 在渠道、路由、媒体和用户体验方面的功能。
title: 功能
x-i18n:
generated_at: "2026-02-04T17:53:22Z"
model: claude-opus-4-5
provider: pi
source_hash: 1b6aee0bfda751824cb6b3a99080b4c80c00ffb355a96f9cff1b596d55d15ed4
source_path: concepts/features.md
workflow: 15
---
## 亮点
<Columns>
<Card title="渠道" icon="message-square">
通过单个 Gateway 网关支持 WhatsApp、Telegram、Discord 和 iMessage。
</Card>
<Card title="插件" icon="plug">
通过扩展添加 Mattermost 等更多平台。
</Card>
<Card title="路由" icon="route">
多智能体路由,支持隔离会话。
</Card>
<Card title="媒体" icon="image">
支持图片、音频和文档的收发。
</Card>
<Card title="应用与界面" icon="monitor">
Web 控制界面和 macOS 配套应用。
</Card>
<Card title="移动节点" icon="smartphone">
iOS 和 Android 节点,支持 Canvas。
</Card>
</Columns>
## 完整列表
- 通过 WhatsApp WebBaileys集成 WhatsApp
- Telegram 机器人支持grammY
- Discord 机器人支持channels.discord.js
- Mattermost 机器人支持(插件)
- 通过本地 imsg CLI 集成 iMessagemacOS
- Pi 的智能体桥接,支持 RPC 模式和工具流式传输
- 长响应的流式传输和分块处理
- 多智能体路由,按工作区或发送者隔离会话
- 通过 OAuth 进行 Anthropic 和 OpenAI 的订阅认证
- 会话:私信合并为共享的 `main`;群组相互隔离
- 群聊支持,通过提及激活
- 图片、音频和文档的媒体支持
- 可选的语音消息转录钩子
- WebChat 和 macOS 菜单栏应用
- iOS 节点,支持配对和 Canvas 界面
- Android 节点支持配对、Canvas、聊天和相机
<Note>
旧版 Claude、Codex、Gemini 和 Opencode 路径已被移除。Pi 是唯一的编程智能体路径。
</Note>

View File

@@ -0,0 +1,23 @@
---
read_when:
- 你想要简要了解 Gateway 网关的网络模型
summary: Gateway 网关、节点和 canvas 主机如何连接。
title: 网络模型
x-i18n:
generated_at: "2026-02-04T17:53:21Z"
model: claude-opus-4-5
provider: pi
source_hash: e3508b884757ef19f425c82e891e2b07e7fd7d985413d569e55ae9b175c91f0f
source_path: gateway/network-model.md
workflow: 15
---
大多数操作通过 Gateway 网关(`openclaw gateway`)进行,它是一个长期运行的单一进程,负责管理渠道连接和 WebSocket 控制平面。
## 核心规则
- 建议每台主机运行一个 Gateway 网关。它是唯一允许拥有 WhatsApp Web 会话的进程。对于救援机器人或严格隔离的场景,可以使用隔离的配置文件和端口运行多个 Gateway 网关。参见[多 Gateway 网关](/gateway/multiple-gateways)。
- 优先使用回环地址Gateway 网关的 WS 默认为 `ws://127.0.0.1:18789`。即使是回环连接,向导也会默认生成 gateway token。若需通过 tailnet 访问,请运行 `openclaw gateway --bind tailnet --token ...`,因为非回环绑定必须使用 token。
- 节点根据需要通过局域网、tailnet 或 SSH 连接到 Gateway 网关的 WS。旧版 TCP 桥接已弃用。
- Canvas 主机是一个 HTTP 文件服务器,运行在 `canvasHost.port`(默认 `18793`)上,提供 `/__openclaw__/canvas/` 路径供节点 WebView 使用。参见 [Gateway 网关配置](/gateway/configuration)`canvasHost`)。
- 远程使用通常通过 SSH 隧道或 Tailscale VPN。参见[远程访问](/gateway/remote)和[设备发现](/gateway/discovery)。

View File

@@ -1,21 +1,19 @@
---
read_when:
- 向新用户介绍 OpenClaw
summary: OpenClaw 的顶层概述、功能和用途
summary: OpenClaw 是一个多渠道 AI 智能体 Gateway 网关,可在任何操作系统上运行。
title: OpenClaw
x-i18n:
generated_at: "2026-02-03T10:07:04Z"
generated_at: "2026-02-04T17:53:40Z"
model: claude-opus-4-5
provider: pi
source_hash: 1e0923d87f184a7d8b16afa0d0d0214ce27aec0c3e6ffb359e6226f8e5f1a152
source_hash: fc8babf7885ef91d526795051376d928599c4cf8aff75400138a0d7d9fa3b75f
source_path: index.md
workflow: 15
---
# OpenClaw 🦞
> _"EXFOLIATE! EXFOLIATE!"_ — 大概是一只太空龙虾说的
<p align="center">
<img
src="/assets/openclaw-logo-text-dark.png"
@@ -31,149 +29,104 @@ x-i18n:
/>
</p>
<p align="center">
<strong>适用于任何操作系统的 WhatsApp/Telegram/Discord/iMessage AI 智能体PiGateway 网关。</strong><br />
插件可添加 Mattermost 等更多渠道。
发送消息,获取智能体响应——尽在口袋中。
</p>
> _"去壳!去壳!"_ — 大概是一只太空龙虾说的
<p align="center">
<a href="https://github.com/openclaw/openclaw">GitHub</a> ·
<a href="https://github.com/openclaw/openclaw/releases">发布版本</a> ·
<a href="/">文档</a> ·
<a href="/start/openclaw">OpenClaw 助手设置</a>
<strong>适用于任何操作系统的 AI 智能体 Gateway 网关,支持 WhatsApp、Telegram、Discord、iMessage 等。</strong><br />
发送消息,随时随地获取智能体响应。通过插件可添加 Mattermost 等更多渠道。
</p>
OpenClaw 将 WhatsApp通过 WhatsApp Web / Baileys、TelegramBot API / grammY、DiscordBot API / channels.discord.js和 iMessageimsg CLI桥接到像 [Pi](https://github.com/badlogic/pi-mono) 这样的编程智能体。插件可添加 MattermostBot API + WebSocket等更多渠道。
OpenClaw 也为 OpenClaw 助手提供支持。
<Columns>
<Card title="入门指南" href="/start/getting-started" icon="rocket">
安装 OpenClaw 并在几分钟内启动 Gateway 网关。
</Card>
<Card title="运行向导" href="/start/wizard" icon="sparkles">
通过 `openclaw onboard` 和配对流程进行引导式设置。
</Card>
<Card title="打开控制界面" href="/web/control-ui" icon="layout-dashboard">
启动浏览器仪表板,管理聊天、配置和会话。
</Card>
</Columns>
## 从这里开始
OpenClaw 通过单个 Gateway 网关进程将聊天应用连接到 Pi 等编程智能体。它为 OpenClaw 助手提供支持,并支持本地或远程部署。
- **从零开始新安装:** [入门指南](/start/getting-started)
- **引导式设置(推荐):** [向导](/start/wizard)`openclaw onboard`
- **打开仪表板(本地 Gateway 网关):** http://127.0.0.1:18789/(或 http://localhost:18789/
## 工作原理
如果 Gateway 网关运行在同一台计算机上,该链接会立即打开浏览器控制 UI。
如果失败,请先启动 Gateway 网关:`openclaw gateway`
```mermaid
flowchart LR
A["Chat apps + plugins"] --> B["Gateway"]
B --> C["Pi agent"]
B --> D["CLI"]
B --> E["Web Control UI"]
B --> F["macOS app"]
B --> G["iOS and Android nodes"]
```
## 仪表板(浏览器控制 UI
Gateway 网关是会话、路由和渠道连接的唯一事实来源。
仪表板是用于聊天、配置、节点、会话等的浏览器控制 UI。
本地默认http://127.0.0.1:18789/
远程访问:[Web 界面](/web) 和 [Tailscale](/gateway/tailscale)
## 核心功能
<Columns>
<Card title="多渠道 Gateway 网关" icon="network">
通过单个 Gateway 网关进程连接 WhatsApp、Telegram、Discord 和 iMessage。
</Card>
<Card title="插件渠道" icon="plug">
通过扩展包添加 Mattermost 等更多渠道。
</Card>
<Card title="多智能体路由" icon="route">
按智能体、工作区或发送者隔离会话。
</Card>
<Card title="媒体支持" icon="image">
发送和接收图片、音频和文档。
</Card>
<Card title="Web 控制界面" icon="monitor">
浏览器仪表板,用于聊天、配置、会话和节点管理。
</Card>
<Card title="移动节点" icon="smartphone">
配对 iOS 和 Android 节点,支持 Canvas。
</Card>
</Columns>
## 快速开始
<Steps>
<Step title="安装 OpenClaw">
```bash
npm install -g openclaw@latest
```
</Step>
<Step title="新手引导并安装服务">
```bash
openclaw onboard --install-daemon
```
</Step>
<Step title="配对 WhatsApp 并启动 Gateway 网关">
```bash
openclaw channels login
openclaw gateway --port 18789
```
</Step>
</Steps>
需要完整的安装和开发环境设置?请参阅[快速开始](/start/quickstart)。
## 仪表板
Gateway 网关启动后,打开浏览器控制界面。
- 本地默认地址http://127.0.0.1:18789/
- 远程访问:[Web 界面](/web)和 [Tailscale](/gateway/tailscale)
<p align="center">
<img src="whatsapp-openclaw.jpg" alt="OpenClaw" width="420" />
</p>
## 工作原理
```
WhatsApp / Telegram / Discord / iMessage+ 插件)
┌───────────────────────────┐
│ Gateway 网关 │ ws://127.0.0.1:18789仅 loopback
│ (单一来源) │
│ │ http://<gateway-host>:18793
│ │ /__openclaw__/canvas/Canvas 主机)
└───────────┬───────────────┘
├─ Pi 智能体RPC
├─ CLIopenclaw …)
├─ 聊天 UISwiftUI
├─ macOS 应用OpenClaw.app
├─ iOS 节点,通过 Gateway WS + 配对
└─ Android 节点,通过 Gateway WS + 配对
```
大多数操作通过 **Gateway 网关**`openclaw gateway`)进行,这是一个长期运行的单一进程,拥有渠道连接和 WebSocket 控制平面。
## 网络模型
- **每台主机一个 Gateway 网关(推荐)**:它是唯一允许拥有 WhatsApp Web 会话的进程。如果你需要救援机器人或严格隔离,请使用隔离的配置文件和端口运行多个 Gateway 网关;参见[多 Gateway 网关](/gateway/multiple-gateways)。
- **loopback 优先**Gateway 网关 WS 默认为 `ws://127.0.0.1:18789`
- 向导现在默认生成 Gateway 网关令牌(即使是 loopback
- 对于 Tailnet 访问,运行 `openclaw gateway --bind tailnet --token ...`(非 loopback 绑定需要令牌)。
- **节点**:连接到 Gateway 网关 WebSocket根据需要通过 LAN/tailnet/SSH旧版 TCP 桥接已弃用/移除。
- **Canvas 主机**:在 `canvasHost.port`(默认 `18793`)上的 HTTP 文件服务器,为节点 WebView 提供 `/__openclaw__/canvas/`;参见 [Gateway 网关配置](/gateway/configuration)`canvasHost`)。
- **远程使用**SSH 隧道或 tailnet/VPN参见[远程访问](/gateway/remote)和[设备发现](/gateway/discovery)。
## 功能(高级概述)
- 📱 **WhatsApp 集成** — 使用 Baileys 实现 WhatsApp Web 协议
- ✈️ **Telegram 机器人** — 通过 grammY 支持私信 + 群组
- 🎮 **Discord 机器人** — 通过 channels.discord.js 支持私信 + 服务器频道
- 🧩 **Mattermost 机器人(插件)** — 机器人令牌 + WebSocket 事件
- 💬 **iMessage** — 本地 imsg CLI 集成macOS
- 🤖 **智能体桥接** — PiRPC 模式)支持工具流式传输
- ⏱️ **流式传输 + 分块** — 分块流式传输 + Telegram 草稿流式传输详情([/concepts/streaming](/concepts/streaming)
- 🧠 **多智能体路由** — 将提供商账户/对等方路由到隔离的智能体(工作区 + 每智能体会话)
- 🔐 **订阅认证** — 通过 OAuth 支持 AnthropicClaude Pro/Max+ OpenAIChatGPT/Codex
- 💬 **会话** — 私聊折叠到共享的 `main`(默认);群组是隔离的
- 👥 **群聊支持** — 默认基于提及;所有者可切换 `/activation always|mention`
- 📎 **媒体支持** — 发送和接收图片、音频、文档
- 🎤 **语音消息** — 可选的转录钩子
- 🖥️ **WebChat + macOS 应用** — 本地 UI + 用于操作和语音唤醒的菜单栏配套应用
- 📱 **iOS 节点** — 作为节点配对并暴露 Canvas 界面
- 📱 **Android 节点** — 作为节点配对并暴露 Canvas + 聊天 + 相机
注意:旧版 Claude/Codex/Gemini/Opencode 路径已移除Pi 是唯一的编程智能体路径。
## 快速开始
运行时要求:**Node ≥ 22**。
```bash
# 推荐全局安装npm/pnpm
npm install -g openclaw@latest
# 或pnpm add -g openclaw@latest
# 新手引导 + 安装服务launchd/systemd 用户服务)
openclaw onboard --install-daemon
# 配对 WhatsApp Web显示二维码
openclaw channels login
# 新手引导后 Gateway 网关通过服务运行;手动运行仍然可行:
openclaw gateway --port 18789
```
之后在 npm 和 git 安装之间切换很简单:安装另一种方式并运行 `openclaw doctor` 来更新 Gateway 网关服务入口点。
从源代码(开发):
```bash
git clone https://github.com/openclaw/openclaw.git
cd openclaw
pnpm install
pnpm ui:build # 首次运行时自动安装 UI 依赖
pnpm build
openclaw onboard --install-daemon
```
如果你还没有全局安装,请从仓库通过 `pnpm openclaw ...` 运行新手引导步骤。
多实例快速开始(可选):
```bash
OPENCLAW_CONFIG_PATH=~/.openclaw/a.json \
OPENCLAW_STATE_DIR=~/.openclaw-a \
openclaw gateway --port 19001
```
发送测试消息(需要运行中的 Gateway 网关):
```bash
openclaw message send --target +15555550123 --message "Hello from OpenClaw"
```
## 配置(可选)
配置位于 `~/.openclaw/openclaw.json`
配置文件位于 `~/.openclaw/openclaw.json`。
- 如果你**什么都不做**OpenClaw 使用内置的 Pi 二进制文件以 RPC 模式运行,按发送者会话。
- 如果你想锁定它,从 `channels.whatsapp.allowFrom` 开始,以及(对于群组)提及规则。
- 如果你**不做任何修改**OpenClaw 使用内置的 Pi 二进制文件以 RPC 模式运行,按发送者创建独立会话。
- 如果你想要限制访问,可以从 `channels.whatsapp.allowFrom` 和(针对群组)提及规则开始配置
示例:
@@ -189,76 +142,45 @@ openclaw message send --target +15555550123 --message "Hello from OpenClaw"
}
```
## 文档
## 从这里开始
- 从这里开始:
- [文档中心(所有页面链接)](/start/hubs)
- [帮助](/help) ← _常见修复 + 故障排除_
- [配置](/gateway/configuration)
- [配置示例](/gateway/configuration-examples)
- [斜杠命令](/tools/slash-commands)
- [多智能体路由](/concepts/multi-agent)
- [更新/回滚](/install/updating)
- [配对(私信 + 节点)](/start/pairing)
- [Nix 模式](/install/nix)
- [OpenClaw 助手设置](/start/openclaw)
- [Skills](/tools/skills)
- [Skills 配置](/tools/skills-config)
- [工作区模板](/reference/templates/AGENTS)
- [RPC 适配器](/reference/rpc)
- [Gateway 网关运维手册](/gateway)
- [节点iOS/Android](/nodes)
- [Web 界面(控制 UI](/web)
- [设备发现 + 传输协议](/gateway/discovery)
- [远程访问](/gateway/remote)
- 提供商和用户体验:
- [WebChat](/web/webchat)
- [控制 UI浏览器](/web/control-ui)
- [Telegram](/channels/telegram)
- [Discord](/channels/discord)
- [Mattermost插件](/channels/mattermost)
- [iMessage](/channels/imessage)
- [群组](/concepts/groups)
- [WhatsApp 群组消息](/concepts/group-messages)
- [媒体:图片](/nodes/images)
- [媒体:音频](/nodes/audio)
- 配套应用:
- [macOS 应用](/platforms/macos)
- [iOS 应用](/platforms/ios)
- [Android 应用](/platforms/android)
- [WindowsWSL2](/platforms/windows)
- [Linux 应用](/platforms/linux)
- 运维和安全:
- [会话](/concepts/session)
- [定时任务](/automation/cron-jobs)
- [Webhooks](/automation/webhook)
- [Gmail 钩子Pub/Sub](/automation/gmail-pubsub)
- [安全性](/gateway/security)
- [故障排除](/gateway/troubleshooting)
<Columns>
<Card title="文档中心" href="/start/hubs" icon="book-open">
所有文档和指南,按用例分类。
</Card>
<Card title="配置" href="/gateway/configuration" icon="settings">
核心 Gateway 网关设置、令牌和提供商配置。
</Card>
<Card title="远程访问" href="/gateway/remote" icon="globe">
SSH 和 tailnet 访问模式。
</Card>
<Card title="渠道" href="/channels/telegram" icon="message-square">
WhatsApp、Telegram、Discord 等渠道的具体设置。
</Card>
<Card title="节点" href="/nodes" icon="smartphone">
iOS 和 Android 节点的配对与 Canvas 功能。
</Card>
<Card title="帮助" href="/help" icon="life-buoy">
常见修复方法和故障排除入口。
</Card>
</Columns>
## 名称由来
## 了解更多
**OpenClaw = CLAW + TARDIS** — 因为每只太空龙虾都需要一台时空机器。
---
_"我们都只是在玩弄自己的提示词。"_ — 一个 AI可能正处于 token 兴奋状态
## 致谢
- **Peter Steinberger**[@steipete](https://x.com/steipete))— 创建者,龙虾低语者
- **Mario Zechner**[@badlogicc](https://x.com/badlogicgames))— Pi 创建者,安全渗透测试员
- **Clawd** — 那只要求更好名字的太空龙虾
## 核心贡献者
- **Maxim Vovshin**@Hyaxia, 36747317+Hyaxia@users.noreply.github.com— Blogwatcher skill
- **Nacho Iacovino**@nachoiacovino, nacho.iacovino@gmail.com— 位置解析Telegram + WhatsApp
## 许可证
MIT — 像海洋中的龙虾一样自由 🦞
---
_"我们都只是在玩弄自己的提示词。"_ — 一个 AI可能正处于 token 兴奋状态
<Columns>
<Card title="完整功能列表" href="/concepts/features" icon="list">
全部渠道、路由和媒体功能。
</Card>
<Card title="多智能体路由" href="/concepts/multi-agent" icon="route">
工作区隔离和按智能体的会话管理。
</Card>
<Card title="安全" href="/gateway/security" icon="shield">
令牌、白名单和安全控制。
</Card>
<Card title="故障排除" href="/gateway/troubleshooting" icon="wrench">
Gateway 网关诊断和常见错误。
</Card>
<Card title="关于与致谢" href="/reference/credits" icon="info">
项目起源、贡献者和许可证。
</Card>
</Columns>

View File

@@ -0,0 +1,34 @@
---
read_when:
- 你想了解项目背景故事或贡献者致谢信息
summary: 项目起源、贡献者和许可证。
title: 致谢
x-i18n:
generated_at: "2026-02-04T17:53:19Z"
model: claude-opus-4-5
provider: pi
source_hash: d55e520313e131025b22cb20b3d2fbd44619e1668d09b5bd9d56d7df019bc46c
source_path: reference/credits.md
workflow: 15
---
## 名称由来
OpenClaw = CLAW + TARDIS因为每只太空龙虾都需要一台时空机器。
## 致谢
- **Peter Steinberger** ([@steipete](https://x.com/steipete)) - 创建者,龙虾语者
- **Mario Zechner** ([@badlogicc](https://x.com/badlogicgames)) - Pi 创建者,安全渗透测试员
- **Clawd** - 那只要求取个更好名字的太空龙虾
## 核心贡献者
- **Maxim Vovshin** (@Hyaxia, 36747317+Hyaxia@users.noreply.github.com) - Blogwatcher skill
- **Nacho Iacovino** (@nachoiacovino, nacho.iacovino@gmail.com) - 位置解析Telegram 和 WhatsApp
## 许可证
MIT - 像海洋中的龙虾一样自由。
> "我们都只是在玩自己的提示词而已。"(某个 AI大概是 token 吸多了)

View File

@@ -0,0 +1,70 @@
---
read_when:
- 你想快速访问关键文档页面
summary: 精选的常用 OpenClaw 文档链接。
title: 文档目录
x-i18n:
generated_at: "2026-02-04T17:53:20Z"
model: claude-opus-4-5
provider: pi
source_hash: 489085dae583ba0690b1b972f037610313973df95813283069c95a06bdc949fa
source_path: start/docs-directory.md
workflow: 15
---
<Note>
如需查看完整的文档地图,请参阅[文档中心](/start/hubs)。
</Note>
## 从这里开始
- [文档中心(所有页面链接)](/start/hubs)
- [帮助](/help)
- [配置](/gateway/configuration)
- [配置示例](/gateway/configuration-examples)
- [斜杠命令](/tools/slash-commands)
- [多智能体路由](/concepts/multi-agent)
- [更新与回滚](/install/updating)
- [配对(私信和节点)](/start/pairing)
- [Nix 模式](/install/nix)
- [OpenClaw 助手设置](/start/openclaw)
- [Skills](/tools/skills)
- [Skills 配置](/tools/skills-config)
- [工作区模板](/reference/templates/AGENTS)
- [RPC 适配器](/reference/rpc)
- [Gateway 网关运维手册](/gateway)
- [节点iOS 和 Android](/nodes)
- [Web 界面(控制面板 UI](/web)
- [设备发现与传输协议](/gateway/discovery)
- [远程访问](/gateway/remote)
## 提供商与用户体验
- [WebChat](/web/webchat)
- [控制面板 UI浏览器](/web/control-ui)
- [Telegram](/channels/telegram)
- [Discord](/channels/discord)
- [Mattermost插件](/channels/mattermost)
- [BlueBubbles (iMessage)](/channels/bluebubbles)
- [iMessage旧版](/channels/imessage)
- [群组](/concepts/groups)
- [WhatsApp 群消息](/concepts/group-messages)
- [媒体图片](/nodes/images)
- [媒体音频](/nodes/audio)
## 配套应用
- [macOS 应用](/platforms/macos)
- [iOS 应用](/platforms/ios)
- [Android 应用](/platforms/android)
- [Windows (WSL2)](/platforms/windows)
- [Linux 应用](/platforms/linux)
## 运维与安全
- [会话](/concepts/session)
- [定时任务](/automation/cron-jobs)
- [Webhooks](/automation/webhook)
- [Gmail 钩子Pub/Sub](/automation/gmail-pubsub)
- [安全](/gateway/security)
- [故障排除](/gateway/troubleshooting)

View File

@@ -1,35 +1,37 @@
---
read_when:
- 你想要文档的完整地图
summary: 链接到每 OpenClaw 文档的中心
title: 文档中心
- 你想要一份完整的文档地图
summary: 链接到每 OpenClaw 文档的导航中心
title: 文档导航中心
x-i18n:
generated_at: "2026-02-03T10:10:07Z"
generated_at: "2026-02-04T17:55:29Z"
model: claude-opus-4-5
provider: pi
source_hash: 2635f570266e9c4b13436a684eea0819ed10a6276a8ab6caf4f9764c60093a1a
source_hash: c4b4572b64d36c9690988b8f964b0712f551ee6491b18a493701a17d2d352cb4
source_path: start/hubs.md
workflow: 15
---
# 文档中心
# 文档导航中心
使用这些中心发现每个页面,包括左侧导航中未显示的深入指南和参考文档
使用这些导航中心发现每个页面,包括深入解析和参考文档——它们不一定出现在左侧导航栏中
## 从这里开始
- [索引](/)
- [入门指南](/start/getting-started)
- [快速开始](/start/quickstart)
- [新手引导](/start/onboarding)
- [向导](/start/wizard)
- [](/start/setup)
- [仪表(本地 Gateway 网关)](http://127.0.0.1:18789/)
- [安装配](/start/setup)
- [仪表(本地 Gateway 网关)](http://127.0.0.1:18789/)
- [帮助](/help)
- [文档目录](/start/docs-directory)
- [配置](/gateway/configuration)
- [配置示例](/gateway/configuration-examples)
- [OpenClaw 助手](/start/openclaw)
- [展示案例](/start/showcase)
- [传说](/start/lore)
- [展示](/start/showcase)
- [背景故事](/start/lore)
## 安装 + 更新
@@ -41,6 +43,7 @@ x-i18n:
## 核心概念
- [架构](/concepts/architecture)
- [功能](/concepts/features)
- [网络中心](/network)
- [智能体运行时](/concepts/agent)
- [智能体工作区](/concepts/agent-workspace)
@@ -73,12 +76,13 @@ x-i18n:
- [模型提供商中心](/providers/models)
- [WhatsApp](/channels/whatsapp)
- [Telegram](/channels/telegram)
- [TelegramgrammY 笔记](/channels/grammy)
- [TelegramgrammY 注意事项](/channels/grammy)
- [Slack](/channels/slack)
- [Discord](/channels/discord)
- [Mattermost](/channels/mattermost)(插件)
- [Signal](/channels/signal)
- [iMessage](/channels/imessage)
- [BlueBubbles (iMessage)](/channels/bluebubbles)
- [iMessage旧版](/channels/imessage)
- [位置解析](/channels/location)
- [WebChat](/web/webchat)
- [Webhooks](/automation/webhook)
@@ -87,6 +91,7 @@ x-i18n:
## Gateway 网关 + 运维
- [Gateway 网关运维手册](/gateway)
- [网络模型](/gateway/network-model)
- [Gateway 网关配对](/gateway/pairing)
- [Gateway 网关锁](/gateway/gateway-lock)
- [后台进程](/gateway/background-process)
@@ -95,8 +100,8 @@ x-i18n:
- [Doctor](/gateway/doctor)
- [日志](/gateway/logging)
- [沙箱隔离](/gateway/sandboxing)
- [仪表](/web/dashboard)
- [Control UI](/web/control-ui)
- [仪表](/web/dashboard)
- [控制界面](/web/control-ui)
- [远程访问](/gateway/remote)
- [远程 Gateway 网关 README](/gateway/remote-gateway-readme)
- [Tailscale](/gateway/tailscale)
@@ -105,27 +110,27 @@ x-i18n:
## 工具 + 自动化
- [工具接口](/tools)
- [工具概览](/tools)
- [OpenProse](/prose)
- [CLI 参考](/cli)
- [Exec 工具](/tools/exec)
- [模式](/tools/elevated)
- [模式](/tools/elevated)
- [定时任务](/automation/cron-jobs)
- [Cron vs 心跳](/automation/cron-vs-heartbeat)
- [思考 + 详细模式](/tools/thinking)
- [定时任务 vs 心跳](/automation/cron-vs-heartbeat)
- [思考 + 详细输出](/tools/thinking)
- [模型](/concepts/models)
- [子智能体](/tools/subagents)
- [Agent send CLI](/tools/agent-send)
- [终端 UI](/tui)
- [终端界面](/tui)
- [浏览器控制](/tools/browser)
- [浏览器Linux 故障排除)](/tools/browser-linux-troubleshooting)
- [投票](/automation/poll)
- [轮询](/automation/poll)
## 节点、媒体、语音
- [节点概](/nodes)
- [节点概](/nodes)
- [摄像头](/nodes/camera)
- [](/nodes/images)
- [](/nodes/images)
- [音频](/nodes/audio)
- [位置命令](/nodes/location-command)
- [语音唤醒](/nodes/voicewake)
@@ -133,22 +138,22 @@ x-i18n:
## 平台
- [平台概](/platforms)
- [平台概](/platforms)
- [macOS](/platforms/macos)
- [iOS](/platforms/ios)
- [Android](/platforms/android)
- [WindowsWSL2](/platforms/windows)
- [Windows (WSL2)](/platforms/windows)
- [Linux](/platforms/linux)
- [Web 界面](/web)
## macOS 配套应用(高级)
- [macOS 开发](/platforms/mac/dev-setup)
- [macOS 开发环境配](/platforms/mac/dev-setup)
- [macOS 菜单栏](/platforms/mac/menu-bar)
- [macOS 语音唤醒](/platforms/mac/voicewake)
- [macOS 语音悬浮窗](/platforms/mac/voice-overlay)
- [macOS WebChat](/platforms/mac/webchat)
- [macOS 画布](/platforms/mac/canvas)
- [macOS Canvas](/platforms/mac/canvas)
- [macOS 子进程](/platforms/mac/child-process)
- [macOS 健康检查](/platforms/mac/health)
- [macOS 图标](/platforms/mac/icon)
@@ -157,7 +162,7 @@ x-i18n:
- [macOS 远程](/platforms/mac/remote)
- [macOS 签名](/platforms/mac/signing)
- [macOS 发布](/platforms/mac/release)
- [macOS Gateway 网关launchd](/platforms/mac/bundled-gateway)
- [macOS Gateway 网关 (launchd)](/platforms/mac/bundled-gateway)
- [macOS XPC](/platforms/mac/xpc)
- [macOS Skills](/platforms/mac/skills)
- [macOS Peekaboo](/platforms/mac/peekaboo)
@@ -179,13 +184,17 @@ x-i18n:
## 实验(探索性)
- [新手引导配置协议](/experiments/onboarding-config-protocol)
- [Cron 加固笔记](/experiments/plans/cron-add-hardening)
- [定时任务加固笔记](/experiments/plans/cron-add-hardening)
- [群组策略加固笔记](/experiments/plans/group-policy-hardening)
- [研究:记忆](/experiments/research/memory)
- [模型配置探索](/experiments/proposals/model-config)
## 项目
- [致谢](/reference/credits)
## 测试 + 发布
- [测试](/reference/test)
- [发布清单](/reference/RELEASING)
- [发布检查清单](/reference/RELEASING)
- [设备型号](/reference/device-models)

View File

@@ -0,0 +1,88 @@
---
read_when:
- 你希望以最快的方式从安装到运行一个可用的 Gateway 网关
summary: 安装 OpenClaw完成 Gateway 网关新手引导,并配对你的第一个渠道。
title: 快速开始
x-i18n:
generated_at: "2026-02-04T17:53:21Z"
model: claude-opus-4-5
provider: pi
source_hash: 3c5da65996f89913cd115279ae21dcab794eadd14595951b676d8f7864fbbe2d
source_path: start/quickstart.md
workflow: 15
---
<Note>
OpenClaw 需要 Node 22 或更新版本。
</Note>
## 安装
<Tabs>
<Tab title="npm">
```bash
npm install -g openclaw@latest
```
</Tab>
<Tab title="pnpm">
```bash
pnpm add -g openclaw@latest
```
</Tab>
</Tabs>
## 新手引导并运行 Gateway 网关
<Steps>
<Step title="新手引导并安装服务">
```bash
openclaw onboard --install-daemon
```
</Step>
<Step title="配对 WhatsApp">
```bash
openclaw channels login
```
</Step>
<Step title="启动 Gateway 网关">
```bash
openclaw gateway --port 18789
```
</Step>
</Steps>
完成新手引导后Gateway 网关将通过用户服务运行。你也可以使用 `openclaw gateway` 手动启动。
<Info>
之后在 npm 安装和 git 安装之间切换非常简单。安装另一种方式后,运行
`openclaw doctor` 即可更新 Gateway 网关服务入口点。
</Info>
## 从源码安装(开发)
```bash
git clone https://github.com/openclaw/openclaw.git
cd openclaw
pnpm install
pnpm ui:build # 首次运行时会自动安装 UI 依赖
pnpm build
openclaw onboard --install-daemon
```
如果你还没有全局安装,可以在仓库目录中通过 `pnpm openclaw ...` 运行新手引导。
## 多实例快速开始(可选)
```bash
OPENCLAW_CONFIG_PATH=~/.openclaw/a.json \
OPENCLAW_STATE_DIR=~/.openclaw-a \
openclaw gateway --port 19001
```
## 发送测试消息
需要一个正在运行的 Gateway 网关。
```bash
openclaw message send --target +15555550123 --message "Hello from OpenClaw"
```

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/bluebubbles",
"version": "2026.2.2",
"version": "2026.2.3",
"description": "OpenClaw BlueBubbles channel plugin",
"type": "module",
"devDependencies": {

View File

@@ -1,6 +1,7 @@
import type { IncomingMessage, ServerResponse } from "node:http";
import type { OpenClawConfig } from "openclaw/plugin-sdk";
import {
createReplyPrefixOptions,
logAckFailure,
logInboundDrop,
logTypingFailure,
@@ -2173,10 +2174,17 @@ async function processMessage(
}, typingRestartDelayMs);
};
try {
const { onModelSelected, ...prefixOptions } = createReplyPrefixOptions({
cfg: config,
agentId: route.agentId,
channel: "bluebubbles",
accountId: account.accountId,
});
await core.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
ctx: ctxPayload,
cfg: config,
dispatcherOptions: {
...prefixOptions,
deliver: async (payload, info) => {
const rawReplyToId =
typeof payload.replyToId === "string" ? payload.replyToId.trim() : "";
@@ -2288,6 +2296,7 @@ async function processMessage(
},
},
replyOptions: {
onModelSelected,
disableBlockStreaming:
typeof account.config.blockStreaming === "boolean"
? !account.config.blockStreaming

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/copilot-proxy",
"version": "2026.2.2",
"version": "2026.2.3",
"description": "OpenClaw Copilot Proxy provider plugin",
"type": "module",
"devDependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/diagnostics-otel",
"version": "2026.2.2",
"version": "2026.2.3",
"description": "OpenClaw diagnostics OpenTelemetry exporter",
"type": "module",
"dependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/discord",
"version": "2026.2.2",
"version": "2026.2.3",
"description": "OpenClaw Discord channel plugin",
"type": "module",
"devDependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/feishu",
"version": "2026.2.2",
"version": "2026.2.3",
"description": "OpenClaw Feishu channel plugin",
"type": "module",
"devDependencies": {

View File

@@ -37,6 +37,7 @@ const FeishuAccountSchema = z
blockStreaming: z.boolean().optional(),
streaming: z.boolean().optional(),
mediaMaxMb: z.number().optional(),
responsePrefix: z.string().optional(),
groups: z.record(z.string(), FeishuGroupSchema.optional()).optional(),
})
.strict();

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/google-antigravity-auth",
"version": "2026.2.2",
"version": "2026.2.3",
"description": "OpenClaw Google Antigravity OAuth provider plugin",
"type": "module",
"devDependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/google-gemini-cli-auth",
"version": "2026.2.2",
"version": "2026.2.3",
"description": "OpenClaw Gemini CLI OAuth provider plugin",
"type": "module",
"devDependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/googlechat",
"version": "2026.2.2",
"version": "2026.2.3",
"description": "OpenClaw Google Chat channel plugin",
"type": "module",
"dependencies": {

View File

@@ -1,6 +1,6 @@
import type { IncomingMessage, ServerResponse } from "node:http";
import type { OpenClawConfig } from "openclaw/plugin-sdk";
import { resolveMentionGatingWithBypass } from "openclaw/plugin-sdk";
import { createReplyPrefixOptions, resolveMentionGatingWithBypass } from "openclaw/plugin-sdk";
import type {
GoogleChatAnnotation,
GoogleChatAttachment,
@@ -725,10 +725,18 @@ async function processMessageWithPipeline(params: {
}
}
const { onModelSelected, ...prefixOptions } = createReplyPrefixOptions({
cfg: config,
agentId: route.agentId,
channel: "googlechat",
accountId: route.accountId,
});
await core.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
ctx: ctxPayload,
cfg: config,
dispatcherOptions: {
...prefixOptions,
deliver: async (payload) => {
await deliverGoogleChatReply({
payload,
@@ -749,6 +757,9 @@ async function processMessageWithPipeline(params: {
);
},
},
replyOptions: {
onModelSelected,
},
});
}

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/imessage",
"version": "2026.2.2",
"version": "2026.2.3",
"description": "OpenClaw iMessage channel plugin",
"type": "module",
"devDependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/line",
"version": "2026.2.2",
"version": "2026.2.3",
"description": "OpenClaw LINE channel plugin",
"type": "module",
"devDependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/llm-task",
"version": "2026.2.2",
"version": "2026.2.3",
"description": "OpenClaw JSON-only LLM task plugin",
"type": "module",
"devDependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/lobster",
"version": "2026.2.2",
"version": "2026.2.3",
"description": "Lobster workflow tool plugin (typed pipelines + resumable approvals)",
"type": "module",
"devDependencies": {

View File

@@ -1,5 +1,11 @@
# Changelog
## 2026.2.3
### Changes
- Version alignment with core OpenClaw release numbers.
## 2026.2.2
### Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/matrix",
"version": "2026.2.2",
"version": "2026.2.3",
"description": "OpenClaw Matrix channel plugin",
"type": "module",
"dependencies": {

View File

@@ -51,6 +51,7 @@ export const MatrixConfigSchema = z.object({
threadReplies: z.enum(["off", "inbound", "always"]).optional(),
textChunkLimit: z.number().optional(),
chunkMode: z.enum(["length", "newline"]).optional(),
responsePrefix: z.string().optional(),
mediaMaxMb: z.number().optional(),
autoJoin: z.enum(["always", "allowlist", "off"]).optional(),
autoJoinAllowlist: z.array(allowFromEntry).optional(),

View File

@@ -1,6 +1,6 @@
import type { LocationMessageEventContent, MatrixClient } from "@vector-im/matrix-bot-sdk";
import {
createReplyPrefixContext,
createReplyPrefixOptions,
createTypingCallbacks,
formatAllowlistMatchMeta,
logInboundDrop,
@@ -579,7 +579,12 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
channel: "matrix",
accountId: route.accountId,
});
const prefixContext = createReplyPrefixContext({ cfg, agentId: route.agentId });
const { onModelSelected, ...prefixOptions } = createReplyPrefixOptions({
cfg,
agentId: route.agentId,
channel: "matrix",
accountId: route.accountId,
});
const typingCallbacks = createTypingCallbacks({
start: () => sendTypingMatrix(roomId, true, undefined, client),
stop: () => sendTypingMatrix(roomId, false, undefined, client),
@@ -604,8 +609,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
});
const { dispatcher, replyOptions, markDispatchIdle } =
core.channel.reply.createReplyDispatcherWithTyping({
responsePrefix: prefixContext.responsePrefix,
responsePrefixContextProvider: prefixContext.responsePrefixContextProvider,
...prefixOptions,
humanDelay: core.channel.reply.resolveHumanDelayConfig(cfg, route.agentId),
deliver: async (payload) => {
await deliverMatrixReplies({
@@ -635,7 +639,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
replyOptions: {
...replyOptions,
skillFilter: roomConfig?.skills,
onModelSelected: prefixContext.onModelSelected,
onModelSelected,
},
});
markDispatchIdle();

View File

@@ -71,6 +71,8 @@ export type MatrixConfig = {
textChunkLimit?: number;
/** Chunking mode: "length" (default) splits by size; "newline" splits on every newline. */
chunkMode?: "length" | "newline";
/** Outbound response prefix override for this channel/account. */
responsePrefix?: string;
/** Max outbound media size in MB. */
mediaMaxMb?: number;
/** Auto-join invites (always|allowlist|off). Default: always. */

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/mattermost",
"version": "2026.2.2",
"version": "2026.2.3",
"description": "OpenClaw Mattermost channel plugin",
"type": "module",
"devDependencies": {

View File

@@ -1,3 +1,5 @@
import type { OpenClawConfig } from "openclaw/plugin-sdk";
import { createReplyPrefixOptions } from "openclaw/plugin-sdk";
import { describe, expect, it } from "vitest";
import { mattermostPlugin } from "./channel.js";
@@ -44,5 +46,27 @@ describe("mattermostPlugin", () => {
});
expect(formatted).toEqual(["@alice", "user123", "bot999"]);
});
it("uses account responsePrefix overrides", () => {
const cfg: OpenClawConfig = {
channels: {
mattermost: {
responsePrefix: "[Channel]",
accounts: {
default: { responsePrefix: "[Account]" },
},
},
},
};
const prefixContext = createReplyPrefixOptions({
cfg,
agentId: "main",
channel: "mattermost",
accountId: "default",
});
expect(prefixContext.responsePrefix).toBe("[Account]");
});
});
});

View File

@@ -27,6 +27,7 @@ const MattermostAccountSchemaBase = z
chunkMode: z.enum(["length", "newline"]).optional(),
blockStreaming: z.boolean().optional(),
blockStreamingCoalesce: BlockStreamingCoalesceSchema.optional(),
responsePrefix: z.string().optional(),
})
.strict();

View File

@@ -5,7 +5,7 @@ import type {
RuntimeEnv,
} from "openclaw/plugin-sdk";
import {
createReplyPrefixContext,
createReplyPrefixOptions,
createTypingCallbacks,
logInboundDrop,
logTypingFailure,
@@ -760,7 +760,12 @@ export async function monitorMattermostProvider(opts: MonitorMattermostOpts = {}
accountId: account.accountId,
});
const prefixContext = createReplyPrefixContext({ cfg, agentId: route.agentId });
const { onModelSelected, ...prefixOptions } = createReplyPrefixOptions({
cfg,
agentId: route.agentId,
channel: "mattermost",
accountId: account.accountId,
});
const typingCallbacks = createTypingCallbacks({
start: () => sendTypingIndicator(channelId, threadRootId),
@@ -775,8 +780,7 @@ export async function monitorMattermostProvider(opts: MonitorMattermostOpts = {}
});
const { dispatcher, replyOptions, markDispatchIdle } =
core.channel.reply.createReplyDispatcherWithTyping({
responsePrefix: prefixContext.responsePrefix,
responsePrefixContextProvider: prefixContext.responsePrefixContextProvider,
...prefixOptions,
humanDelay: core.channel.reply.resolveHumanDelayConfig(cfg, route.agentId),
deliver: async (payload: ReplyPayload) => {
const mediaUrls = payload.mediaUrls ?? (payload.mediaUrl ? [payload.mediaUrl] : []);
@@ -825,7 +829,7 @@ export async function monitorMattermostProvider(opts: MonitorMattermostOpts = {}
...replyOptions,
disableBlockStreaming:
typeof account.blockStreaming === "boolean" ? !account.blockStreaming : undefined,
onModelSelected: prefixContext.onModelSelected,
onModelSelected,
},
});
markDispatchIdle();

View File

@@ -42,6 +42,8 @@ export type MattermostAccountConfig = {
blockStreaming?: boolean;
/** Merge streamed block replies before sending. */
blockStreamingCoalesce?: BlockStreamingCoalesceConfig;
/** Outbound response prefix override for this channel/account. */
responsePrefix?: string;
};
export type MattermostConfig = {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/memory-core",
"version": "2026.2.2",
"version": "2026.2.3",
"description": "OpenClaw core memory search plugin",
"type": "module",
"devDependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/memory-lancedb",
"version": "2026.2.2",
"version": "2026.2.3",
"description": "OpenClaw LanceDB-backed long-term memory plugin with auto-recall/capture",
"type": "module",
"dependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/minimax-portal-auth",
"version": "2026.2.2",
"version": "2026.2.3",
"description": "OpenClaw MiniMax Portal OAuth provider plugin",
"type": "module",
"devDependencies": {

View File

@@ -1,5 +1,11 @@
# Changelog
## 2026.2.3
### Changes
- Version alignment with core OpenClaw release numbers.
## 2026.2.2
### Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/msteams",
"version": "2026.2.2",
"version": "2026.2.3",
"description": "OpenClaw Microsoft Teams channel plugin",
"type": "module",
"dependencies": {

View File

@@ -493,6 +493,7 @@ export function createMSTeamsMessageHandler(deps: MSTeamsMessageHandlerDeps) {
const { dispatcher, replyOptions, markDispatchIdle } = createMSTeamsReplyDispatcher({
cfg,
agentId: route.agentId,
accountId: route.accountId,
runtime,
log,
adapter,

View File

@@ -1,5 +1,5 @@
import {
createReplyPrefixContext,
createReplyPrefixOptions,
createTypingCallbacks,
logTypingFailure,
resolveChannelMediaMaxBytes,
@@ -26,6 +26,7 @@ import { getMSTeamsRuntime } from "./runtime.js";
export function createMSTeamsReplyDispatcher(params: {
cfg: OpenClawConfig;
agentId: string;
accountId?: string;
runtime: RuntimeEnv;
log: MSTeamsMonitorLogger;
adapter: MSTeamsAdapter;
@@ -55,16 +56,17 @@ export function createMSTeamsReplyDispatcher(params: {
});
},
});
const prefixContext = createReplyPrefixContext({
const { onModelSelected, ...prefixOptions } = createReplyPrefixOptions({
cfg: params.cfg,
agentId: params.agentId,
channel: "msteams",
accountId: params.accountId,
});
const chunkMode = core.channel.text.resolveChunkMode(params.cfg, "msteams");
const { dispatcher, replyOptions, markDispatchIdle } =
core.channel.reply.createReplyDispatcherWithTyping({
responsePrefix: prefixContext.responsePrefix,
responsePrefixContextProvider: prefixContext.responsePrefixContextProvider,
...prefixOptions,
humanDelay: core.channel.reply.resolveHumanDelayConfig(params.cfg, params.agentId),
deliver: async (payload) => {
const tableMode = core.channel.text.resolveMarkdownTableMode({
@@ -124,7 +126,7 @@ export function createMSTeamsReplyDispatcher(params: {
return {
dispatcher,
replyOptions: { ...replyOptions, onModelSelected: prefixContext.onModelSelected },
replyOptions: { ...replyOptions, onModelSelected },
markDispatchIdle,
};
}

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/nextcloud-talk",
"version": "2026.2.2",
"version": "2026.2.3",
"description": "OpenClaw Nextcloud Talk channel plugin",
"type": "module",
"devDependencies": {

View File

@@ -47,6 +47,7 @@ export const NextcloudTalkAccountSchemaBase = z
chunkMode: z.enum(["length", "newline"]).optional(),
blockStreaming: z.boolean().optional(),
blockStreamingCoalesce: BlockStreamingCoalesceSchema.optional(),
responsePrefix: z.string().optional(),
mediaMaxMb: z.number().positive().optional(),
})
.strict();

View File

@@ -1,4 +1,5 @@
import {
createReplyPrefixOptions,
logInboundDrop,
resolveControlCommandGate,
type OpenClawConfig,
@@ -285,10 +286,18 @@ export async function handleNextcloudTalkInbound(params: {
},
});
const { onModelSelected, ...prefixOptions } = createReplyPrefixOptions({
cfg: config as OpenClawConfig,
agentId: route.agentId,
channel: CHANNEL_ID,
accountId: account.accountId,
});
await core.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
ctx: ctxPayload,
cfg: config as OpenClawConfig,
dispatcherOptions: {
...prefixOptions,
deliver: async (payload) => {
await deliverNextcloudTalkReply({
payload: payload as {
@@ -308,6 +317,7 @@ export async function handleNextcloudTalkInbound(params: {
},
replyOptions: {
skillFilter: roomConfig?.skills,
onModelSelected,
disableBlockStreaming:
typeof account.config.blockStreaming === "boolean"
? !account.config.blockStreaming

View File

@@ -68,6 +68,8 @@ export type NextcloudTalkAccountConfig = {
blockStreaming?: boolean;
/** Merge streamed block replies before sending. */
blockStreamingCoalesce?: BlockStreamingCoalesceConfig;
/** Outbound response prefix override for this channel/account. */
responsePrefix?: string;
/** Media upload max size in MB. */
mediaMaxMb?: number;
};

View File

@@ -1,5 +1,11 @@
# Changelog
## 2026.2.3
### Changes
- Version alignment with core OpenClaw release numbers.
## 2026.2.2
### Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/nostr",
"version": "2026.2.2",
"version": "2026.2.3",
"description": "OpenClaw Nostr channel plugin for NIP-04 encrypted DMs",
"type": "module",
"dependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/open-prose",
"version": "2026.2.2",
"version": "2026.2.3",
"description": "OpenProse VM skill pack plugin (slash command + telemetry).",
"type": "module",
"devDependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/signal",
"version": "2026.2.2",
"version": "2026.2.3",
"description": "OpenClaw Signal channel plugin",
"type": "module",
"devDependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/slack",
"version": "2026.2.2",
"version": "2026.2.3",
"description": "OpenClaw Slack channel plugin",
"type": "module",
"devDependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/telegram",
"version": "2026.2.2",
"version": "2026.2.3",
"description": "OpenClaw Telegram channel plugin",
"type": "module",
"devDependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/tlon",
"version": "2026.2.2",
"version": "2026.2.3",
"description": "OpenClaw Tlon/Urbit channel plugin",
"type": "module",
"dependencies": {

View File

@@ -23,6 +23,7 @@ export const TlonAccountSchema = z.object({
dmAllowlist: z.array(ShipSchema).optional(),
autoDiscoverChannels: z.boolean().optional(),
showModelSignature: z.boolean().optional(),
responsePrefix: z.string().optional(),
});
export const TlonConfigSchema = z.object({
@@ -35,6 +36,7 @@ export const TlonConfigSchema = z.object({
dmAllowlist: z.array(ShipSchema).optional(),
autoDiscoverChannels: z.boolean().optional(),
showModelSignature: z.boolean().optional(),
responsePrefix: z.string().optional(),
authorization: TlonAuthorizationSchema.optional(),
defaultAuthorizedShips: z.array(ShipSchema).optional(),
accounts: z.record(z.string(), TlonAccountSchema).optional(),

View File

@@ -1,5 +1,6 @@
import type { RuntimeEnv, ReplyPayload, OpenClawConfig } from "openclaw/plugin-sdk";
import { format } from "node:util";
import { createReplyPrefixOptions } from "openclaw/plugin-sdk";
import { getTlonRuntime } from "../runtime.js";
import { normalizeShip, parseChannelNest } from "../targets.js";
import { resolveTlonAccount } from "../types.js";
@@ -28,6 +29,29 @@ type ChannelAuthorization = {
allowedShips?: string[];
};
type UrbitMemo = {
author?: string;
content?: unknown;
sent?: number;
};
type UrbitUpdate = {
id?: string | number;
response?: {
add?: { memo?: UrbitMemo };
post?: {
id?: string | number;
"r-post"?: {
set?: { essay?: UrbitMemo };
reply?: {
id?: string | number;
"r-reply"?: { set?: { memo?: UrbitMemo } };
};
};
};
};
};
function resolveChannelAuthorization(
cfg: OpenClawConfig,
channelNest: string,
@@ -120,15 +144,14 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
runtime.log?.("[tlon] No group channels to monitor (DMs only)");
}
// oxlint-disable-next-line typescript/no-explicit-any
const handleIncomingDM = async (update: any) => {
const handleIncomingDM = async (update: UrbitUpdate) => {
try {
const memo = update?.response?.add?.memo;
if (!memo) {
return;
}
const messageId = update.id as string | undefined;
const messageId = update.id != null ? String(update.id) : undefined;
if (!processedTracker.mark(messageId)) {
return;
}
@@ -160,25 +183,24 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
}
};
// oxlint-disable-next-line typescript/no-explicit-any
const handleIncomingGroupMessage = (channelNest: string) => async (update: any) => {
const handleIncomingGroupMessage = (channelNest: string) => async (update: UrbitUpdate) => {
try {
const parsed = parseChannelNest(channelNest);
if (!parsed) {
return;
}
const essay = update?.response?.post?.["r-post"]?.set?.essay;
const memo = update?.response?.post?.["r-post"]?.reply?.["r-reply"]?.set?.memo;
const post = update?.response?.post?.["r-post"];
const essay = post?.set?.essay;
const memo = post?.reply?.["r-reply"]?.set?.memo;
if (!essay && !memo) {
return;
}
const content = memo || essay;
const isThreadReply = Boolean(memo);
const messageId = isThreadReply
? update?.response?.post?.["r-post"]?.reply?.id
: update?.response?.post?.id;
const rawMessageId = isThreadReply ? post?.reply?.id : update?.response?.post?.id;
const messageId = rawMessageId != null ? String(rawMessageId) : undefined;
if (!processedTracker.mark(messageId)) {
return;
@@ -355,17 +377,19 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
const dispatchStartTime = Date.now();
const responsePrefix = core.channel.reply.resolveEffectiveMessagesConfig(
const { onModelSelected, ...prefixOptions } = createReplyPrefixOptions({
cfg,
route.agentId,
).responsePrefix;
agentId: route.agentId,
channel: "tlon",
accountId: route.accountId,
});
const humanDelay = core.channel.reply.resolveHumanDelayConfig(cfg, route.agentId);
await core.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
ctx: ctxPayload,
cfg,
dispatcherOptions: {
responsePrefix,
...prefixOptions,
humanDelay,
deliver: async (payload: ReplyPayload) => {
let replyText = payload.text;
@@ -408,6 +432,9 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
);
},
},
replyOptions: {
onModelSelected,
},
});
};

View File

@@ -1,5 +1,11 @@
# Changelog
## 2026.2.3
### Changes
- Version alignment with core OpenClaw release numbers.
## 2026.2.2
### Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/twitch",
"version": "2026.2.2",
"version": "2026.2.3",
"description": "OpenClaw Twitch channel plugin",
"type": "module",
"dependencies": {

View File

@@ -26,6 +26,8 @@ const TwitchAccountSchema = z.object({
allowedRoles: z.array(TwitchRoleSchema).optional(),
/** Require @mention to trigger bot responses */
requireMention: z.boolean().optional(),
/** Outbound response prefix override for this channel/account. */
responsePrefix: z.string().optional(),
/** Twitch client secret (required for token refresh via RefreshingAuthProvider) */
clientSecret: z.string().optional(),
/** Refresh token (required for automatic token refresh) */

View File

@@ -6,6 +6,7 @@
*/
import type { ReplyPayload, OpenClawConfig } from "openclaw/plugin-sdk";
import { createReplyPrefixOptions } from "openclaw/plugin-sdk";
import type { TwitchAccountConfig, TwitchChatMessage } from "./types.js";
import { checkTwitchAccessControl } from "./access-control.js";
import { getOrCreateClientManager } from "./client-manager-registry.js";
@@ -103,11 +104,18 @@ async function processTwitchMessage(params: {
channel: "twitch",
accountId,
});
const { onModelSelected, ...prefixOptions } = createReplyPrefixOptions({
cfg,
agentId: route.agentId,
channel: "twitch",
accountId,
});
await core.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
ctx: ctxPayload,
cfg,
dispatcherOptions: {
...prefixOptions,
deliver: async (payload) => {
await deliverTwitchReply({
payload,
@@ -121,6 +129,9 @@ async function processTwitchMessage(params: {
});
},
},
replyOptions: {
onModelSelected,
},
});
}

View File

@@ -55,6 +55,8 @@ export interface TwitchAccountConfig {
allowedRoles?: TwitchRole[];
/** Require @mention to trigger bot responses */
requireMention?: boolean;
/** Outbound response prefix override for this channel/account. */
responsePrefix?: string;
/** Twitch client secret (required for token refresh via RefreshingAuthProvider) */
clientSecret?: string;
/** Refresh token (required for automatic token refresh) */

View File

@@ -1,5 +1,11 @@
# Changelog
## 2026.2.3
### Changes
- Version alignment with core OpenClaw release numbers.
## 2026.2.2
### Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/voice-call",
"version": "2026.2.2",
"version": "2026.2.3",
"description": "OpenClaw voice-call plugin",
"type": "module",
"dependencies": {

View File

@@ -135,6 +135,36 @@ describe("CallManager", () => {
expect(provider.hangupCalls[0]?.providerCallId).toBe("provider-missing");
});
it("rejects inbound calls with anonymous caller ID when allowlist enabled", () => {
const config = VoiceCallConfigSchema.parse({
enabled: true,
provider: "plivo",
fromNumber: "+15550000000",
inboundPolicy: "allowlist",
allowFrom: ["+15550001234"],
});
const storePath = path.join(os.tmpdir(), `openclaw-voice-call-test-${Date.now()}`);
const provider = new FakeProvider();
const manager = new CallManager(config, storePath);
manager.initialize(provider, "https://example.com/voice/webhook");
manager.processEvent({
id: "evt-allowlist-anon",
type: "call.initiated",
callId: "call-anon",
providerCallId: "provider-anon",
timestamp: Date.now(),
direction: "inbound",
from: "anonymous",
to: "+15550000000",
});
expect(manager.getCallByProviderCallId("provider-anon")).toBeUndefined();
expect(provider.hangupCalls).toHaveLength(1);
expect(provider.hangupCalls[0]?.providerCallId).toBe("provider-anon");
});
it("rejects inbound calls that only match allowlist suffixes", () => {
const config = VoiceCallConfigSchema.parse({
enabled: true,

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/whatsapp",
"version": "2026.2.2",
"version": "2026.2.3",
"description": "OpenClaw WhatsApp channel plugin",
"type": "module",
"devDependencies": {

View File

@@ -1,5 +1,11 @@
# Changelog
## 2026.2.3
### Changes
- Version alignment with core OpenClaw release numbers.
## 2026.2.2
### Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/zalo",
"version": "2026.2.2",
"version": "2026.2.3",
"description": "OpenClaw Zalo channel plugin",
"type": "module",
"dependencies": {

View File

@@ -16,6 +16,7 @@ const zaloAccountSchema = z.object({
allowFrom: z.array(allowFromEntry).optional(),
mediaMaxMb: z.number().optional(),
proxy: z.string().optional(),
responsePrefix: z.string().optional(),
});
export const ZaloConfigSchema = zaloAccountSchema.extend({

View File

@@ -1,5 +1,6 @@
import type { IncomingMessage, ServerResponse } from "node:http";
import type { OpenClawConfig, MarkdownTableMode } from "openclaw/plugin-sdk";
import { createReplyPrefixOptions } from "openclaw/plugin-sdk";
import type { ResolvedZaloAccount } from "./accounts.js";
import {
ZaloApiError,
@@ -583,11 +584,18 @@ async function processMessageWithPipeline(params: {
channel: "zalo",
accountId: account.accountId,
});
const { onModelSelected, ...prefixOptions } = createReplyPrefixOptions({
cfg: config,
agentId: route.agentId,
channel: "zalo",
accountId: account.accountId,
});
await core.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
ctx: ctxPayload,
cfg: config,
dispatcherOptions: {
...prefixOptions,
deliver: async (payload) => {
await deliverZaloReply({
payload,
@@ -606,6 +614,9 @@ async function processMessageWithPipeline(params: {
runtime.error?.(`[${account.accountId}] Zalo ${info.kind} reply failed: ${String(err)}`);
},
},
replyOptions: {
onModelSelected,
},
});
}

View File

@@ -21,6 +21,8 @@ export type ZaloAccountConfig = {
mediaMaxMb?: number;
/** Proxy URL for API requests. */
proxy?: string;
/** Outbound response prefix override for this channel/account. */
responsePrefix?: string;
};
export type ZaloConfig = {

View File

@@ -1,5 +1,11 @@
# Changelog
## 2026.2.3
### Changes
- Version alignment with core OpenClaw release numbers.
## 2026.2.2
### Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/zalouser",
"version": "2026.2.2",
"version": "2026.2.3",
"description": "OpenClaw Zalo Personal Account plugin via zca-cli",
"type": "module",
"dependencies": {

View File

@@ -19,6 +19,7 @@ const zalouserAccountSchema = z.object({
groupPolicy: z.enum(["disabled", "allowlist", "open"]).optional(),
groups: z.object({}).catchall(groupConfigSchema).optional(),
messagePrefix: z.string().optional(),
responsePrefix: z.string().optional(),
});
export const ZalouserConfigSchema = zalouserAccountSchema.extend({

View File

@@ -1,6 +1,6 @@
import type { ChildProcess } from "node:child_process";
import type { OpenClawConfig, MarkdownTableMode, RuntimeEnv } from "openclaw/plugin-sdk";
import { mergeAllowlist, summarizeMapping } from "openclaw/plugin-sdk";
import { createReplyPrefixOptions, mergeAllowlist, summarizeMapping } from "openclaw/plugin-sdk";
import type { ResolvedZalouserAccount, ZcaFriend, ZcaGroup, ZcaMessage } from "./types.js";
import { getZalouserRuntime } from "./runtime.js";
import { sendMessageZalouser } from "./send.js";
@@ -334,10 +334,18 @@ async function processMessage(
},
});
const { onModelSelected, ...prefixOptions } = createReplyPrefixOptions({
cfg: config,
agentId: route.agentId,
channel: "zalouser",
accountId: account.accountId,
});
await core.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
ctx: ctxPayload,
cfg: config,
dispatcherOptions: {
...prefixOptions,
deliver: async (payload) => {
await deliverZalouserReply({
payload: payload as { text?: string; mediaUrls?: string[]; mediaUrl?: string },
@@ -360,6 +368,9 @@ async function processMessage(
runtime.error(`[${account.accountId}] Zalouser ${info.kind} reply failed: ${String(err)}`);
},
},
replyOptions: {
onModelSelected,
},
});
}

Some files were not shown because too many files have changed in this diff Show More