The update_plan checklist tool has been default-on with no model gating for a
while, so keeping it under tools.experimental misrepresented it and kept a
container key alive for a single boolean. Rename it to a plain boolean
tools.updatePlan (camel-cased tool id, matching tools.agentToAgent and
tools.toolSearch), keeping the !== false default-on semantics.
The strict schema rejects the retired key, so openclaw doctor --fix now lifts
tools.experimental.planTool to tools.updatePlan and deletes the emptied
container. Registration also drops five parameters that were never read
(agentSessionKey, agentId, modelProvider, modelId, pluginToolAllowlist).
Docs: config-tools.md dropped a stale claim that the tool defaults off behind a
strict-agentic GPT-5 rule that no longer exists, experimental-features.md no
longer lists the tool and now cites the real Codex app-server floor (0.143.0,
per MIN_CODEX_APP_SERVER_VERSION).
Config baseline core count drops 2307 -> 2306.
Sensitive log redaction became unconditional and `logging.redactSensitive`
was retired from the config schema, but the policy doctor still classified
`dataHandling.sensitiveLogging.requireRedaction` as an automatic repair that
would have written the retired key back into config.
Remove the automatic repair (check-id registration, patch branch, and the
`enableSensitiveLoggingRedaction` writer), drop the `logging.redactSensitive`
config target, and reclassify the check as `validateOnly`. The check keeps
evaluating the policy declaration against the redaction invariant; it just no
longer claims a fixable config target. Refresh the policy docs, the finding
fix hint, and a stale comment in `src/logging/redact.ts`.
* docs: correct retired cron/audit config keys, cron failure-alert default, memory recall default, and tool-search telemetry claims
- configuration-reference: cron block documented cron.webhook and cron.failureDestination, both retired by the config-surface reduction tranches (58452de711, edecdbd05e); the cron schema is strict so a copied snippet is rejected. Document only the live keys and note the doctor --fix migrations.
- configuration-reference: root-level audit block is retired; canonical path is logging.audit (src/config/zod-schema.root-shape.ts).
- configuration-reference: cron.failureAlert.after default is 2, not 3 (src/cron/service/failure-alerts.ts).
- memory-config: rememberAcrossConversations defaults on for personal installs (packages/memory-host-sdk/src/host/config-utils.ts), matching the canonical table earlier in the page.
- tool-search: telemetry records catalogSize, per-source counts, and search/describe/call counts, and only on tool_search_code results. No byte accounting exists in the runtime.
* docs: retire remaining references to removed cron, audit, and logging config keys
Sweep follow-up to the previous commit, covering the same bug class in the pages that still contradicted it.
- cron-jobs/cli-cron: global cron.failureDestination is retired; the destination fields now live on cron.failureAlert (src/config/zod-schema.root-shape.ts, merged by legacy-config-migrations.runtime.retired.ts:379). Per-job delivery.failureDestination bullets left intact.
- gateway/audit, cli/audit, gateway/protocol: root-level audit.* is retired; canonical path is logging.audit.*.
- logging: logging.redactSensitive is retired (dead-config-keys.test.ts:198; removed by legacy-config-migrations.runtime.tier-eval.ts:12). resolveConfigRedaction hardcodes DEFAULT_REDACT_MODE = tools, so redaction is unconditional. Also documented that redactPatterns replaces the defaults on the log path (redact.ts:419) while tool payloads always merge them.
- logging: consoleStyle accepts only pretty|json (zod-schema.root-shape.ts:106); compact remains the automatic non-TTY rendering style (logging/console.ts:40) but is no longer settable, and doctor maps a stored one to pretty.
- security: security --fix no longer touches redaction and the logging.redact_off audit check is retired (src/security/audit-loopback-logging.test.ts asserts it never fires).
* chore(docs): regenerate docs map after retired-key cleanup
* refactor(gateway): remove dead sessions.observer.ask rpc
* docs: record btw and companion contract split
* fix(gateway): unexport observer model sanitizer after ask removal
* feat(anthropic): gate live model discovery on contract coverage
Live catalog discovery cloned a template for any newly discovered Claude id, so
a future model generation would be selectable while request shaping treated it
as pre-4.6 and 400d. Add an opt-in acceptUnknownModel gate to the shared live
catalog seam and have the Anthropic plugin accept a discovered model only when
Anthropic's advertised capabilities agree with the contracts we would apply.
Manifest-published ids bypass the gate and keep their metadata.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs(plugins): document the live-discovery admission hook
Record acceptUnknownModel in the provider-plugin SDK reference: when to use
it, that manifest-published ids bypass it, and the fail-closed guidance.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
The runtime retirement already shipped: busy deferral is automatic,
reasoning payloads stay internal, the HEARTBEAT_OK ack budget is fixed at
300 chars, the Heartbeats prompt section follows cadence, and tool-error
warnings are always on. Docs still advertised skipWhenBusy, ackMaxChars,
includeReasoning, includeSystemPromptSection, and suppressToolErrorWarnings
as live options; this aligns seven pages with the fixed policies and the
strict heartbeat field list, locks the claw-profile skipWhenBusy rejection
diagnostic with a dedicated test, renames includeReasoning-era test/comments,
and canonicalizes claw add-plan workspace path assertions (macOS realpath).
* docs: sync heartbeat, memory, commitments, and system-prompt docs with current behavior
The heartbeat doc described a removed broad default prompt; the memory doc
claimed automatic distillation that does not run on a default install; the
commitments docs advertised a snoozed status nothing currently writes; the
system-prompt doc omitted the Promised Work and Proactive Sub-Agent
Orchestration sections.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs(heartbeat): describe scheduled work accurately
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* docs(discord): document channel-allowlist and ambient room event pitfalls
Three gating behaviors that silently produce a mute or blind agent:
- A guild channels map is an allowlist. Adding one entry denies every
unlisted channel rather than leaving them at guild defaults; the "*"
wildcard key keeps the rest of the guild reachable.
- requireMention: true drops unmentioned messages before they can become
room events, so an ambient agent has no room backlog at all.
- Room events post via message(action=send), but the message tool ships
only in the messaging profile; a coding-profile agent listens and can
never speak.
Adds matching Discord failure-signature rows to channel troubleshooting.
* docs: regenerate docs map for new Discord and ambient headings
* test(telegram): consolidate bot test harness
* test(plugin-sdk): expose isolated test state
Promote the isolated OpenClaw test-state lifecycle through a narrow published Plugin SDK subpath so extension tests no longer import private core helpers. This intentional SDK surface addition is maintainer-approved.
* test(telegram): use public test-state seam
* test(plugin-sdk): keep test state local-only
Match the existing channel test-helper boundary: bundled extension tests can import the focused SDK source entrypoint, while ordinary builds and the published npm package exclude it. The earlier public classification existed only on this unmerged PR branch and was never a shipped contract.
* test(plugins): map test-state in package boundaries
* fix: SQLite WAL file can stay inflated on a running gateway until restart
Since #82366 switched the periodic 30-minute checkpoint to PASSIVE (to keep
WAL maintenance off the event loop), no checkpoint on a running process
truncates the WAL *file* any more -- only close() does, i.e. a restart.
wal_autocheckpoint recycles WAL space in place but never shrinks the file,
and is itself a PASSIVE checkpoint a reader can transiently block. So when a
reader briefly pins frames (e.g. a memory reindex, a backup, a slow query),
the WAL grows past the autocheckpoint size and then stays parked at that
high-water mark for the whole life of the process. Observed in production: a
1.6 GB agent DB left a 1.6 GB -wal that only manual TRUNCATE checkpoints
could reclaim. This affects every SQLite-backed store (task registry, plugin
state, proxy capture, memory host, ...), not just memory.
Set PRAGMA journal_size_limit (default 64 MiB, overridable via
journalSizeLimitBytes) right after wal_autocheckpoint so any completing
checkpoint -- including the PASSIVE periodic/auto ones #82366 now relies on
-- truncates the WAL file back to the ceiling. This restores the bounded
on-disk WAL that TRUNCATE used to give, without reintroducing the blocking
checkpoint #82366 removed: journal_size_limit only changes how far a
completing checkpoint truncates, never checkpoint timing. The 64 MiB ceiling
sits ~16x above the autocheckpoint steady state (~4 MB at 1000 pages), so it
is inert in normal operation and engages only on pathological growth.
Related: #82366, #81715
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: tighten SQLite WAL ceiling proof
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* refactor(channels): remove flat streaming compat
maintainer-approved early removal of v2026.7.2-gated compat
* refactor(channels): remove group intro hint adapter
maintainer-approved early removal of v2026.7.2-gated compat
Plugin SDK surface baseline update is maintainer-approved for this intentional removal.
* feat(ui): repair settings titles, scope form-unsafe banner, consolidate advanced tier
- Advanced/Notifications settings headers rendered raw i18n keys
(tabs.advanced/tabs.notifications); configPageTitle now resolves through
the nav registry titleForRoute, deleting the drifting key map.
- Form-unsafe banner is value-aware (only when the user's config has a value
at a form-unsupported path in the active scope), names the paths, offers an
Open Raw editor action, and sits in the content column instead of full-bleed.
- Advanced tier collapses to one synced toggle: hidden advanced fields render
a ghost row that enables the toggle; the Advanced page always reveals and
hides the toggle; per-section details state and the controlled-open dance
are deleted; toggle visibility mirrors the renderer's tier split.
- schema.tags no longer tags facet-less paths as "advanced" (common fields
like update.channel wore a lying chip); the chip is no longer rendered in
form rows while tag:advanced search keeps working.
* fix(config): dev bootstrap writes canonical agents.entries; finish stale agents.list sweep
- openclaw gateway run --dev failed on a fresh state dir: the bootstrap wrote
the retired agents.list array and validation rejected its own config
(Unrecognized key: list). It now writes the keyed agents.entries record;
new dev.test.ts validates the written shape against the zod schema.
- Revive the dead gateway hot-reload rule: prefix agents.list never matched
canonical config diffs, so per-agent heartbeat edits fell through to the
agents:none tail rule; the rule now matches agents.entries.
- config set replacement protection moves from the dead agents.list array
to the agents.entries map (joins plugins.entries/auth.profiles family).
- Sweep remaining stale agents.list config-path strings in hints, fix-it
messages, elevated gates, doctor hints, audit text, and type docs to
agents.entries.*; RPC ids, the internal list projection, and doctor
legacy-migration references intentionally keep the old name.
* test(ui): derive nav i18n audit from route registry; fix stale bootstrap hint assertion
- Knip flagged navigationCopyEntries (test-only export); the audit now walks
ALL_ROUTES through prod titleForRoute/subtitleForRoute and rejects raw
dotted-key output, so no export exists solely for the test.
- commands-context-report expected the retired agents.list[] hint wording.
* fix(config): align rebase resolution with main's roster-aware diagnostic
- tool-policy-diagnostic: keep main's test expectations (dotted
agents.entries.<id> paths from the roster-aware implementation); our
pre-rebase bracket-style assertions no longer match any code.
- Reapply the placeholder sweep the conflict resolution dropped:
generic agents.list[] fallbacks in tool-policy-diagnostic and the audit
sandbox-mode hint now say agents.entries.*.