docs: typography hygiene across 4 large pages

Replaced 152 typography characters (curly quotes, apostrophes, em/en
dashes, non-breaking hyphens) with ASCII equivalents so grep,
copy-paste, and Mintlify search hit clean tokens. Per docs/CLAUDE.md
heading and content hygiene rules.

- docs/gateway/security/index.md: 59 chars
- docs/plugins/hooks.md: 34 chars
- docs/reference/session-management-compaction.md: 30 chars
- docs/tools/clawhub.md: 29 chars
This commit is contained in:
Vincent Koc
2026-05-05 19:18:29 -07:00
parent 585bff4b75
commit 736f627fb5
4 changed files with 115 additions and 115 deletions

View File

@@ -45,7 +45,7 @@ POSIX `chmod` when running on Windows.
It flags common footguns (Gateway auth exposure, browser control exposure, elevated allowlists, filesystem permissions, permissive exec approvals, and open-channel tool exposure).
OpenClaw is both a product and an experiment: youre wiring frontier-model behavior into real messaging surfaces and real tools. **There is no perfectly secure setup.** The goal is to be deliberate about:
OpenClaw is both a product and an experiment: you're wiring frontier-model behavior into real messaging surfaces and real tools. **There is no "perfectly secure" setup.** The goal is to be deliberate about:
- who can talk to your bot
- where the bot is allowed to act
@@ -224,7 +224,7 @@ Advisory triage guidance:
- `security="full"` is a broad posture warning, not proof of a bug. It is the chosen default for trusted personal-assistant setups; tighten it only when your threat model needs approval or allowlist guardrails.
- **Network exposure** (Gateway bind/auth, Tailscale Serve/Funnel, weak/short auth tokens).
- **Browser control exposure** (remote nodes, relay ports, remote CDP endpoints).
- **Local disk hygiene** (permissions, symlinks, config includes, synced folder paths).
- **Local disk hygiene** (permissions, symlinks, config includes, "synced folder" paths).
- **Plugins** (plugins load without an explicit allowlist).
- **Policy drift/misconfig** (sandbox docker settings configured but sandbox mode off; ineffective `gateway.nodes.denyCommands` patterns because matching is exact command-name only (for example `system.run`) and does not inspect shell text; dangerous `gateway.nodes.allowCommands` entries; global `tools.profile="minimal"` overridden by per-agent profiles; plugin-owned tools reachable under permissive tool policy).
- **Runtime expectation drift** (for example assuming implicit exec still means `sandbox` when `tools.exec.host` now defaults to `auto`, or explicitly setting `tools.exec.host="sandbox"` while sandbox mode is off).
@@ -252,7 +252,7 @@ Use this when auditing access or deciding what to back up:
When the audit prints findings, treat this as a priority order:
1. **Anything open + tools enabled**: lock down DMs/groups first (pairing/allowlists), then tighten tool policy/sandboxing.
1. **Anything "open" + tools enabled**: lock down DMs/groups first (pairing/allowlists), then tighten tool policy/sandboxing.
2. **Public network exposure** (LAN bind, Funnel, missing auth): fix immediately.
3. **Browser control remote exposure**: treat it like operator access (tailnet-only, pair nodes deliberately, avoid public exposure).
4. **Permissions**: make sure state/config/credentials/auth are not group/world-readable.
@@ -265,11 +265,11 @@ Each audit finding is keyed by a structured `checkId` (for example
`gateway.bind_no_auth` or `tools.exec.security_full_configured`). Common
critical severity classes:
- `fs.*` filesystem permissions on state, config, credentials, auth profiles.
- `gateway.*` bind mode, auth, Tailscale, Control UI, trusted-proxy setup.
- `hooks.*`, `browser.*`, `sandbox.*`, `tools.exec.*` per-surface hardening.
- `plugins.*`, `skills.*` plugin/skill supply chain and scan findings.
- `security.exposure.*` cross-cutting checks where access policy meets tool blast radius.
- `fs.*` - filesystem permissions on state, config, credentials, auth profiles.
- `gateway.*` - bind mode, auth, Tailscale, Control UI, trusted-proxy setup.
- `hooks.*`, `browser.*`, `sandbox.*`, `tools.exec.*` - per-surface hardening.
- `plugins.*`, `skills.*` - plugin/skill supply chain and scan findings.
- `security.exposure.*` - cross-cutting checks where access policy meets tool blast radius.
See the full catalog with severity levels, fix keys, and auto-fix support at
[Security audit checks](/gateway/security/audit-checks).
@@ -430,7 +430,7 @@ If a macOS node is paired, the Gateway can invoke `system.run` on that node. Thi
`systemRunPlan`; later approved forwards reuse that stored plan, and gateway
validation rejects caller edits to command/cwd/session context after the
approval request was created.
- If you dont want remote execution, set security to **deny** and remove node pairing for that Mac.
- If you don't want remote execution, set security to **deny** and remove node pairing for that Mac.
This distinction matters for triage:
@@ -463,11 +463,11 @@ People who message you can:
## Core concept: access control before intelligence
Most failures here are not fancy exploits theyre someone messaged the bot and the bot did what they asked.
Most failures here are not fancy exploits - they're "someone messaged the bot and the bot did what they asked."
OpenClaws stance:
OpenClaw's stance:
- **Identity first:** decide who can talk to the bot (DM pairing / allowlists / explicit open).
- **Identity first:** decide who can talk to the bot (DM pairing / allowlists / explicit "open").
- **Scope next:** decide where the bot is allowed to act (group allowlists + mention gating, tools, sandboxing, device permissions).
- **Model last:** assume the model can be manipulated; design so manipulation has limited blast radius.
@@ -530,7 +530,7 @@ Details: [Plugins](/tools/plugin)
All current DM-capable channels support a DM policy (`dmPolicy` or `*.dm.policy`) that gates inbound DMs **before** the message is processed:
- `pairing` (default): unknown senders receive a short pairing code and the bot ignores their message until approved. Codes expire after 1 hour; repeated DMs wont resend a code until a new request is created. Pending requests are capped at **3 per channel** by default.
- `pairing` (default): unknown senders receive a short pairing code and the bot ignores their message until approved. Codes expire after 1 hour; repeated DMs won't resend a code until a new request is created. Pending requests are capped at **3 per channel** by default.
- `allowlist`: unknown senders are blocked (no pairing handshake).
- `open`: allow anyone to DM (public). **Requires** the channel allowlist to include `"*"` (explicit opt-in).
- `disabled`: ignore inbound DMs entirely.
@@ -571,7 +571,7 @@ If you run multiple accounts on the same channel, use `per-account-channel-peer`
## Allowlists for DMs and groups
OpenClaw has two separate who can trigger me? layers:
OpenClaw has two separate "who can trigger me?" layers:
- **DM allowlist** (`allowFrom` / `channels.discord.allowFrom` / `channels.slack.allowFrom`; legacy: `channels.discord.dm.allowFrom`, `channels.slack.dm.allowFrom`): who is allowed to talk to the bot in direct messages.
- When `dmPolicy="pairing"`, approvals are written to the account-scoped pairing allowlist store under `~/.openclaw/credentials/` (`<channel>-allowFrom.json` for default account, `<channel>-<accountId>-allowFrom.json` for non-default accounts), merged with config allowlists.
@@ -588,14 +588,14 @@ Details: [Configuration](/gateway/configuration) and [Groups](/channels/groups)
## Prompt injection (what it is, why it matters)
Prompt injection is when an attacker crafts a message that manipulates the model into doing something unsafe (ignore your instructions, dump your filesystem, follow this link and run commands, etc.).
Prompt injection is when an attacker crafts a message that manipulates the model into doing something unsafe ("ignore your instructions", "dump your filesystem", "follow this link and run commands", etc.).
Even with strong system prompts, **prompt injection is not solved**. System prompt guardrails are soft guidance only; hard enforcement comes from tool policy, exec approvals, sandboxing, and channel allowlists (and operators can disable these by design). What helps in practice:
- Keep inbound DMs locked down (pairing/allowlists).
- Prefer mention gating in groups; avoid always-on bots in public rooms.
- Prefer mention gating in groups; avoid "always-on" bots in public rooms.
- Treat links, attachments, and pasted instructions as hostile by default.
- Run sensitive tool execution in a sandbox; keep secrets out of the agents reachable filesystem.
- Run sensitive tool execution in a sandbox; keep secrets out of the agent's reachable filesystem.
- Note: sandboxing is opt-in. If sandbox mode is off, implicit `host=auto` resolves to the gateway host. Explicit `host=sandbox` still fails closed because no sandbox runtime is available. Set `host=gateway` if you want that behavior to be explicit in config.
- Limit high-risk tools (`exec`, `browser`, `web_fetch`, `web_search`) to trusted agents or explicit allowlists.
- If you allowlist interpreters (`python`, `node`, `ruby`, `perl`, `php`, `lua`, `osascript`), enable `tools.exec.strictInlineEval` so inline eval forms still need explicit approval.
@@ -604,10 +604,10 @@ Even with strong system prompts, **prompt injection is not solved**. System prom
Red flags to treat as untrusted:
- Read this file/URL and do exactly what it says.
- Ignore your system prompt or safety rules.
- Reveal your hidden instructions or tool outputs.
- Paste the full contents of ~/.openclaw or your logs.
- "Read this file/URL and do exactly what it says."
- "Ignore your system prompt or safety rules."
- "Reveal your hidden instructions or tool outputs."
- "Paste the full contents of ~/.openclaw or your logs."
## External content special-token sanitization
@@ -619,7 +619,7 @@ Why:
- Sanitization happens at the external-content wrapping layer, so it applies uniformly across fetch/read tools and inbound channel content rather than being per-provider.
- Outbound model responses already have a separate sanitizer that strips leaked `<tool_call>`, `<function_calls>`, `<system-reminder>`, `<previous_response>`, and similar internal runtime scaffolding from user-visible replies at the final channel delivery boundary. The external-content sanitizer is the inbound counterpart.
This does not replace the other hardening on this page `dmPolicy`, allowlists, exec approvals, sandboxing, and `contextVisibility` still do the primary work. It closes one specific tokenizer-layer bypass against self-hosted stacks that forward user text with special tokens intact.
This does not replace the other hardening on this page - `dmPolicy`, allowlists, exec approvals, sandboxing, and `contextVisibility` still do the primary work. It closes one specific tokenizer-layer bypass against self-hosted stacks that forward user text with special tokens intact.
## Unsafe external content bypass flags
@@ -851,7 +851,7 @@ When Bonjour is enabled in minimal mode, the Gateway broadcasts enough for devic
### Lock down the Gateway WebSocket (local auth)
Gateway auth is **required by default**. If no valid gateway auth path is configured,
the Gateway refuses WebSocket connections (failclosed).
the Gateway refuses WebSocket connections (fail-closed).
Onboarding generates a token by default (even for loopback) so
local clients must authenticate.
@@ -962,7 +962,7 @@ Treat node pairing like admin access.
Recommended pattern:
- Keep the Gateway and node host on the same tailnet (Tailscale).
- Pair the node intentionally; disable browser proxy routing if you dont need it.
- Pair the node intentionally; disable browser proxy routing if you don't need it.
Avoid:
@@ -996,7 +996,7 @@ OpenClaw loads workspace-local `.env` files for agents and tools, but never lets
- Any key that starts with `OPENCLAW_*` is blocked from untrusted workspace `.env` files.
- Channel endpoint settings for Matrix, Mattermost, IRC, and Synology Chat are also blocked from workspace `.env` overrides, so cloned workspaces cannot redirect bundled connector traffic through local endpoint config. Endpoint env keys (such as `MATRIX_HOMESERVER`, `MATTERMOST_URL`, `IRC_HOST`, `SYNOLOGY_CHAT_INCOMING_URL`) must come from the gateway process environment or `env.shellEnv`, not from a workspace-loaded `.env`.
- The block is fail-closed: a new runtime-control variable added in a future release cannot be inherited from a checked-in or attacker-supplied `.env`; the key is ignored and the gateway keeps its own value.
- Trusted process/OS environment variables (the gateway's own shell, launchd/systemd unit, app bundle) still apply this only constrains `.env` file loading.
- Trusted process/OS environment variables (the gateway's own shell, launchd/systemd unit, app bundle) still apply - this only constrains `.env` file loading.
Why: workspace `.env` files frequently live next to agent code, get committed by accident, or get written by tools. Blocking the whole `OPENCLAW_*` prefix means adding a new `OPENCLAW_*` flag later can never regress into silent inheritance from workspace state.
@@ -1012,7 +1012,7 @@ Recommendations:
- Keep log and transcript redaction on (`logging.redactSensitive: "tools"`; default).
- Add custom patterns for your environment via `logging.redactPatterns` (tokens, hostnames, internal URLs).
- When sharing diagnostics, prefer `openclaw status --all` (pasteable, secrets redacted) over raw logs.
- Prune old session transcripts and log files if you dont need long retention.
- Prune old session transcripts and log files if you don't need long retention.
Details: [Logging](/gateway/logging)
@@ -1070,7 +1070,7 @@ Additional hardening options:
### Secure baseline (copy/paste)
One safe default config that keeps the Gateway private, requires DM pairing, and avoids always-on group bots:
One "safe default" config that keeps the Gateway private, requires DM pairing, and avoids always-on group bots:
```json5
{
@@ -1089,7 +1089,7 @@ One “safe default” config that keeps the Gateway private, requires DM pairin
}
```
If you want safer by default tool execution too, add a sandbox + deny dangerous tools for any non-owner agent (example below under Per-agent access profiles).
If you want "safer by default" tool execution too, add a sandbox + deny dangerous tools for any non-owner agent (example below under "Per-agent access profiles").
Built-in baseline for chat-driven agent turns: non-owner senders cannot use the `cron` or `gateway` tools.
@@ -1140,14 +1140,14 @@ access those accounts and data. Treat browser profiles as **sensitive state**:
trusted-proxy or Tailscale Serve identity headers.
- Treat browser downloads as untrusted input; prefer an isolated downloads directory.
- Disable browser sync/password managers in the agent profile if possible (reduces blast radius).
- For remote gateways, assume browser control is equivalent to operator access to whatever that profile can reach.
- For remote gateways, assume "browser control" is equivalent to "operator access" to whatever that profile can reach.
- Keep the Gateway and node hosts tailnet-only; avoid exposing browser control ports to LAN or public Internet.
- Disable browser proxy routing when you dont need it (`gateway.nodes.browser.mode="off"`).
- Chrome MCP existing-session mode is **not** safer; it can act as you in whatever that host Chrome profile can reach.
- Disable browser proxy routing when you don't need it (`gateway.nodes.browser.mode="off"`).
- Chrome MCP existing-session mode is **not** "safer"; it can act as you in whatever that host Chrome profile can reach.
### Browser SSRF policy (strict by default)
OpenClaws browser navigation policy is strict by default: private/internal destinations stay blocked unless you explicitly opt in.
OpenClaw's browser navigation policy is strict by default: private/internal destinations stay blocked unless you explicitly opt in.
- Default: `browser.ssrfPolicy.dangerouslyAllowPrivateNetwork` is unset, so browser navigation keeps private/internal/special-use destinations blocked.
- Legacy alias: `browser.ssrfPolicy.allowPrivateNetwork` is still accepted for compatibility.

View File

@@ -54,8 +54,8 @@ keep registration order.
`api.on(name, handler, opts?)` accepts:
- `priority` handler ordering (higher runs first).
- `timeoutMs` optional per-hook budget. When set, the hook runner aborts that
- `priority` - handler ordering (higher runs first).
- `timeoutMs` - optional per-hook budget. When set, the hook runner aborts that
handler after the budget elapses and continues with the next one, instead of
letting slow setup or recall work consume the caller's configured model
timeout. Omit it to use the default observation/decision timeout that the
@@ -100,52 +100,52 @@ observation-only.
**Agent turn**
- `before_model_resolve` override provider or model before session messages load
- `agent_turn_prepare` consume queued plugin turn injections and add same-turn context before prompt hooks
- `before_prompt_build` add dynamic context or system-prompt text before the model call
- `before_agent_start` compatibility-only combined phase; prefer the two hooks above
- **`before_agent_reply`** short-circuit the model turn with a synthetic reply or silence
- **`before_agent_finalize`** inspect the natural final answer and request one more model pass
- `agent_end` observe final messages, success state, and run duration
- `heartbeat_prompt_contribution` add heartbeat-only context for background monitor and lifecycle plugins
- `before_model_resolve` - override provider or model before session messages load
- `agent_turn_prepare` - consume queued plugin turn injections and add same-turn context before prompt hooks
- `before_prompt_build` - add dynamic context or system-prompt text before the model call
- `before_agent_start` - compatibility-only combined phase; prefer the two hooks above
- **`before_agent_reply`** - short-circuit the model turn with a synthetic reply or silence
- **`before_agent_finalize`** - inspect the natural final answer and request one more model pass
- `agent_end` - observe final messages, success state, and run duration
- `heartbeat_prompt_contribution` - add heartbeat-only context for background monitor and lifecycle plugins
**Conversation observation**
- `model_call_started` / `model_call_ended` observe sanitized provider/model call metadata, timing, outcome, and bounded request-id hashes without prompt or response content
- `llm_input` observe provider input (system prompt, prompt, history)
- `llm_output` observe provider output
- `model_call_started` / `model_call_ended` - observe sanitized provider/model call metadata, timing, outcome, and bounded request-id hashes without prompt or response content
- `llm_input` - observe provider input (system prompt, prompt, history)
- `llm_output` - observe provider output
**Tools**
- **`before_tool_call`** rewrite tool params, block execution, or require approval
- `after_tool_call` observe tool results, errors, and duration
- **`tool_result_persist`** rewrite the assistant message produced from a tool result
- **`before_message_write`** inspect or block an in-progress message write (rare)
- **`before_tool_call`** - rewrite tool params, block execution, or require approval
- `after_tool_call` - observe tool results, errors, and duration
- **`tool_result_persist`** - rewrite the assistant message produced from a tool result
- **`before_message_write`** - inspect or block an in-progress message write (rare)
**Messages and delivery**
- **`inbound_claim`** claim an inbound message before agent routing (synthetic replies)
- `message_received` observe inbound content, sender, thread, and metadata
- **`message_sending`** rewrite outbound content or cancel delivery
- `message_sent` observe outbound delivery success or failure
- **`before_dispatch`** inspect or rewrite an outbound dispatch before channel handoff
- **`reply_dispatch`** participate in the final reply-dispatch pipeline
- **`inbound_claim`** - claim an inbound message before agent routing (synthetic replies)
- `message_received` - observe inbound content, sender, thread, and metadata
- **`message_sending`** - rewrite outbound content or cancel delivery
- `message_sent` - observe outbound delivery success or failure
- **`before_dispatch`** - inspect or rewrite an outbound dispatch before channel handoff
- **`reply_dispatch`** - participate in the final reply-dispatch pipeline
**Sessions and compaction**
- `session_start` / `session_end` track session lifecycle boundaries
- `before_compaction` / `after_compaction` observe or annotate compaction cycles
- `before_reset` observe session-reset events (`/reset`, programmatic resets)
- `session_start` / `session_end` - track session lifecycle boundaries
- `before_compaction` / `after_compaction` - observe or annotate compaction cycles
- `before_reset` - observe session-reset events (`/reset`, programmatic resets)
**Subagents**
- `subagent_spawning` / `subagent_delivery_target` / `subagent_spawned` / `subagent_ended` coordinate subagent routing and completion delivery
- `subagent_spawning` / `subagent_delivery_target` / `subagent_spawned` / `subagent_ended` - coordinate subagent routing and completion delivery
**Lifecycle**
- `gateway_start` / `gateway_stop` start or stop plugin-owned services with the Gateway
- `cron_changed` observe gateway-owned cron lifecycle changes (added, updated, removed, started, finished, scheduled)
- **`before_install`** inspect skill or plugin install scans and optionally block
- `gateway_start` / `gateway_stop` - start or stop plugin-owned services with the Gateway
- `cron_changed` - observe gateway-owned cron lifecycle changes (added, updated, removed, started, finished, scheduled)
- **`before_install`** - inspect skill or plugin install scans and optionally block
## Tool call policy
@@ -188,7 +188,7 @@ Rules:
approvals. The `/approve` command can approve both exec and plugin approvals.
- A lower-priority `block: true` can still block after a higher-priority hook
requested approval.
- `onResolution` receives the resolved approval decision `allow-once`,
- `onResolution` receives the resolved approval decision - `allow-once`,
`allow-always`, `deny`, `timeout`, or `cancelled`.
Bundled plugins that need host-level policy can register trusted tool policies
@@ -397,14 +397,14 @@ before the next major release:
`PluginApprovalResolution` union (`allow-once` / `allow-always` / `deny` /
`timeout` / `cancelled`) instead of a free-form `string`.
For the full list memory capability registration, provider thinking
For the full list - memory capability registration, provider thinking
profile, external auth providers, provider discovery types, task runtime
accessors, and the `command-auth``command-status` rename see
accessors, and the `command-auth``command-status` rename - see
[Plugin SDK migration → Active deprecations](/plugins/sdk-migration#active-deprecations).
## Related
- [Plugin SDK migration](/plugins/sdk-migration) active deprecations and removal timeline
- [Plugin SDK migration](/plugins/sdk-migration) - active deprecations and removal timeline
- [Building plugins](/plugins/building-plugins)
- [Plugin SDK overview](/plugins/sdk-overview)
- [Plugin entry points](/plugins/sdk-entrypoints)

View File

@@ -2,7 +2,7 @@
summary: "Deep dive: session store + transcripts, lifecycle, and (auto)compaction internals"
read_when:
- You need to debug session ids, transcript JSONL, or sessions.json fields
- You are changing auto-compaction behavior or adding pre-compaction housekeeping
- You are changing auto-compaction behavior or adding "pre-compaction" housekeeping
- You want to implement memory flushes or silent system turns
title: "Session management deep dive"
---
@@ -33,7 +33,7 @@ If you want a higher-level overview first, start with:
OpenClaw is designed around a single **Gateway process** that owns session state.
- UIs (macOS app, web Control UI, TUI) should query the Gateway for session lists and token counts.
- In remote mode, session files are on the remote host; checking your local Mac files wont reflect what the Gateway is using.
- In remote mode, session files are on the remote host; "checking your local Mac files" won't reflect what the Gateway is using.
---
@@ -135,7 +135,7 @@ runtime authority from an older run.
## Session keys (`sessionKey`)
A `sessionKey` identifies _which conversation bucket_ youre in (routing + isolation).
A `sessionKey` identifies _which conversation bucket_ you're in (routing + isolation).
Common patterns:
@@ -167,7 +167,7 @@ Implementation detail: the decision happens in `initSessionState()` in `src/auto
## Session store schema (`sessions.json`)
The stores value type is `SessionEntry` in `src/config/sessions.ts`.
The store's value type is `SessionEntry` in `src/config/sessions.ts`.
Key fields (not exhaustive):
@@ -200,7 +200,7 @@ The store is safe to edit, but the Gateway is the authority: it may rewrite or r
## Transcript structure (`*.jsonl`)
Transcripts are managed by `@mariozechner/pi-coding-agent`s `SessionManager`.
Transcripts are managed by `@mariozechner/pi-coding-agent`'s `SessionManager`.
The file is JSONL:
@@ -215,7 +215,7 @@ Notable entry types:
- `compaction`: persisted compaction summary with `firstKeptEntryId` and `tokensBefore`
- `branch_summary`: persisted summary when navigating a tree branch
OpenClaw intentionally does **not** fix up transcripts; the Gateway uses `SessionManager` to read/write them.
OpenClaw intentionally does **not** "fix up" transcripts; the Gateway uses `SessionManager` to read/write them.
---
@@ -226,10 +226,10 @@ Two different concepts matter:
1. **Model context window**: hard cap per model (tokens visible to the model)
2. **Session store counters**: rolling stats written into `sessions.json` (used for /status and dashboards)
If youre tuning limits:
If you're tuning limits:
- The context window comes from the model catalog (and can be overridden via config).
- `contextTokens` in the store is a runtime estimate/reporting value; dont treat it as a strict guarantee.
- `contextTokens` in the store is a runtime estimate/reporting value; don't treat it as a strict guarantee.
For more, see [/token-use](/reference/token-use).
@@ -276,7 +276,7 @@ exceeded`, and similar provider-shaped variants) → compact → retry.
Where:
- `contextWindow` is the models context window
- `contextWindow` is the model's context window
- `reserveTokens` is headroom reserved for prompts + the next model output
These are Pi runtime semantics (OpenClaw consumes the events, but Pi decides when to compact).
@@ -306,7 +306,7 @@ loop after new tool results have been appended.
## Compaction settings (`reserveTokens`, `keepRecentTokens`)
Pis compaction settings live in Pi settings:
Pi's compaction settings live in Pi settings:
```json5
{
@@ -323,7 +323,7 @@ OpenClaw also enforces a safety floor for embedded runs:
- If `compaction.reserveTokens < reserveTokensFloor`, OpenClaw bumps it.
- Default floor is `20000` tokens.
- Set `agents.defaults.compaction.reserveTokensFloor: 0` to disable the floor.
- If its already higher, OpenClaw leaves it alone.
- If it's already higher, OpenClaw leaves it alone.
- Manual `/compact` honors an explicit `agents.defaults.compaction.keepRecentTokens`
and keeps Pi's recent-tail cut point. Without an explicit keep budget,
manual compaction remains a hard checkpoint and rebuilt context starts from
@@ -343,7 +343,7 @@ OpenClaw also enforces a safety floor for embedded runs:
compaction. The old full transcript remains archived and linked from the
compaction checkpoint instead of being rewritten in place.
Why: leave enough headroom for multi-turn housekeeping (like memory writes) before compaction becomes unavoidable.
Why: leave enough headroom for multi-turn "housekeeping" (like memory writes) before compaction becomes unavoidable.
Implementation: `ensurePiCompactionReserveTokens()` in `src/agents/pi-settings.ts`
(called from `src/agents/pi-embedded-runner.ts`).
@@ -382,12 +382,12 @@ You can observe compaction and session state via:
## Silent housekeeping (`NO_REPLY`)
OpenClaw supports silent turns for background tasks where the user should not see intermediate output.
OpenClaw supports "silent" turns for background tasks where the user should not see intermediate output.
Convention:
- The assistant starts its output with the exact silent token `NO_REPLY` /
`no_reply` to indicate do not deliver a reply to the user.
`no_reply` to indicate "do not deliver a reply to the user".
- OpenClaw strips/suppresses this in the delivery layer.
- Exact silent-token suppression is case-insensitive, so `NO_REPLY` and
`no_reply` both count when the whole payload is just the silent token.
@@ -395,7 +395,7 @@ Convention:
ordinary actionable user requests.
As of `2026.1.10`, OpenClaw also suppresses **draft/typing streaming** when a
partial chunk begins with `NO_REPLY`, so silent operations dont leak partial
partial chunk begins with `NO_REPLY`, so silent operations don't leak partial
output mid-turn.
---
@@ -403,14 +403,14 @@ output mid-turn.
## Pre-compaction "memory flush" (implemented)
Goal: before auto-compaction happens, run a silent agentic turn that writes durable
state to disk (e.g. `memory/YYYY-MM-DD.md` in the agent workspace) so compaction cant
state to disk (e.g. `memory/YYYY-MM-DD.md` in the agent workspace) so compaction can't
erase critical context.
OpenClaw uses the **pre-threshold flush** approach:
1. Monitor session context usage.
2. When it crosses a soft threshold (below Pis compaction threshold), run a silent
write memory now directive to the agent.
2. When it crosses a "soft threshold" (below Pi's compaction threshold), run a silent
"write memory now" directive to the agent.
3. Use the exact silent token `NO_REPLY` / `no_reply` so the user sees
nothing.
@@ -434,7 +434,7 @@ Notes:
- The flush is skipped when the session workspace is read-only (`workspaceAccess: "ro"` or `"none"`).
- See [Memory](/concepts/memory) for the workspace file layout and write patterns.
Pi also exposes a `session_before_compact` hook in the extension API, but OpenClaws
Pi also exposes a `session_before_compact` hook in the extension API, but OpenClaw's
flush logic lives on the Gateway side today.
---
@@ -447,7 +447,7 @@ flush logic lives on the Gateway side today.
- model context window (too small)
- compaction settings (`reserveTokens` too high for the model window can cause earlier compaction)
- tool-result bloat: enable/tune session pruning
- Silent turns leaking? Confirm the reply starts with `NO_REPLY` (case-insensitive exact token) and youre on a build that includes the streaming suppression fix.
- Silent turns leaking? Confirm the reply starts with `NO_REPLY` (case-insensitive exact token) and you're on a build that includes the streaming suppression fix.
## Related

View File

@@ -29,7 +29,7 @@ Site: [clawhub.ai](https://clawhub.ai)
```
</Step>
<Step title="Use">
Start a new OpenClaw session it picks up the new skill.
Start a new OpenClaw session - it picks up the new skill.
</Step>
<Step title="Publish (optional)">
For registry-authenticated workflows (publish, sync, manage), install
@@ -152,7 +152,7 @@ shared, and gated, see [Skills](/tools/skills).
## Security and moderation
ClawHub is open by default anyone can upload skills, but a GitHub
ClawHub is open by default - anyone can upload skills, but a GitHub
account must be **at least one week old** to publish. This slows down
abuse without blocking legitimate contributors.
@@ -221,9 +221,9 @@ publish/sync.
Login options:
- `--token <token>` paste an API token.
- `--label <label>` label stored for browser login tokens (default: `CLI token`).
- `--no-browser` do not open a browser (requires `--token`).
- `--token <token>` - paste an API token.
- `--label <label>` - label stored for browser login tokens (default: `CLI token`).
- `--no-browser` - do not open a browser (requires `--token`).
</Accordion>
<Accordion title="Search">
@@ -233,7 +233,7 @@ publish/sync.
Searches skills. For plugin/package discovery, use `clawhub package explore`.
- `--limit <n>` max results.
- `--limit <n>` - max results.
</Accordion>
<Accordion title="Browse / inspect plugins">
@@ -247,12 +247,12 @@ publish/sync.
Options:
- `--family skill|code-plugin|bundle-plugin` filter package family.
- `--official` show only official packages.
- `--executes-code` show only packages that execute code.
- `--version <version>` / `--tag <tag>` inspect a specific package version.
- `--versions`, `--files`, `--file <path>` inspect package history and files.
- `--json` machine-readable output.
- `--family skill|code-plugin|bundle-plugin` - filter package family.
- `--official` - show only official packages.
- `--executes-code` - show only packages that execute code.
- `--version <version>` / `--tag <tag>` - inspect a specific package version.
- `--versions`, `--files`, `--file <path>` - inspect package history and files.
- `--json` - machine-readable output.
</Accordion>
<Accordion title="Install / update / list">
@@ -265,8 +265,8 @@ publish/sync.
Options:
- `--version <version>` install or update to a specific version (single slug only on `update`).
- `--force` overwrite if the folder already exists, or when local files do not match any published version.
- `--version <version>` - install or update to a specific version (single slug only on `update`).
- `--force` - overwrite if the folder already exists, or when local files do not match any published version.
- `clawhub list` reads `.clawhub/lock.json`.
</Accordion>
@@ -277,11 +277,11 @@ publish/sync.
Options:
- `--slug <slug>` skill slug.
- `--name <name>` display name.
- `--version <version>` semver version.
- `--changelog <text>` changelog text (can be empty).
- `--tags <tags>` comma-separated tags (default: `latest`).
- `--slug <slug>` - skill slug.
- `--name <name>` - display name.
- `--version <version>` - semver version.
- `--changelog <text>` - changelog text (can be empty).
- `--tags <tags>` - comma-separated tags (default: `latest`).
</Accordion>
<Accordion title="Publish plugins">
@@ -294,9 +294,9 @@ publish/sync.
Options:
- `--dry-run` build the exact publish plan without uploading anything.
- `--json` emit machine-readable output for CI.
- `--source-repo`, `--source-commit`, `--source-ref` optional overrides when auto-detection is not enough.
- `--dry-run` - build the exact publish plan without uploading anything.
- `--json` - emit machine-readable output for CI.
- `--source-repo`, `--source-commit`, `--source-ref` - optional overrides when auto-detection is not enough.
</Accordion>
<Accordion title="Request rescans">
@@ -329,13 +329,13 @@ publish/sync.
Options:
- `--root <dir...>` extra scan roots.
- `--all` upload everything without prompts.
- `--dry-run` show what would be uploaded.
- `--bump <type>` `patch|minor|major` for updates (default: `patch`).
- `--changelog <text>` changelog for non-interactive updates.
- `--tags <tags>` comma-separated tags (default: `latest`).
- `--concurrency <n>` registry checks (default: `4`).
- `--root <dir...>` - extra scan roots.
- `--all` - upload everything without prompts.
- `--dry-run` - show what would be uploaded.
- `--bump <type>` - `patch|minor|major` for updates (default: `patch`).
- `--changelog <text>` - changelog for non-interactive updates.
- `--tags <tags>` - comma-separated tags (default: `latest`).
- `--concurrency <n>` - registry checks (default: `4`).
</Accordion>
</AccordionGroup>