Related: #157877 Related: #108264 ## What Problem This Solves Fixes: a turn delivered to Telegram gets the channel's formatting rules in a different shape, twice, or not at all, depending on how it started. - Reply turns carry the rules inside the inbound metadata. On an account with `richMessages: true`, they also get a separate "Collapsible Details" section, so the `<details>` rule arrives twice. - Cron announce turns (#157877) carry the same rules in a second block with a different schema. - Subagent and requester announce turns, and other delivered agent turns (inter-session steps, `openclaw agent --deliver`), get no formatting rules. ## User Impact User impact: every turn whose visible output is delivered to a channel gets that channel's formatting rules once, in one block. This covers replies, heartbeats, cron announces and subagent announces. For Telegram, the rich-message rules apply only when the delivering account has `richMessages: true`. Other accounts get the standard-formatting rules. Turns with no chat delivery get no rules: no delivery, webhook delivery, subagent children, and Control UI chat. Slack announces now get Slack's rules too. No config change is required. ## Why This Change Was Made - One core function builds the block: `buildDeliveryFormatPrompt`. Reply turns read the loaded plugin that received the message, as before. Cron and agent-command turns resolve the delivering plugin with on-demand loading, for example for the first cron announce after startup. It asks the plugin for the delivering account's rules and renders one trusted `### Delivery Format` block (`openclaw.delivery_format.v1`) into the extra system prompt. This is the path every runtime (embedded, Codex, CLI) and its compaction already reads. - Three entry points call this function, each only when its turn has a channel delivery target: - Reply metadata, which also covers heartbeats and system events. - Cron delivery resolution. - Agent-command session preparation, for turns that deliver or use message-tool delivery. It uses the outbound channel and account chosen by delivery preflight, so a turn that starts on one account and delivers through another gets the delivering account's rules. - Removed: - The cron-only builder and its `openclaw.delivery_meta.v1` schema. - The `response_format` field in the inbound metadata. - Telegram's `markdownDetails` capability. The Telegram contract already contains the `<details>` rule. - The block has no per-turn fields, so its bytes are the same for every turn kind on the same channel and contract. It stays in trusted system metadata and never enters the transcript. The CLI session-binding inputs are unchanged: replies still keep this block out of the static binding text, and cron still hashes it. - External ACP agents do not receive OpenClaw's extra system prompt, so they do not get this block. The docs say "OpenClaw agent turn" for that reason. - Upgrade: the old cron `Delivery Context` block (#157877) is not in any release. Reply turns keep this block out of the CLI session-binding text, as before. A CLI-backed cron session on `main` whose bound prompt text changes resumes with `system-prompt` content drift, not a reset (covered by `src/agents/cli-session.test.ts`, "resumes on content drift"). - Plugin SDK: `inboundFormattingHints` is a shipped field, so this change keeps its name and signature. It is an intentional scope extension: core now calls it for every OpenClaw agent turn whose delivery target is the channel, not only inbound replies. The hook only receives `cfg` and `accountId`, with no inbound message data, so an existing hook returns the same rules it returns today. The SDK docs and type comment describe the new scope. - Control UI keeps its core-owned `markdownDetails` capability, because it has no channel plugin. - Follow-ups, not in this PR: - A `message` tool send to a different channel than the turn's own still gets only the current channel's rules. - `/btw` side answers do not get the block yet. ## Evidence - Focused tests at the real entry points, with a Telegram stub whose rich and plain accounts return different contracts: - `src/auto-reply/reply/get-reply.delivery-format.test.ts`: `getReplyFromConfig` replies on a rich account and on a plain account each get exactly one block with their own contract. A Telegram heartbeat through `runHeartbeatOnce` gets exactly one block. A Control UI reply gets none. - `src/commands/agent.delivery-format.test.ts`: `agentCommandFromIngress` with `deliver: true` (rich account) and with message-tool delivery (plain account) each append exactly one block after the caller's prompt. A turn from the rich account that delivers through the plain account gets the plain rules. An undelivered turn keeps the caller's prompt unchanged. - `src/cron/isolated-agent/run.delivery-formatting.test.ts`: cron announces load the Telegram plugin on demand, as on a cold Gateway. They get exactly one block for rich and plain accounts, and none with `mode: "none"`. - `extensions/telegram/src/channel-actions.contract.test.ts`: in the real Telegram plugin, a rich account and a plain account on the same bot get different contracts, and neither advertises `markdownDetails`. - The tests fail with the old production code restored: both delivered agent-command cases get no block, and the Telegram test finds `markdownDetails`. With the source account used instead of the outbound account, the cross-account case fails. - Test cost with `pnpm test <file> --maxWorkers=1`: about 7.5 s of test time for the agent-command file, 9 s for the reply and heartbeat file, and 4.3 s for the cron file. Most of the wall time is cold transform. - Neighboring suites pass: inbound metadata, prompt session context, reply media-only, agent command, session preparation and the system prompt. Changed-file typecheck, format and line-cap checks pass. - Live Telegram Test Server run with a real user recorder and a recording mock provider, on `main` and on this branch (reply and cron code as in the current head): | Run | Model request system prompt | Telegram result | | --- | --- | --- | | `main`, reply, rich on | rules inside inbound metadata `response_format`, plus a separate `## Collapsible Details` section (the `<details>` rule twice) | rich message | | `main`, cron announce, rich on | rules in `### Delivery Context` (`openclaw.delivery_meta.v1`) | rich message | | this branch, reply, rich on | one `### Delivery Format` block (`openclaw.delivery_format.v1`, `markdown_telegram_rich`), `<details>` rule once, no `Collapsible Details` section, no `response_format` in inbound metadata | rich message | | this branch, cron announce, rich on | the same `### Delivery Format` block, byte for byte; no `Delivery Context` block | rich message | | this branch, reply, rich off | one `### Delivery Format` block with the "Telegram rich OFF" rules | plain text message | The mock reply is fixed, so the Telegram message does not change between `main` and this branch. No screenshots are attached for that reason. - Not live-tested: subagent announces, heartbeats, and the Codex and CLI runtimes. They read the same extra-system-prompt input that the focused tests cover. Co-authored-by: Ayaan Zaidi <hi@obviy.us> |
||
|---|---|---|
| .agents | ||
| .claude | ||
| .github | ||
| .openclaw/worktree-profiles | ||
| .vscode | ||
| apps | ||
| CHANGELOG | ||
| config | ||
| crates | ||
| custodian-skills | ||
| deploy | ||
| docs | ||
| examples/ai-chat | ||
| extensions | ||
| git-hooks | ||
| packages | ||
| patches | ||
| qa | ||
| scripts | ||
| security | ||
| skills | ||
| src | ||
| test | ||
| ui | ||
| .crabbox.yaml | ||
| .dockerignore | ||
| .env.example | ||
| .gitattributes | ||
| .gitignore | ||
| .npmrc | ||
| .oxfmtrc.jsonc | ||
| .oxlintrc.json | ||
| .pre-commit-config.yaml | ||
| .semgrepignore | ||
| AGENTS.md | ||
| appcast-arm64.xml | ||
| appcast-x86_64.xml | ||
| appcast.xml | ||
| CHANGELOG.md | ||
| cli-root-options.d.mts | ||
| cli-root-options.mjs | ||
| CONTRIBUTING.md | ||
| docker-compose.yml | ||
| Dockerfile | ||
| fly.toml | ||
| gateway-run-argv.d.mts | ||
| gateway-run-argv.mjs | ||
| gateway-shutdown-budget.d.mts | ||
| gateway-shutdown-budget.mjs | ||
| LICENSE | ||
| node-compile-cache.d.mts | ||
| node-compile-cache.mjs | ||
| node-host-launcher.mjs | ||
| node-runtime-recovery.d.mts | ||
| node-runtime-recovery.mjs | ||
| node-runtime-update.d.mts | ||
| node-runtime-update.mjs | ||
| node-sqlite.d.mts | ||
| node-sqlite.mjs | ||
| node-version.d.mts | ||
| node-version.mjs | ||
| openclaw.mjs | ||
| package.json | ||
| pnpm-lock.yaml | ||
| pnpm-workspace.yaml | ||
| README.md | ||
| render.yaml | ||
| SECURITY.md | ||
| taxonomy.yaml | ||
| THIRD_PARTY_NOTICES.md | ||
| tsconfig.core.json | ||
| tsconfig.extensions.json | ||
| tsconfig.extensions.projects.json | ||
| tsconfig.json | ||
| tsconfig.scripts.json | ||
| tsconfig.ui.json | ||
| tsdown.ai.config.ts | ||
| tsdown.config.ts | ||
| VISION.md | ||
| vitest.config.ts | ||
OpenClaw 🦞 — Your assistant, on your devices, in your chats
OpenClaw is an open-source AI assistant that runs on your own computer and meets you in the channels you already use: Discord, iMessage, Slack, Teams, Telegram, WhatsApp, and 20+ more, plus native apps for macOS, iOS, Android, Windows, and Linux. One Gateway runs it as a personal assistant on a laptop or as a shared team deployment; configuration is the only difference.
Yours, with no catch. State, memory, and credentials live on your hardware. Models and agent harnesses (Claude, Codex, local models) are plugins you can swap without changing anything else. Your prompts go to the model provider and chat platforms you configure, plus any diagnostics export you enable yourself; by default OpenClaw itself phones home for nothing but a daily version check, anonymous feature statistics are opt-in, and update.checkOnStart: false disables both (what OpenClaw sends). OpenClaw is stewarded by the OpenClaw Foundation, an independent 501(c)(3), and has no paid tier, hosted service, or token. The architecture case — trusted gateway, untrusted execution, deterministic policy — is in Why OpenClaw.
Website · Docs · Getting started · Why OpenClaw · Showcase · FAQ · Vision · DeepWiki
Install
The installer supports macOS, Linux, and Windows. It provisions a supported Node.js runtime when needed.
# macOS / Linux / WSL2
curl -fsSL https://openclaw.ai/install.sh | bash
# Windows PowerShell
iwr -useb https://openclaw.ai/install.ps1 | iex
Already manage Node.js? Install the published package instead (Node 24.16+ or 26.1+; Node 26 recommended):
npm install -g openclaw@latest --allow-scripts=openclaw
That command is for npm 12 or npm 11.16+. On npm 11.15 and earlier, omit
--allow-scripts=openclaw. See the
installation guide for the lifecycle script
contract, Docker, Nix, and other deployment paths.
Quick start
On a fresh install, the installer scripts start onboarding automatically. Complete the wizard they open. If you installed the package directly with npm, pnpm, or Bun, run:
openclaw onboard --install-daemon
After onboarding:
openclaw gateway status
openclaw dashboard
Onboarding verifies model access, creates the workspace, and configures the Gateway. The last command opens the Control UI; send a message there to confirm the assistant is working. See the getting started guide for channel setup and troubleshooting.
How it fits together
- The Gateway is the local control plane for sessions, tools, events, and channel connections.
- The Control UI, CLI, and TUI connect to the Gateway.
- Channels bring the assistant to WhatsApp, Telegram, Slack, Discord, Google Chat, Signal, iMessage, and other messaging services.
- Companion apps and nodes add voice, Canvas, camera, screen, and device-local actions on supported platforms.
OpenClaw works with hosted and local model providers. Its tools, skills, and plugins extend what an assistant can do.
Security
Treat inbound messages as untrusted input. DM-capable channels pair unknown senders by default; approve a pairing request with openclaw pairing approve <channel> <code>.
Tools run on the host for the main session unless you configure sandboxing. Read the security guide, exposure runbook, and sandboxing guide before connecting other users or exposing the Gateway remotely.
Documentation
| Goal | Start here |
|---|---|
| Configure models and auth | Models · Model providers |
| Connect a messaging service | Channels |
| Add tools, skills, and plugins | Tools · Skills · Plugins · ClawHub |
| Run apps and device nodes | Platforms · Nodes |
| Use the CLI and chat commands | CLI reference · Slash commands |
| Configure or operate the Gateway | Configuration · Architecture · Updating · Release channels |
Development
The repository is a pnpm workspace. Plain npm install at the repository root is not supported.
git clone https://github.com/openclaw/openclaw.git
cd openclaw
pnpm install
pnpm build
pnpm ui:build
See CONTRIBUTING.md for the contribution workflow and the source setup guide for the development loop.
Governance
OpenClaw is developed in the open by the OpenClaw Foundation, an independent 501(c)(3). The Foundation employs the core team and signs releases. Donors and infrastructure sponsors support the Foundation; none of them own or direct the project. OpenAI is a donor, not an owner.
Community
See CONTRIBUTING.md for maintainers and contribution guidelines; AI-assisted PRs are welcome.
Use the issue chooser for bugs and feature requests, ask setup questions in Discord, and report vulnerabilities through SECURITY.md. New capabilities usually belong in plugins built on the plugin SDK and shared through ClawHub.
OpenClaw was built for Molty, a space lobster AI assistant, by Peter Steinberger and the community. Explore the project lore, soul.md, Peter's site, Star History, and @openclaw.
Special thanks to Mario Zechner for his support and for pi, and to Adam Doppelt for the lobster.bot domain.
Donors and sponsors
The Foundation is funded by donors including Amazon, Lobster Computer Company, Offline Holdings, OpenAI, Red Hat, and the University of Michigan, with infrastructure support from Blacksmith, Convex, GitHub, NVIDIA, and Vercel.
Contributors
Thanks to all clawtributors:
License
MIT © OpenClaw Foundation. See THIRD_PARTY_NOTICES.md for incorporated or adapted code.