{"id":"500dd11d-7d2d-4960-9de7-b5a725f96b55","entityType":"agent","slug":"clawhub-bkf-gitty-claw-update-runbook","name":"OpenClaw Update Runbook","canonicalUrl":"https://www.xpersona.co/agent/clawhub-bkf-gitty-claw-update-runbook","canonicalPath":"/agent/clawhub-bkf-gitty-claw-update-runbook","generatedAt":"2026-10-11T20:57:50.579Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T16:20:44.716Z","emptyReason":null},"description":"Use when updating OpenClaw or debugging an OpenClaw instance after an update. This skill acts as a structured update runbook with emphasis on gateway startup...","descriptionLabel":"Source description","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 1K downloads reported by the source. Last updated 10/11/2026.","installCommand":"clawhub skill install s170vkzshxphjazbn77zkncnhx86ge19:claw-update-runbook","sourceUrl":"https://clawhub.ai/bkf-gitty/claw-update-runbook","homepage":"https://clawhub.ai/bkf-gitty/skills/claw-update-runbook","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/bkf-gitty/claw-update-runbook","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/bkf-gitty/skills/claw-update-runbook","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":60,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"OpenClaw Update Runbook technical dossier on Xpersona with agent coverage, OPENCLEW support, and live trust metadata."},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-11T16:20:44.716Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T16:20:44.716Z","emptyReason":null},"stars":null,"forks":null,"downloads":1029,"packageName":null,"latestVersion":"1.0.6","tractionLabel":"1K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T16:20:44.702Z","emptyReason":null},"lastUpdatedAt":"2026-10-11T16:20:44.716Z","lastCrawledAt":"2026-10-11T16:20:44.702Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-12T16:20:44.702Z","lastVerifiedAt":null,"highlights":[{"version":"1.0.6","createdAt":"2026-05-28T16:55:26.552Z","changelog":"Sanitized public runbook update with service-user diagnostics, ClawHub Codex extension drift checks, isolated Codex-home guidance, and generic shared-repo wording.","fileCount":7,"zipByteSize":31862},{"version":"1.0.2","createdAt":"2026-05-23T07:59:25.577Z","changelog":"Add remote stable-recovery reachability guidance","fileCount":12,"zipByteSize":40272},{"version":"1.0.1","createdAt":"2026-05-12T23:08:00.692Z","changelog":"Add Codex runtime smoke-test guidance and sanitized beta failure pattern","fileCount":6,"zipByteSize":23235},{"version":"1.0.0","createdAt":"2026-05-12T21:53:41.599Z","changelog":"Initial release: a structured OpenClaw update and recovery runbook for operators using Codex or Claude-style agents. Includes the main skill instructions, README, and a companion failure-pattern reference for service health, plugin drift, config changes, model routing, channel checks, cron verification, and post-update diagnostics.","fileCount":6,"zipByteSize":22841}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s170vkzshxphjazbn77zkncnhx86ge19:claw-update-runbook","setupComplexity":"low","setupSteps":["Install using `clawhub skill install s170vkzshxphjazbn77zkncnhx86ge19:claw-update-runbook` in an isolated environment before connecting it to live workloads.","No published capability contract is available yet, so validate auth and request/response behavior manually.","Review the upstream CLAWHUB listing at https://clawhub.ai/bkf-gitty/claw-update-runbook before using production credentials."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-bkf-gitty-claw-update-runbook/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-bkf-gitty-claw-update-runbook/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-bkf-gitty-claw-update-runbook/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-bkf-gitty-claw-update-runbook/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-bkf-gitty-claw-update-runbook/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-bkf-gitty-claw-update-runbook/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-11T20:57:50.574Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-bkf-gitty-claw-update-runbook/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-bkf-gitty-claw-update-runbook/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-bkf-gitty-claw-update-runbook/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-bkf-gitty-claw-update-runbook/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T16:20:44.716Z","emptyReason":null},"readme":"Skill: OpenClaw Update Runbook\n\nOwner: bkf-gitty\n\nSummary: Use when updating OpenClaw or debugging an OpenClaw instance after an update. This skill acts as a structured update runbook with emphasis on gateway startup...\n\nTags: latest:1.0.6\n\nVersion history:\n\nv1.0.6 | 2026-05-28T16:55:26.552Z | user\n\nSanitized public runbook update with service-user diagnostics, ClawHub Codex extension drift checks, isolated Codex-home guidance, and generic shared-repo wording.\n\nv1.0.2 | 2026-05-23T07:59:25.577Z | user\n\nAdd remote stable-recovery reachability guidance\n\nv1.0.1 | 2026-05-12T23:08:00.692Z | user\n\nAdd Codex runtime smoke-test guidance and sanitized beta failure pattern\n\nv1.0.0 | 2026-05-12T21:53:41.599Z | user\n\nInitial release: a structured OpenClaw update and recovery runbook for operators using Codex or Claude-style agents. Includes the main skill instructions, README, and a companion failure-pattern reference for service health, plugin drift, config changes, model routing, channel checks, cron verification, and post-update diagnostics.\n\nArchive index:\n\nArchive v1.0.6: 7 files, 31862 bytes\n\nFiles: agents/openai.yaml (303b), LICENSE (1056b), README.md (2813b), references/failure-patterns.md (61670b), skill-card.md (2322b), SKILL.md (15611b), _meta.json (138b)\n\nFile v1.0.6:SKILL.md\n\n---\nname: openclaw-update-runbook\ndescription: Use when updating OpenClaw or debugging an OpenClaw instance after an update. This skill acts as a structured update runbook with emphasis on gateway startup, service-manager state, plugin registry and install drift, bundled-vs-npm/clawhub plugin confusion, stale config carried across upgrades, channel health, task ledger corruption, and logs that explain why the updated system is slow, disconnected, or half-broken.\nversion: 1.0.6\nmetadata:\n  openclaw:\n    emoji: \"🦞\"\n---\n\n# OpenClaw Update Runbook\n\nUse this skill when an OpenClaw host was just updated, is about to be updated, or is behaving strangely after an update. It is a generic operator runbook, not a release-specific checklist.\n\nThis skill is meant to be installed as a folder, not copied as a single file. It expects `references/failure-patterns.md` to exist locally beside `SKILL.md` inside the same skill bundle.\n\nThe goal is not only to get it running, but to prove which layer is broken:\n\n- service lifecycle and service-manager state\n- host package version\n- plugin/package compatibility\n- config drift\n- model/provider runtime routing\n- channel health\n- task ledger health\n- cron/session isolation and channel-lane ownership\n- runtime performance\n- command-path and update-channel assumptions\n- self-update hazards when an agent updates the gateway that is running it\n- supply-chain and package-integrity spot checks after plugin/npm churn\n\n## Quick workflow\n\n1. Establish the real starting state.\n   For remote multi-host updates, first prove SSH reachability to each host\n   with a short timeout. If a host cannot be reached directly or through an\n   available jump host, record it as a transport/access blocker instead of an\n   OpenClaw update failure, because no OpenClaw command has executed on that\n   host yet.\n\n   If you are connected over non-interactive SSH, do not assume the\n   login-shell `PATH` is available. First locate the binary with common install\n   paths such as a package-manager prefix and `~/.local/bin/openclaw`, then\n   export the correct `PATH` for the audit session.\n\n   If the gateway process is owned by a different OS user than the SSH login\n   user, run OpenClaw diagnostics as the gateway service user. The SSH user can\n   have no `openclaw` on PATH, or a private package-manager shim can be\n   unreadable, while the LaunchAgent/systemd service is healthy under another\n   home directory. Derive the service user, state dir, CLI path, and port from\n   the live process/service definition before running `doctor` or editing\n   config.\n\n   Check:\n   - `openclaw --version`\n   - `openclaw update status`\n   - `openclaw status --deep`\n   - `openclaw doctor --non-interactive --no-workspace-suggestions`\n   - `openclaw channels status --deep`\n   - `openclaw tasks audit`\n   - current model routing: agent defaults, agent-level model maps, fallback chains, and cron payload models\n   - recent successful sessions for the primary model and runtime, not just the display model name\n\n2. Verify the gateway is actually managed correctly.\n   Look at service-manager state, running PID, and `/health`.\n   Derive the service label/name and gateway port from `openclaw status --deep`\n   and/or the service definition instead of guessing them.\n   Do not trust only one of:\n   - the host's service manager\n   - process list\n   - health endpoint\n\n   It is common to have:\n   - a service definition present but not loaded\n   - a detached gateway process still serving traffic\n   - the service manager and the live process disagreeing\n\n3. Separate bundled plugins from globally installed plugins.\n   First inspect plugin health:\n   - `openclaw plugins doctor`\n   - `openclaw plugins list --json`\n   - `openclaw plugins inspect <id>`\n\n   Important rule:\n   - If a capability is supposed to be bundled, verify whether a stale global npm install is shadowing it.\n   - If a capability is not bundled, check npm and ClawHub before assuming config is wrong.\n   - For special runtime plugins such as `codex`, compare `plugins inspect <id>`\n     with `plugins list --json`; inspect can report a runtime as loaded while\n     raw plugin metadata still says disabled.\n   - For ClawHub/runtime plugins such as `codex`, compare the plugin version\n     against the host version even when `plugins doctor` is clean. Use\n     `openclaw plugins update <id> --dry-run` to see whether an official\n     matching package exists before changing broader model config.\n\n4. Check for config carried across the upgrade that no longer validates.\n   Pay attention to:\n   - `tools.web.search.provider`\n   - `plugins.allow`\n   - `plugins.entries.*`\n   - model aliases and fallback chains\n   - runtime mappings for `openai/*`, `openai-codex/*`, `codex`, and `pi`\n   - cron job payload model refs, which can be normalized separately from agent defaults\n   - update channel metadata\n\n   If doctor says a provider or plugin is unknown, inspect the actual config file and do not assume `doctor --fix` fully cleaned it.\n\n5. Compare plugin install records to what exists on disk.\n   Inspect:\n   - `~/.openclaw/plugins/installs.json`\n   - `~/.openclaw/npm/node_modules/@openclaw/...`\n   - `~/.openclaw/extensions/...`\n\n   Look for:\n   - recorded install paths that do not exist\n   - recorded versions drifting from installed versions\n   - ClawHub-installed runtime plugins under `~/.openclaw/extensions/<id>` that\n     load successfully but lag the host cohort\n   - npm install records where `resolvedSpec`, integrity, and installed version\n     are exact, but the stored `spec` is still a bare package name such as\n     `@openclaw/discord`\n   - package specs rewritten or preserved during `openclaw update --channel ...`\n   - external plugins that lack a release for the selected channel and were\n     installed from a fallback tag such as `@latest`\n   - source-only TypeScript plugin packages with no compiled `dist/`\n   - plugin runtime deps removed from third-party plugin directories\n\n6. Inspect recent gateway logs before changing too much.\n   Read:\n   - `~/.openclaw/logs/gateway.log`\n   - `~/.openclaw/logs/gateway.err.log`\n   - `/tmp/openclaw/openclaw-YYYY-MM-DD.log`\n\n   Prioritize recent startup lines and warnings involving:\n   - plugin load failures\n   - config validation\n   - provider fallback attempts and primary-route auth or module failures\n   - update lifecycle messages such as service stop fallbacks,\n     config overwrites/backups, and service reload timing\n   - channel auth (if a channel returns 401/auth-failure post-update, inspect `~/.openclaw/service-env/*.env` for token-line quote corruption — see Pattern #23 — before assuming the upstream credential was rotated)\n   - context-engine fallback\n   - active-memory timeouts\n   - event loop degradation\n   - task restart blocking\n   - transient post-restart UI/websocket scope errors that clear after the\n     gateway is ready\n\n7. Audit runtime/task health after the upgrade.\n   Check for:\n   - stale running tasks\n   - lost tasks\n   - delivery failures\n   - timestamp inconsistencies\n   - cron jobs whose persisted `sessionKey` points at a live channel lane\n     such as `agent:<agent>:discord:direct:*` despite `sessionTarget: isolated`\n\n   A successful package update can still leave the system unhealthy if stale tasks block restarts or keep the audit red.\n\n8. Prove the primary model route, not just overall agent success.\n   Run a narrow direct agent smoke test with a fresh session id and inspect the returned metadata:\n   - final provider and model\n   - runtime or harness id\n   - `fallbackAttempts`\n   - provider auth errors\n   - module load errors\n   - schema validation errors\n\n   Treat `status: ok` as insufficient if the primary model failed and a fallback provider completed the run.\n   Treat a clean `plugins doctor` as insufficient for runtime plugins until a\n   fresh direct agent run proves that the intended harness can load and execute.\n\n9. If the update was initiated from inside OpenClaw, audit it as a special risk.\n   An OpenClaw agent can sometimes update the package it is running under, but\n   that path has repeatedly left hosts with the package changed and the managed\n   service unloaded or not restarted. From an outside SSH shell, verify:\n   - whether the requested version actually installed\n   - whether the managed service is loaded/running after the update\n   - whether the gateway `/health` endpoint and channels recovered\n   - whether a fresh `openclaw gateway restart` repairs an installed-but-unloaded\n     service without any further package changes\n\n   Do not treat the agent conversation's final message as authoritative. Trust\n   the post-update host state.\n\n10. Test at least one representative cron path.\n   Check:\n   - cron payload model counts\n   - model counts by `agentId` so temporary provider workarounds can be\n     rolled back without flattening full-size and mini cron routes together\n   - persisted `sessionKey` values, especially channel/direct-message keys on\n     isolated cron jobs\n   - named or high-value cron job status\n   - manual `cron run` behavior\n   - whether `--expect-final` actually waits for final completion on the current build\n   - recent run history for the specific job id, not only current job state,\n     so stale last-run errors are separated from active regressions\n\n   If cron verification only proves enqueue, state that clearly in the handoff notes.\n\n11. Run a targeted npm/plugin supply-chain spot check when plugin installs changed.\n   This is especially important after a failed plugin install, external plugin\n   fallback, or public npm compromise advisory. Check:\n   - whether `openclaw security audit --deep` flags unpinned npm plugin specs\n     after plugin update churn\n   - exact installed package versions against the advisory list\n   - plugin install roots such as `~/.openclaw/npm/node_modules`\n   - global OpenClaw/npm roots such as `/opt/homebrew/lib/node_modules`\n   - obvious malicious lifecycle hooks in `package.json`\n   - persistence artifacts named by the advisory\n   - lockfiles and config files for strong IoCs\n\n   State the limits of the check: a live-system scan cannot prove a package was\n   never installed and removed earlier.\n\n12. Re-run the narrowest fix, then verify again.\n   Common fix sequence:\n   - stop gateway cleanly\n   - update host package\n   - refresh plugin registry if needed\n   - repair or update broken plugin installs\n   - restart gateway\n   - re-run `doctor`, `plugins doctor`, `status --deep`, `channels status --deep`, and `tasks audit`\n\n## Where to look first\n\nUse this order when diagnosing post-update failures:\n\n- Service state: service manager, PID, `/health`\n- Host version: `openclaw --version`\n- Plugin mismatch: `openclaw plugins doctor`\n- Config drift: `openclaw doctor`\n- Channel reality: `openclaw channels status --deep`\n- Task ledger: `openclaw tasks audit`\n- Model/runtime route reality: direct smoke metadata and fallback attempts\n- Runtime symptoms: gateway logs\n\n## When to open references\n\nStart with this file first.\n\nOpen [references/failure-patterns.md](references/failure-patterns.md) when:\n\n- `doctor` or `plugins doctor` points to a known-looking regression\n- `channels status` or logs disagree with the apparent service health\n- plugin installs, install records, or config state do not match what is on disk\n- the update completed, but the host is still slow, disconnected, noisy, or half-broken\n\nUse the reference file for symptom matching and concrete examples after the main workflow has narrowed the likely failure area.\n\n## Bundled vs external plugin rule\n\nDo not assume a broken plugin means \"plugin missing.\"\n\nThere are three common cases:\n\n- Bundled plugin exists in the host package, but stale config still points at an old provider/plugin id.\n- Bundled plugin exists, but a globally installed npm plugin shadows it and is on the wrong version.\n- Plugin is not bundled, so the fix is to inspect npm or ClawHub and reconcile install records.\n\nA channel plugin is a good example of the second case: a host can upgrade correctly while still loading an older globally installed plugin package.\n\nIf the feature is not bundled, check npm and ClawHub before rewriting config.\n\n## Fixing mindset\n\nPrefer the smallest fix that makes state consistent again:\n\n- refresh registry before reinstalling everything\n- update one stale plugin before removing all plugins\n- inspect the actual config file when helper commands appear to succeed but warnings remain\n- verify whether a third-party plugin needs local runtime deps before deleting plugin-side `node_modules`\n\nDo not stop at \"service is up.\" A good finish means:\n\n- the right version is installed\n- the gateway is managed correctly\n- channels are connected\n- the intended primary model route succeeds without an unexpected fallback\n- cron payload models and representative cron jobs are healthy\n- plugin doctor is clean or explained\n- task audit is not carrying a fresh blocking error\n\n## Handoff notes\n\nIf the upgrade exposed an OpenClaw bug rather than local drift, collect enough information for the next operator or project/support contact. Do not assume the user has any particular external account or wants a public report created.\n\n- exact version before and after\n- relevant config keys\n- primary model route before and after, including runtime id\n- direct smoke result metadata, especially `fallbackAttempts`\n- cron model map before and after any temporary workaround, including mini\n  routes and inherited/default model cases\n- exact first bad cron run timestamps from `openclaw cron runs --id <id>`,\n  not just the time the operator noticed the issue\n- any cron `sessionKey` values that crossed channel/session boundaries, after\n  replacing channel ids and account ids with placeholders\n- plugin source path actually loaded\n- installed package version and file layout for any failing npm plugin\n- whether the plugin was bundled or globally installed\n- gateway OS service user and command path when they differ from the SSH user\n- exact update command and selected channel\n- whether external plugins used channel-specific versions or fallbacks\n- service stop/restart messages, especially if the service manager needed a fallback stop/unload path\n- `doctor`/`plugins doctor` warning text\n- the specific log lines around startup failure or restart\n\nSanitize handoff notes before sharing externally:\n- remove hostnames, usernames, IPs, machine names, tokens, account ids, channel ids, and personal job names\n- replace local paths with placeholders such as `<state>`, `<global-openclaw>`, and `~/.openclaw`\n- summarize private prompt/session contents instead of quoting them\n- keep exact version numbers, package names, model ids, runtime ids, and error classes when they are needed to reproduce the bug\n\nFor concrete regression patterns and example symptoms, read [references/failure-patterns.md](references/failure-patterns.md).\n\n## Updating this skill\n\nWhen another operator or agent learns something new from a different OpenClaw host:\n\n- do not delete existing workflow steps unless they are clearly wrong\n- do not replace an existing failure pattern with a narrower one\n- prefer additive updates over rewrites\n- add new regression patterns to `references/failure-patterns.md`\n- only tighten the main workflow in this file if the new lesson changes the recommended audit order for most hosts\n\nIf a new finding is host-specific or uncertain, add it as a new failure pattern with:\n\n- symptom\n- what to inspect\n- why it matters\n\nDo not silently erase older patterns just because the current host did not hit them.\n\nFile v1.0.6:README.md\n\n# OpenClaw Update Runbook\n\nAn operator-focused skill and reference pack for updating OpenClaw, debugging post-update regressions, and proving which layer is actually broken before making changes.\n\nThis skill turns the update/debug process into a repeatable audit: establish the real host state, inspect service and plugin drift, verify model routing, then apply the smallest repair that makes the system consistent again.\n\nInstall or copy the whole folder so `SKILL.md` and `references/failure-patterns.md` stay together. The skill expects those files to exist side by side on disk.\n\n## What it includes\n\n- `SKILL.md`: the main update runbook skill\n- `references/failure-patterns.md`: concrete regression patterns seen across multiple hosts\n- `agents/openai.yaml`: lightweight agent metadata for skill catalogs that use it\n\n## What it helps with\n\n- confirming the real service state after an update\n- separating service-manager issues from detached-process issues\n- spotting bundled-vs-global plugin drift\n- finding stale config that survives upgrades\n- checking whether plugin install records match disk reality\n- reading the right logs before changing too much\n- cleaning up task ledger problems that keep a host noisy or half-broken\n\n## Who this is for\n\n- operators maintaining one or more OpenClaw hosts\n- operators helping a team or another maintainer recover after an update\n- anyone who wants a structured checklist for \"OpenClaw feels broken after upgrade\"\n\n## Install\n\nPlace the folder where your agent skills live, or install it through a compatible skill manager.\n\nDo not copy only `SKILL.md`. The skill refers to local companion files under `references/` and `agents/`.\n\nThe main entry point is:\n\n- `SKILL.md`\n\n## How to use\n\nInvoke the skill when you are:\n\n- upgrading OpenClaw\n- checking health right after an upgrade\n- debugging a host that became slow, disconnected, or inconsistent after update\n\nThe agent should start with `SKILL.md` and open `references/failure-patterns.md` only when the main workflow points to a known regression pattern or contradictory runtime symptoms.\n\nThe runbook is intentionally conservative: verify service reality first, inspect plugin and config drift second, then apply the smallest fix that makes the host consistent again.\n\n## Maintenance model\n\nThis runbook is cumulative. New host-specific lessons should usually be added to `references/failure-patterns.md` rather than replacing existing guidance.\n\nContribution style:\n\n- additive over destructive\n- preserve older patterns unless they are clearly wrong\n- keep examples generic and free of secrets or personal host details\n\n## Suggested catalog description\n\nStructured OpenClaw update runbook for AI-agent operators: service checks, plugin drift, config regressions, task cleanup, and post-upgrade debugging.\n\nFile v1.0.6:_meta.json\n\n{\n  \"ownerId\": \"kn72yh2bfzkawx37gayv80km7186hw0q\",\n  \"slug\": \"claw-update-runbook\",\n  \"version\": \"1.0.6\",\n  \"publishedAt\": 1779987326552\n}\n\nFile v1.0.6:references/failure-patterns.md\n\n# Failure Patterns\n\nUse this file when the main skill identifies a likely upgrade regression and you need concrete examples of what to inspect.\n\nContribution rule:\n- append new patterns or expand existing ones\n- do not delete older patterns unless they are proven false\n- preserve examples from other hosts even if the current host is healthy\n\n## 1. Update channel drift\n\nSymptom:\n- host is intentionally on beta or a newer stable build\n- `status --deep` says local version is newer than `npm latest`\n- config still says `\"update.channel\": \"stable\"` after a beta install\n\nWhat to inspect:\n- `openclaw --version`\n- `openclaw status --deep`\n- `openclaw.json` update metadata\n\nWhy it matters:\n- operators get misleading update advice\n- handoff notes should call out when install/update channel state is not persisted\n\n## 2. Stale config after upgrade\n\nSymptom:\n- `doctor` says provider or plugin is unknown\n- runtime falls back to auto-detect or legacy behavior\n- helper commands claim to fix config, but warnings remain\n\nCommon keys:\n- `tools.web.search.provider`\n- `plugins.allow`\n- `plugins.entries.*`\n\nTypical example:\n- `tools.web.search.provider=brave` remains after host/plugin changes and becomes invalid\n\n## 3. Bundled plugin vs global npm plugin shadowing\n\nSymptom:\n- bundled capability should work after host upgrade\n- `plugins list` shows a global plugin path under `~/.openclaw/npm/node_modules`\n- plugin version does not match host version\n\nExample:\n- host on `<current-version>`\n- global `@openclaw/discord` still at `<previous-version>`\n- gateway warns about missing compiled runtime output because the global plugin is source-only\n\nWhat to inspect:\n- `openclaw plugins inspect <id>`\n- plugin `source`\n- plugin `origin`\n- plugin `version`\n- presence of `dist/`\n\n## 4. Install records drift from disk reality\n\nSymptom:\n- config or install registry says a plugin is installed\n- recorded path under `~/.openclaw/npm/node_modules/@openclaw/` or `~/.openclaw/extensions/` does not exist\n- plugin not found / phantom allowlist warnings\n\nWhat to inspect:\n- `~/.openclaw/plugins/installs.json`\n- actual install path on disk\n- `openclaw plugins registry --refresh`\n\nThis is the case where reinstalling the plugin is often correct.\n\n## 5. Third-party plugin runtime deps removed\n\nSymptom:\n- after `doctor --fix` or cleanup, a third-party plugin fails to load\n- error looks like `Cannot find module ...`\n- plugin root still exists, but plugin-side `node_modules` is gone\n\nWhat to inspect:\n- plugin package directory\n- plugin `package.json`\n- whether dependencies are externalized at build time\n\nWhy it matters:\n- cleanup can be too aggressive for non-bundled plugins\n\n## 6. Context engine not registered after restart\n\nSymptom:\n- logs say context engine falls back to legacy\n- plugin may still be installed but failed to initialize\n\nLook for:\n- plugin load errors\n- missing dependencies\n- plugin contract warnings\n- plugin registry metadata drift\n\n## 7. Event loop degradation after update\n\nSymptom:\n- `channels status --deep` reports degraded event loop\n- logs show lane wait exceeded, active-memory timeouts, or restart blocked by active tasks\n\nCommon culprits:\n- stale running tasks\n- active-memory timeout loops\n- plugin load retries\n- long-running approval followups\n\nCheck:\n- `openclaw tasks audit`\n- recent `gateway.err.log`\n- recent `gateway.log`\n\n## 8. Task ledger blocks clean restart\n\nSymptom:\n- restart or drain says blocked by active task runs\n- `tasks audit` shows `stale_running`, `lost`, or repeated delivery failures\n\nUseful commands:\n- `openclaw tasks show <id>`\n- `openclaw tasks cancel <id>`\n- `openclaw tasks maintenance --apply`\n\nFix the ledger if it is obviously wrong; otherwise every later health check becomes noisy.\n\n## 9. Command-path disagreement\n\nSymptom:\n- `status --deep` says a channel token is unavailable in this command path\n- `channels status --deep` says channel is connected and healthy\n\nTreat this as a reporting mismatch first, not a real outage.\n\nAdditional example:\n- A channel can be healthy in the gateway service with `token:env`, while `doctor` still warns that the corresponding token env var is absent in the doctor environment.\n- Verify the service env file and `channels status`; do not treat the doctor shell-env warning alone as proof the live gateway is down.\n\n## 10. What to hand the next operator or support contact\n\nWhen a problem looks like an update regression, capture:\n\n- host version before and after\n- whether the capability was bundled, npm-installed, or ClawHub-installed\n- the plugin source path actually loaded\n- stale config keys still present after fix attempts\n- exact `doctor` and `plugins doctor` messages\n- startup log lines around the failure\n\n## 11. Plugin updater follows stale install records\n\nSymptom:\n- core OpenClaw is updated, but `~/.openclaw/plugins/installs.json` still records older plugin specs\n- `openclaw plugins update --all` tries to reinstall the older recorded versions instead of reconciling to the currently installed packages\n- plugin directories under `~/.openclaw/npm/node_modules/@openclaw/` may disappear or config suddenly becomes invalid until the exact desired versions are reinstalled\n\nTypical example:\n- host core is updated\n- install records still point at older plugin specs\n- running `openclaw plugins update --all` attempts the old plugin specs and leaves channel plugins missing on disk until the intended package versions are reinstalled\n\nWhat to inspect:\n- `~/.openclaw/plugins/installs.json`\n- actual package versions in `~/.openclaw/npm/node_modules/@openclaw/*/package.json`\n- whether the plugin directories still exist after `plugins update --all`\n\nWhy it matters:\n- the built-in updater can deepen an upgrade regression if install metadata drift is not corrected first\n- prefer reconciling install records or reinstalling exact target versions before trusting `openclaw plugins update --all`\n\nRefinement:\n- `openclaw plugins registry --refresh` does NOT rewrite the install record's `spec` field. It refreshes `hostContractVersion` and compatibility data only.\n- After a refresh, install records can still carry pinned specs like `<plugin>@<older-version>` even when the disk version is `<newer-version>`. `plugins update --all` will then **downgrade** the on-disk plugin to match the pinned spec.\n- Correct sequence to actually move a third-party plugin forward:\n  1. `openclaw plugins update <id> @<scope>/<pkg>@latest` (note: `update` accepts an explicit spec; this rewrites the install record's spec).\n  2. Or `openclaw plugins install <pkg>@latest --force` to drop the pin.\n- `--all` is safe only after every install record's `spec` already points at `@latest` or the desired version — never trust it after a host upgrade without spot-checking install records first.\n\n## 12. Control UI token mismatch after restart\n\nSymptom:\n- gateway is healthy and reachable\n- dashboard page loads, but websocket auth fails\n- `gateway.err.log` shows `[ws] unauthorized ... reason=token_mismatch`\n- log text may say `unauthorized: gateway token mismatch (open the dashboard URL and paste the token in Control UI settings)`\n\nWhat to inspect:\n- recent `~/.openclaw/logs/gateway.err.log` websocket auth lines\n- whether `gateway.auth.token` or its SecretRef source changed during reinstall/restart\n- whether the browser-side Control UI is still holding an older token\n\nWhy it matters:\n- this can look like a gateway outage even when the backend is healthy\n- separate UI auth cache problems from real startup or channel failures before changing server-side config again\n\n## 13. Channel SecretRef resolves but runtime account still cannot use it\n\nSymptom:\n- `openclaw config validate` passes\n- `openclaw secrets audit` reports `unresolved=0`\n- `openclaw channels status` says a channel is configured but stopped/disconnected with `secret unavailable in this command path`\n- logs say a channel token is unavailable, for example a channel delivery path says the bot token configured for account `default` is unavailable\n\nWhat to inspect:\n- the channel token config path, for example `channels.discord.token`\n- the referenced secrets provider and backing file\n- whether the gateway service env has a working token fallback\n- whether the channel plugin prefers the broken config SecretRef over the env fallback\n\nObserved workaround:\n- add the token to the service env from the existing local secret source\n- remove the broken channel token config field so the channel falls through to the env-token path\n- restart gateway and verify `channels status` reports `token:env` and connected\n\nWhy it matters:\n- schema validation and secrets audit can both pass while the channel runtime still cannot consume the SecretRef\n- this can leave a channel integration down after an update even though the secret exists\n\nConfirmed regression scope:\n- Reproduced cleanly across multiple adjacent channel-plugin versions with a SecretRef pointing at a valid `secrets.json` entry.\n- `openclaw secrets audit` reports `unresolved=0`, `openclaw secrets reload` says \"Secrets reloaded.\", but the channel plugin still throws `unresolved SecretRef ... Resolve this command against an active gateway runtime snapshot before reading it.` at startup.\n- Sibling plugins using the same SecretRef shape (e.g. brave's `/brave_api_key`) resolve fine — the bug is plugin-side, not in the secrets layer.\n- Pragmatic workaround (when env fallback isn't available): inline the literal token into the affected channel token field. This adds one entry to `secrets audit --plaintext` findings but restores the channel. Plan to revert once upstream `@openclaw/discord` ships a fix that resolves SecretRefs against the runtime snapshot.\n\nAddendum — `token:config` in `channels status` is ambiguous:\n- the same status row appears whether the token came from a successfully resolved SecretRef OR from an inline literal (workaround applied); it is not a signal that the upstream bug is fixed.\n- To disambiguate, inspect the actual config field directly:\n  - `node -e 'const c=JSON.parse(require(\"fs\").readFileSync(process.env.HOME+\"/.openclaw/openclaw.json\",\"utf8\")); console.log(typeof c.channels?.discord?.token, c.channels?.discord?.token)'`\n  - `string` value → inline literal (workaround in place)\n  - `object` value → SecretRef (relies on plugin runtime resolution)\n- An operator running this runbook on an inherited host should not assume `token:config` means the regression is gone; verify the field shape before claiming the workaround is no longer needed.\n\n## 14. Gateway CLI start reports argument error but managed service recovers\n\nSymptom:\n- after update, `openclaw gateway start` prints an argument-count error\n- the command may still re-bootstrap the managed service afterward\n- the service manager and open port check show the gateway running despite the CLI error\n\nWhat to inspect:\n- the host service-manager status command\n- listener on the configured gateway port\n- `openclaw status`\n- gateway stdout/stderr logs\n\nWhy it matters:\n- the CLI error is alarming but may not be the actual outage\n- verify service reality before retrying installs or rolling back\n\n## 15. `plugins uninstall` is destructive of every config trace, not just the install record\n\nSymptom:\n- after `openclaw plugins uninstall <id> --force`, the plugin disappears from `plugins list` as expected\n- but the plugin then shows as `disabled` once you try to re-enable a sibling install (e.g., a copy under `~/.openclaw/extensions/`)\n- exclusive slots (e.g., `plugins.slots.contextEngine`) silently revert to `legacy`\n\nWhat `uninstall` can remove:\n- the install record in `~/.openclaw/plugins/installs.json`\n- the on-disk install directory\n- `plugins.entries.<id>` from `openclaw.json`\n- the `<id>` entry from `plugins.allow`\n- exclusive slot assignments where `<id>` was the holder\n\nRecovery after rolling back to a different copy of the same plugin:\n- `openclaw plugins enable <id>` re-adds the entry, allowlist row, and slot assignment\n- restart gateway\n\nCLI flag note:\n- `plugins uninstall` does not accept `--yes`, `-y`, or `--non-interactive`. Use `--force` to skip the confirmation prompt over a non-interactive shell.\n\nWhy it matters:\n- treat `uninstall` as \"wipe all traces\", not as \"remove just the install record\"\n- if you only wanted to swap install paths (npm → extensions or vice versa), prefer manual relocation + `plugins registry --refresh` over `uninstall` + reinstall\n\n## 16. Third-party plugin declares optional peer dependency but compiled bundle imports it unconditionally\n\nSymptom:\n- after upgrading a third-party plugin, `plugins doctor` reports a load failure like `Error [ERR_MODULE_NOT_FOUND]: Cannot find package '<peer-package>'`\n- the plugin's `package.json` lists the missing package under `peerDependenciesMeta` with `optional: true`, suggesting it should be skippable\n\nRoot cause:\n- the published `dist/index.js` was emitted with an unconditional `import` of an \"optional\" peer dependency\n- Node's ESM resolver cannot satisfy the import, so the plugin fails to load even though `package.json` says the dep is optional\n\nTypical example:\n- `<plugin>@<version>` declared `<peer-package>` as `peerDependenciesMeta.<dep>.optional: true`\n- the plugin still failed to load because `dist/index.js` imported it unconditionally\n- the previous version shipped a bundled `node_modules/` next to the plugin and worked fine\n- `plugins update --all` on a host with a stale install record (pattern #11) may downgrade instead, masking this as a different failure mode\n\nWhat to inspect:\n- `package.json` `peerDependencies`, `peerDependenciesMeta`, `dependencies`, `devDependencies`\n- the actual import sites in `dist/index.js` (`grep -E \"from '@.*pi-\" dist/index.js`)\n- whether a previous version's bundled deps are still on disk (e.g., `~/.openclaw/extensions/<id>.stale-*` or `.backup-*` directories)\n\nRecovery:\n- roll back to the last known-good plugin version, ideally one that bundled its deps\n- prefer renaming the broken install dir (e.g., to `<dir>.broken-<date>`) over deleting it, so the failure can still be reproduced for an upstream report\n- share upstream or with support: declared optional deps in `package.json` vs unconditional imports in `dist`\n\nWhy two hosts on the same plugin version can show different results:\n- the bug only surfaces when Node's ESM resolver cannot find the \"optional\" peer from the plugin's location\n- on hosts where the peer is **hoisted** at `~/.openclaw/npm/node_modules/<scope>/<peer>` (sibling to the plugin), the import succeeds silently and `plugins doctor` reports clean\n- the peer can also be satisfied by a copy under `<global-openclaw>/node_modules/<scope>/<peer>` (bundled with the host package), or by leftover `~/.openclaw/plugin-backups/<id>.*/node_modules/<scope>/<peer>` directories from a prior disabled install\n- a host that recently ran a clean reinstall (or `npm prune`, or a `doctor --fix` cleanup that removed disabled plugin backups) is more likely to hit the failure than a host that has accumulated multiple historical copies of the peer\n- if you reproduce the bug, also enumerate every on-disk copy of the peer before rolling back, so you can explain the divergence to upstream:\n  ```\n  find ~/.openclaw <global-node-modules> -maxdepth 6 -type d -name \"<peer-package-name>\"\n  ```\n\nInspection note:\n- `dist/index.js` is typically a single esbuild-bundled minified line; `grep` will appear to match the entire file. Use `grep -oE \"from'@[^']+'\" dist/index.js` (or similar token-level patterns) to enumerate actual import specifiers without dumping the bundle.\n\nWhy it matters:\n- this is not a missing-dep on the operator's side — it is a packaging defect\n- avoid the temptation to manually `npm install` the missing peer into the plugin dir, because the next `plugins update` will overwrite the directory and the fix will silently disappear\n- the resolver-luck variance is itself the bug: a plugin that \"works on my host\" but breaks for the next operator is the same defect, not a host configuration difference; do not dismiss the upstream report because your host happens to satisfy the import\n\n## 17. \"Duplicate plugin id detected\" warning text wraps in a self-referential way\n\nSymptom:\n- `plugins doctor` and `openclaw doctor` warn: `plugin <id>: duplicate plugin id detected; global plugin will be overridden by global plugin (/path/A)`\n- only one path is visible at a glance; the second path is wrapped to a later line and easily missed\n- on a narrow terminal the warning can look self-referential (\"global plugin will be overridden by global plugin (X)\") and is easy to dismiss as a UI bug\n\nReality:\n- the warning is real — there are two on-disk plugin manifests for the same id\n- the conflict is almost always between `~/.openclaw/extensions/<id>/` and `~/.openclaw/npm/node_modules/<scope>/<id>/` (or two copies under the same root)\n- the npm path generally wins, but the extensions path still triggers the warning every restart\n\nWhat to inspect:\n- `find ~/.openclaw -maxdepth 4 -type d \\( -name \"<id>\" -o -name \"@*<id>*\" \\)`\n- whether `plugins.load.paths` in `openclaw.json` is empty or pointing at an extra root\n- whether a previous `plugins update --all` left a `.backup-*` directory next to the new install (those are typically ignored, but a renamed-not-deleted manual copy can be picked up)\n\nRecovery:\n- pick the canonical install (npm-tracked is preferred for plugins managed via `openclaw plugins install`)\n- rename the unwanted copy to `<dir>.stale-<date>` (safer than `rm -rf` mid-runbook)\n- restart gateway and confirm `plugins doctor` reports zero errors and the warning is gone\n\nWhy it matters:\n- operators often dismiss this as cosmetic; it is not — the second path keeps generating doctor noise that masks new regressions\n- the warning text formatter wraps poorly; always re-read the full multi-line warning before deciding the conflict is benign\n\nTrue false-positive variant:\n- after archiving every redundant on-disk copy and confirming `find ~/.openclaw -maxdepth 6 -name 'openclaw.plugin.json' | xargs grep -l '\"<id>\"'` returns only the canonical install path, the warning can still persist\n- `openclaw plugins inspect <id>` then shows the warning's path field is **identical** to the loaded plugin's `Source` path — i.e., the warning is comparing the manifest against itself\n- this looks like an OpenClaw bug where the same manifest is being matched twice (once via the `installs.json` install record, once via filesystem scan) and both lookups are tagged `Origin: global`, generating a phantom duplicate\n- distinguishing genuine #17 (two real manifests on disk) from this false-positive: run `plugins inspect <id>` and compare the `Source` line to the path inside the WARN line. Same path = false positive. Different paths = genuine duplicate, keep hunting.\n- when it is the false positive, leave it alone; do not delete the canonical install in an attempt to silence it\n\n## 18. Bundled provider discovery mode change after host upgrade\n\nSymptom:\n- after upgrading the host package, `openclaw doctor` adds a new warning:\n  `plugins.allow is restrictive, but bundled provider discovery is still in legacy compatibility mode. Bundled provider plugins can ... set plugins.bundledDiscovery to \"allowlist\" after confirming omitted providers.`\n- previously absent config key is now expected: `plugins.bundledDiscovery`\n\nBackground:\n- `plugins.allow` historically gated only third-party plugins; bundled provider plugins (anthropic, openai, gemini, etc.) were always discoverable.\n- a host release introduced `plugins.bundledDiscovery` with two modes:\n  - `\"compat\"` — preserves legacy behavior; bundled providers stay discoverable regardless of `plugins.allow`\n  - `\"allowlist\"` — bundled providers must also appear in `plugins.allow`\n- Hosts upgraded from an older config shape can inherit the legacy behavior implicitly, and doctor may flag it until the key is set explicitly.\n\nWhat to do:\n- if `plugins.allow` is restrictive and you intentionally rely on bundled providers, set `plugins.bundledDiscovery: \"compat\"` to lock in current behavior — note that this **does not silence the doctor warning**, it only pins the mode against a future default flip (see refinement below)\n- if you want strict allowlisting end-to-end and want the warning gone, audit which bundled providers your agent fallback chains require, add them to `plugins.allow`, then set `plugins.bundledDiscovery: \"allowlist\"`\n\nRefinement:\n- Some releases auto-migrate `plugins.bundledDiscovery` to `\"compat\"` during the host upgrade, so the key may already be set even on hosts that never had it explicitly. Always re-read the live config before assuming the warning means the key is unset.\n- Even with `\"compat\"` explicitly set, doctor continues to print: `plugins.allow is restrictive, but bundled provider discovery is still in legacy compatibility mode ... set plugins.bundledDiscovery to \"allowlist\" after confirming omitted bundled providers are intentionally blocked`. The warning is the doctor's nudge to migrate forward, not a \"key missing\" warning. Two paths to silence:\n  1. Migrate to `\"allowlist\"` (recommended): enumerate the bundled providers your agents actually need by walking `c.agents.defaults.model.{primary,fallbacks}` and any agent-level overrides; the model strings are typically `provider/model` shaped (e.g., `anthropic/claude-opus-4-7`, `openai-codex/gpt-5.5`). Map each `provider/` prefix to its bundled plugin id (`openai-codex` → `openai`, since the openai plugin owns both `openai` and `openai-codex` provider ids). Add the corresponding plugin ids to `plugins.allow`, set `plugins.bundledDiscovery: \"allowlist\"`, restart, and re-run doctor.\n  2. Accept the persistent warning and rely on `\"compat\"` — fine for now, but re-audit after every minor bump in case a future version changes the warning into an error.\n- When migrating to `\"allowlist\"`, also confirm the corresponding API-key env vars are present in the service env (e.g., `ANTHROPIC_API_KEY` for the `anthropic` plugin); plugins added to `plugins.allow` without credentials will load but fail at first use, which is harder to diagnose than a discovery warning.\n\nWhy it matters:\n- this is a config-shape change introduced silently by a minor version bump; treat it as a host-upgrade follow-up, not a one-off doctor warning\n- ignoring it doesn't break anything today, but a future minor that flips the default to `\"allowlist\"` will instantly regress provider discovery on every host that hasn't pinned the mode\n\n## 19. CLI uninstall confirmation prompt blocks non-interactive runbooks\n\nSymptom:\n- `openclaw plugins uninstall <id>` prints `Uninstall plugin \"<id>\"? [y/N]` and then exits without doing anything in a non-interactive shell (e.g., a single ssh command with no stdin).\n- stderr may include an unrelated `Detected unsettled top-level await` warning that obscures the real reason (no input piped to the prompt).\n\nWhat to do:\n- always pass `--force` for non-interactive uninstalls\n- `--yes` and `-y` may not be accepted; use `--force` when the command help confirms it skips the prompt\n- if you also want a preview, run `--dry-run` first\n\nWhy it matters:\n- a runbook that pipes a single `ssh` command without a TTY will silently no-op the uninstall, then proceed to \"verify\" steps that report the plugin still present and confuse the operator into deeper changes\n\n## 20. Multi-step SSH update command disconnects mid-run while the box keeps working\n\nSymptom:\n- operator runs a single multi-step `ssh user@host '... stop ... npm install ... reinstall plugins ... start ...'` command\n- the SSH session appears hung or returns no output to the operator's terminal\n- reconnecting with a fresh ssh shows the box has actually completed most or all of the work — versions bumped, gateway running, plugins on disk\n\nWhat's happening:\n- when one of the inner steps restarts launchd or replaces the wrapper script the gateway plist sources, the parent shell association can break and the local ssh client stops receiving stdout, even though the remote `zsh -c '...'` keeps running detached and finishes the script.\n- the remote orphan can persist as a `zsh -c` process for minutes after the parent ssh exits.\n\nWhat to inspect:\n- on the remote host: `pgrep -fl \"openclaw/dist/index.js gateway\"` (current gateway PID and command line)\n- `pgrep -fl \"zsh -c\"` for orphan wrapper processes from the disconnected session\n- on-disk plugin versions vs `npm view @openclaw/<id> version`\n- `~/.openclaw/logs/gateway.log` for the latest `http server listening` line (confirms a fresh restart actually happened)\n\nRecovery:\n- kill orphan wrapper zsh processes (`kill <pid>`)\n- re-run the verification suite (`openclaw --version`, `openclaw plugins doctor`, `openclaw channels status`, `openclaw tasks audit`) from a fresh ssh session\n- do NOT re-run the update script blindly; it may have completed successfully and a second run can re-pin install records to versions that were just bumped\n\nPractical advice:\n- prefer breaking the update into separate ssh invocations per phase: stop → host update → plugin reinstalls → start → verify. A disconnect then loses only the current phase, not the whole sequence.\n- where a single transactional run is unavoidable, redirect the script's output to a remote file (`> /tmp/openclaw-update.log 2>&1`) and tail it from a second ssh session, so the parent disconnect does not lose the audit trail.\n\nWhy it matters:\n- treating an apparent hang as failure and rerunning can corrupt install records mid-flight\n- the runbook's \"verify\" step must rely on freshly inspected box state, not on the success path of the update command's stdout\n\n## 21. Version drift between operator sessions on hosts with autopilot agents\n\nSymptom:\n- operator returns to a host they audited recently and finds a different `openclaw --version` than what they last left it on\n- no explicit operator-initiated update happened in the interim\n- `update.auto.enabled` may be `false` in `openclaw.json`, but the host still moved versions\n\nBackground:\n- some hosts run autopilot or scheduled cron agents (e.g., `gbrain`, `com.gbrain.autopilot.plist`, scheduled openclaw cron jobs) that may bump `openclaw` or its plugins out of band, ignoring the host-level update channel/auto flag\n- the `meta.lastTouchedVersion` field in `openclaw.json` only reflects the last writer, not the last installer\n\nWhat to do:\n- always re-snapshot the live state at session start, even within hours of the previous session:\n  - `openclaw --version`\n  - per-plugin disk versions: `for d in ~/.openclaw/npm/node_modules/@*/*/; do node -e 'process.stdout.write(JSON.parse(require(\"fs\").readFileSync(process.argv[1])).name+\" \"+JSON.parse(require(\"fs\").readFileSync(process.argv[1])).version+\"\\n\")' \"$d/package.json\"; done`\n  - any service-env or config edits applied by previous workarounds\n- do not rely on prior-session memory for current state; treat every session as a fresh audit\n\nWhy it matters:\n- a stale mental model leads to the wrong fix path — e.g., applying an env-var workaround when a literal-inline workaround is already in place, or \"rolling back\" an update the operator never made\n- two parallel operator sessions (or an operator + a long-running autopilot) can converge on contradictory workarounds if neither re-snapshots first\n\n## 22. Cohort version snapshot before host update\n\nPractice:\n- before stopping the gateway, capture every plugin's installed version with a single command:\n  ```\n  for d in ~/.openclaw/npm/node_modules/@*/*/; do\n    node -e 'const p=JSON.parse(require(\"fs\").readFileSync(process.argv[1])); process.stdout.write(p.name+\"@\"+p.version+\"\\n\")' \"$d/package.json\"\n  done | sort > /tmp/openclaw-pre-upgrade-plugins.txt\n  ```\n- after the upgrade, re-run the same command into `/tmp/openclaw-post-upgrade-plugins.txt` and `diff` them.\n- a clean cohort upgrade should show every plugin version moving in the diff; any plugin that did NOT move is a candidate for shadow drift (Pattern #3) once the host moves further.\n\nWhy it matters:\n- a `plugins install <pkg>@latest --pin --force` no-op (e.g., from a network or registry hiccup, or because npm latest temporarily lagged ClawHub) is invisible until you hit a sub-feature that depends on the new version.\n- without the snapshot/diff, the operator cannot prove the cohort actually moved — only that the host did.\n- the snapshot also documents what to roll back to if the new cohort surfaces a packaging defect (Pattern #16).\n\n## 23. Service-env writer corrupts string secrets with literal double-quote wrapping\n\nSymptom:\n- a previously working channel returns auth failure from the upstream API immediately after a host upgrade, even though `channels status` reports `token:env` and the channel was healthy before the upgrade\n- `secrets audit` reports `unresolved=0` and the underlying value in `secrets.json` is unchanged\n- the channel reconnects fine if you manually re-paste the token into the env file\n\nRoot cause:\n- the service-env writer JSON-encodes string values from `secrets.json` (wrapping them in `\"`) and **then** shell-single-quotes the result for the env file\n- the resulting line looks like `export CHANNEL_TOKEN='\"<token>\"'` — the outer single quotes are correct shell quoting, but the inner literal `\"` characters become part of the value when the env file is sourced\n- the upstream API receives a token with stray leading and trailing `\"` chars and rejects it\n- the bug only surfaces the next time the env file is regenerated (a host upgrade, certain `doctor --fix` runs, plugin reinstalls), so it presents as \"the upgrade broke the channel\" rather than a config drift\n\nWhat to inspect:\n- the raw bytes of the env line, not just the masked output:\n  ```\n  node -e 'const fs=require(\"fs\"); const p=process.env.HOME+\"/.openclaw/service-env/<service-env-file>\"; const l=fs.readFileSync(p,\"utf8\").split(\"\\n\").find(l=>l.startsWith(\"export <TOKEN_ENV_NAME>=\")); console.log(JSON.stringify(l))'\n  ```\n- a clean line has a single shell-quoted token value with no inner literal double quotes\n- a corrupted line has literal `\"` characters just inside the shell quotes\n- check every `*_TOKEN` / `*_API_KEY` line in the env file the same way; the same writer emits all of them\n\nRecovery:\n- back up the env file: `cp <env> <env>.bak-token-fix-<date>`\n- rewrite the affected lines using the value from `secrets.json` (which is the canonical clean value), shell-single-quoted with no inner JSON wrapping; only safe if the secret itself contains no single quotes (almost always the case for API tokens)\n- restart the gateway through the host service manager\n- re-run `openclaw channels status --deep` and confirm the channel reconnects\n\nWhy it matters:\n- this is a packaging defect in the env-file writer, not operator drift; the local fix is fragile because the next regeneration will re-corrupt the file\n- share upstream or with support: exact line bytes, the source `secrets.json` value type (string), and the affected host version\n- until upstream ships a fix, treat any operation that may rewrite `service-env/*.env` (host updates, plugin updates, `doctor --fix` involving secrets) as a channel-auth outage risk and re-verify channel auth immediately after\n\nWorkflow addendum:\n- when post-update channel health shows auth failure, **inspect the env file's raw bytes for quote corruption before assuming the upstream credential was rotated**. The wrong diagnosis path leads to credential rotation and operator confusion; the right diagnosis takes 30 seconds.\n\n## 24. Non-interactive SSH hides the OpenClaw binary\n\nSymptom:\n- `ssh host 'openclaw --version'` returns `command not found`\n- the same host has a working managed service and `openclaw status` works in an interactive shell\n- service-manager status may also look wrong if the operator guesses an old service label\n\nWhat to inspect:\n- `echo \"$PATH\"` inside the non-interactive SSH command\n- common binary locations for the host's package manager and `~/.local/bin/openclaw`\n- the actual service label or name\n- the gateway command and port inside the service definition or `openclaw status --deep`\n\nObserved example:\n- non-interactive SSH inherited only `/usr/bin:/bin:/usr/sbin:/sbin`\n- OpenClaw was installed under a package-manager prefix\n- the gateway service label was not the older guessed label\n- the live gateway port differed from an old hard-coded health port, so probing the old port falsely reported an outage\n\nWhy it matters:\n- a stripped SSH `PATH` can look like a missing installation\n- an old label or hard-coded port can make a healthy gateway look stopped\n- always establish the command path, label, and port before running update or repair commands\n\n## 25. Update stop phase may need service-manager fallback even after clean gateway SIGTERM\n\nSymptom:\n- `openclaw update --channel <channel>` prints that the normal service stop did not fully stop the service\n- updater reports it used a stronger stop/unload fallback and left the service unloaded before continuing\n- gateway logs may show a clean `SIGTERM` shutdown, followed by a short-lived restart that is immediately terminated before the package swap completes\n\nWhat to inspect:\n- update command stdout/stderr\n- the host service-manager status command before and after the update\n- recent gateway logs around the stop/restart window\n- final `openclaw status --deep`, `/health`, and managed-service PID\n\nWhy it matters:\n- this is a lifecycle hiccup, not necessarily an update failure\n- do not rerun the update just because the normal stop needed fallback; first verify the final service is loaded/running and the gateway responds on its configured port\n- include the stop/fallback lines in handoff notes, because they show service-manager semantics the updater had to recover from\n\n## 26. Selected update channel has no matching external plugin release\n\nSymptom:\n- host updates successfully to a selected channel such as beta\n- an external plugin cannot be found on npm for `<package>@<channel>`\n- updater falls back to another tag such as `@latest`\n- post-update `plugins doctor` can still be clean, but the host is now running a mixed channel cohort\n\nObserved example:\n- host updated to a selected channel build\n- one third-party plugin had no `@beta` release and fell back to `@latest`\n- a globally installed official channel plugin did update to the matching beta version\n- plugin peer dependency links were repaired during the update\n\nWhat to inspect:\n- update output for `Package not found on npm` and `falling back` lines\n- `openclaw plugins list --json` for each enabled plugin's `origin`, `source`, and `version`\n- `~/.openclaw/plugins/installs.json` to see whether the recorded spec now points at the intended version/tag\n\nWhy it matters:\n- \"host on beta\" does not imply every external plugin is on beta\n- a clean `plugins doctor` proves loadability, not cohort consistency\n- handoff notes should separate OpenClaw-bundled plugin behavior from external plugin publishing gaps\n\n## 27. Transient post-restart scope and pricing warnings can coexist with healthy channels\n\nSymptom:\n- immediately after restart, gateway logs show websocket responses like `missing scope: operator.read`\n- `status --deep` reports a noncritical external catalog or pricing fetch degraded\n- channels remain connected and `/health` reports live\n\nWhat to inspect:\n- whether the scope errors are confined to the seconds after restart\n- whether later `channels status --deep` is connected\n- whether `/health` returns `{\"ok\":true,\"status\":\"live\"}`\n- whether the warning is tied to a third-party catalog/pricing fetch rather than local gateway startup\n\nWhy it matters:\n- these warnings are useful to report, but they should not be conflated with a failed package update\n- stale Control UI/websocket clients can race the new gateway during restart\n- external catalog/pricing fetch failures may degrade status without affecting channel delivery or plugin loading\n\n## 28. Codex OAuth model migration succeeds in config but fails at runtime\n\nSymptom:\n- an OAuth-only OpenAI/Codex host has working `openai-codex/gpt-*` refs before upgrade\n- `doctor` or `update` rewrites agent and cron refs to `openai/gpt-*`\n- session/status tables may show the display model as `gpt-5.5` and the runtime as `OpenAI Codex`\n- a direct agent run returns `status: ok`, but metadata shows the OpenAI/Codex primary route failed and a fallback provider won\n\nWhat to inspect:\n- `agents.defaults.model.primary`\n- `agents.defaults.models` and every `agents.list[*].models` entry for `agentRuntime.id`\n- cron payload models in `~/.openclaw/cron/jobs.json`\n- direct smoke test metadata: provider, model, runtime/harness, and `fallbackAttempts`\n- recent gateway logs around `agent model:` and provider fallback decisions\n\nTypical failures:\n- direct `openai/gpt-*` route fails with direct OpenAI API-key auth on an OAuth-only host\n- migrated `openai/gpt-*` route selects a new `codex` runtime but fails before model execution\n- restored `openai-codex/gpt-*` route reaches the old provider but fails on request-shaping or tool-schema validation\n\nWhy it matters:\n- `status: ok` is not proof that the intended OpenAI/Codex route works; fallbacks can mask the primary-route regression\n- cron jobs can be silently migrated independently of agent defaults and then fail later when they fire\n- do not claim a model-routing fix is verified until a fresh direct run completes on the intended provider/runtime with no unexpected fallback\n\nVerification command shape:\n```\nopenclaw agent --agent main --session-id <fresh-id> --message \"Reply exactly: SMOKE_OK\" --timeout 120 --json\n```\n\nThe result is healthy only if:\n- the payload text is correct\n- the final provider/model match the intended primary route\n- runtime/harness matches the intended path\n- `fallbackAttempts` is empty or contains only known benign retries\n\n## 29. `@openclaw/codex` package import resolves `root-alias.cjs` as a directory\n\nSymptom:\n- update installs or enables `@openclaw/codex`\n- model entries route `openai/gpt-*` through `agentRuntime.id: \"codex\"`\n- direct agent smoke falls back with:\n  `Cannot find module '<global-openclaw>/dist/plugin-sdk/root-alias.cjs/codex-native-task-runtime'`\n- on disk, `root-alias.cjs` is a file and `codex-native-task-runtime.js` is its sibling\n\nWhat to inspect:\n- `~/.openclaw/npm/node_modules/@openclaw/codex/package.json`\n- `~/.openclaw/npm/node_modules/@openclaw/codex/dist/run-attempt-*.js`\n- `<global-openclaw>/dist/plugin-sdk/root-alias.cjs`\n- `<global-openclaw>/dist/plugin-sdk/codex-native-task-runtime.js`\n- whether `plugins.entries.codex` exists or whether `codex` is activated as a special runtime plugin outside normal plugin entries\n- both `openclaw plugins inspect codex` and `openclaw plugins list --json`; these can disagree, with `inspect` reporting `Status: loaded` while the JSON list shows `\"enabled\": false` / `\"status\": \"disabled\"` for the same package\n\nUseful snapshot:\n```\nnode -e 'const fs=require(\"fs\"); const p=process.env.HOME+\"/.openclaw/npm/node_modules/@openclaw/codex/package.json\"; console.log(JSON.stringify(JSON.parse(fs.readFileSync(p,\"utf8\")), null, 2))'\nfind <global-openclaw>/dist/plugin-sdk -maxdepth 2 -type f | grep -E \"root-alias|codex-native\"\n```\n\nWhy it matters:\n- this is likely an OpenClaw package/import-path bug, not local credential drift\n- reverting only the model id may hide the package bug by moving traffic back to an older provider path\n- handoff notes should include the exact package version and sanitized file layout\n- `plugins doctor` may still say \"No plugin issues detected\"; do not treat plugin doctor alone as proof the `codex` agent runtime can execute\n\nObserved in 2026.5.12-beta.2:\n- update auto-installed missing configured plugin `codex` from `@openclaw/codex@beta`\n- `plugins inspect codex` reported package version `2026.5.12-beta.2` and `Status: loaded`\n- raw plugin JSON showed the same plugin as disabled\n- direct smoke with `openclaw agent --model openai/gpt-5.5 --json` failed immediately with the `root-alias.cjs/codex-native-task-runtime` module path error\n- the expected file existed as `<global-openclaw>/dist/plugin-sdk/codex-native-task-runtime.js`, adjacent to `<global-openclaw>/dist/plugin-sdk/root-alias.cjs`\n\n## 30. OpenAI-compatible tool schema rejects arrays missing `items`\n\nSymptom:\n- the OpenAI/Codex route reaches request validation, then fails with a 400 schema error\n- fallback succeeds on a provider with looser or different tool-schema validation\n- error text resembles:\n  `Invalid schema for function '<tool>': In context=('properties', '<array_field>'), array schema missing items.`\n\nWhat to inspect:\n- the failing tool name and plugin owner\n- the generated tool schema passed to OpenAI/Codex\n- plugin schema source if the tool belongs to a plugin\n- request-shaping code that converts tool definitions between provider schema formats\n\nWhy it matters:\n- this blocks the primary route even when credentials and runtime selection are correct\n- fallback success can make the agent appear healthy while all GPT/OpenAI primary runs are actually rejected before completion\n- the local workaround is usually to remove/fix the bad tool from the agent toolset or fall back to another provider, but the upstream fix should validate/sanitize schemas before dispatch\n\nHandoff guidance:\n- sanitize the tool name if it reveals private app naming, but keep the field path and JSON Schema error text\n- state whether the same agent run succeeded only through fallback\n- include the OpenClaw version and provider/model that rejected the schema\n\n## 31. Updater restart step runs under the previous CLI after package swap\n\nSymptom:\n- `openclaw update --channel beta` reports a successful package swap from version X to version Y\n- during restart it warns that config was written by version Y, but the current command is running version X\n- updater then says the gateway already reports version Y and skips a redundant restart\n\nWhat to inspect:\n- `openclaw --version` from a fresh shell\n- `which openclaw`\n- `openclaw gateway status --deep` or `openclaw status --deep`\n- managed-service command path and live gateway version\n\nWhy it matters:\n- this may be harmless if the gateway is actually running the new version, but it is confusing in beta validation\n- it can mask real CLI/global-install/service path mismatches\n- capture the warning for the next operator or support contact, but verify service reality before rerunning the update\n\n## 32. `cron run --expect-final` proves enqueue but not final completion\n\nSymptom:\n- `openclaw cron run <id> --expect-final --timeout <ms>` returns quickly with an enqueue-style JSON payload\n- no final agent result is included even though help says the flag waits for the final response\n- `openclaw cron runs` may require `--id`, which makes broad post-update polling less discoverable\n\nWhat to inspect:\n- exact CLI version\n- `openclaw cron run --help`\n- `openclaw cron runs --help`\n- run history for the specific job id\n- job status after a delay\n\nWhy it matters:\n- cron verification after an update can be falsely marked complete when only enqueue was proven\n- for handoff notes, distinguish \"manual run enqueued\" from \"manual run completed successfully\"\n- pair manual cron runs with a delayed status/history poll before declaring cron healthy\n\n## 33. Discord offline because the managed gateway service is installed but unloaded\n\nSymptom:\n- Discord shows the bot offline, and local channel status can only report config because the gateway is unreachable\n- `openclaw doctor` reports `Gateway not running` and a managed service such as a LaunchAgent installed but not loaded\n- `openclaw update status` may still work from SSH because it does not require the live gateway\n\nObserved recovery:\n- From an outside SSH shell, export the real package-manager path first\n- Run the requested stable update explicitly, for example `openclaw update --channel stable --yes --timeout 1800`\n- Re-run `openclaw status --deep` and `openclaw channels status --deep`\n- A healthy recovery shows the service loaded/running, gateway reachable, the selected channel persisted, and Discord `running, connected`\n\nWhat to inspect:\n- `command -v openclaw` and `openclaw --version`\n- `openclaw update status`\n- `openclaw doctor --non-interactive --no-workspace-suggestions`\n- `openclaw status --deep`\n- `openclaw channels status --deep`\n\nWhy it matters:\n- a channel outage can be a service-manager state problem rather than a Discord plugin problem\n- updating from outside the OpenClaw-managed agent path can recover an unloaded gateway and move the host back to the intended stable channel in one pass\n- record pre-update warnings separately from the package update result, especially plaintext-secret warnings, stale session metadata, and old task-ledger warnings\n\nRemote access guardrail:\n- If another host cannot be reached over SSH with a short timeout, including from an available jump host, classify it as a transport/access blocker\n- Do not file an OpenClaw issue for an unreachable host unless you have logs or command output proving OpenClaw failed on that host\n\n## 34. In-gateway self-update can leave the package changed but the service unloaded\n\nSymptom:\n- the user asks OpenClaw itself to update the running OpenClaw host\n- the agent conversation reports an update attempt or partial success\n- later SSH shows one of:\n  - CLI package reached the requested stable/tag, but the managed LaunchAgent/service is installed and not loaded\n  - host remained on the previous beta/stable even though the agent said it attempted the update\n  - channels are offline because the gateway is not actually running\n\nWhat to inspect:\n- `openclaw --version`\n- `openclaw update status`\n- `openclaw gateway status --deep`\n- `openclaw status --deep`\n- `openclaw channels status --deep`\n- service-manager state from the real service label, not a guessed label\n- recent gateway logs around the update/restart window\n\nRecovery:\n- switch to an outside shell/SSH session\n- run the explicit target update from there, for example:\n  ```\n  openclaw update --channel stable --yes --timeout 1800\n  ```\n  or, when the exact tag matters:\n  ```\n  openclaw update --tag <version> --yes --timeout 1800\n  ```\n- if the package is already at the target version but the service is unloaded, try:\n  ```\n  openclaw gateway restart\n  ```\n- then verify service loaded/running, `/health`, channels, plugin doctor, and tasks audit\n\nWhy it matters:\n- this is different from a failed npm package install; the dangerous part is that the process supervising the agent is also the process being stopped/replaced\n- a successful package swap is not enough if the service manager never reloads the gateway\n- do not trust the agent's final chat response as proof of update success; trust the host state inspected from outside the managed gateway\n\n## 35. Stable package installed while update channel still points at beta\n\nSymptom:\n- operator explicitly updates to the latest stable\n- `openclaw --version` and gateway version show the stable build\n- `openclaw update status` still offers a newer beta build or reports beta channel metadata\n- the host may have been on a beta channel in previous sessions\n\nWhat to inspect:\n- `openclaw --version`\n- `openclaw update status`\n- `openclaw status --deep`\n- `openclaw.json` update/channel fields\n- whether the update command used `--channel stable`, `--tag <stable-version>`, or only a bare `update`\n\nRecovery:\n- if the user's intent is stable, explicitly set or preserve the stable channel with the update command rather than assuming a stable tag rewrites every channel preference\n- after the update, record both facts in the audit:\n  - installed/runtime version\n  - configured update channel and next offered version\n- if a future run must avoid accidental beta adoption, correct the config/channel state before running another automatic update\n\nWhy it matters:\n- \"latest stable installed\" and \"host will keep following stable\" are separate claims\n- leaving beta channel metadata behind can make the next operator accidentally move the machine back onto beta\n- this is especially easy to miss when the gateway itself is healthy and channels are connected\n\n## 36. Deprecated plugin runtime API warning is usually an attribution issue, not a blocker\n\nSymptom:\n- `openclaw plugins doctor` or `openclaw doctor` is otherwise clean but prints:\n  `plugin runtime config.loadConfig() is deprecated (runtime-config-load-write); use config.current().`\n- the gateway is healthy and channels are connected\n- the warning may or may not identify which plugin emitted it, depending on OpenClaw version\n\nWhat to inspect:\n- `openclaw plugins doctor`\n- `openclaw plugins list --json`\n- `openclaw plugins inspect <id>` for third-party plugins loaded from npm\n- recent gateway logs for the same warning with more context\n\nHow to treat it:\n- do not block the update on this warning if all health checks pass\n- include it in the audit report as technical debt\n- if the warning is unattributed, note that the diagnostic itself is incomplete; later versions may improve attribution by naming the plugin/source path\n\nWhy it matters:\n- repeated nonblocking warnings can hide fresh failures in long update runs\n- it is useful upstream feedback, but it should not be conflated with a broken install, disconnected channel, or failed model route\n\n## 37. Supply-chain advisory audit should combine exact version matching with IoC checks\n\nSymptom:\n- after update/plugin churn, the user asks whether npm packages are compromised\n- a public advisory lists hundreds of affected packages and specific indicators of compromise\n- top-level `npm ls` looks clean but does not cover nested plugin installs or persistence artifacts\n\nWhat to inspect:\n- the advisory's exact package/version table\n- global npm roots such as `/opt/homebrew/lib/node_modules` or `/usr/local/lib/node_modules`\n- OpenClaw plugin roots such as `~/.openclaw/npm/node_modules`\n- workspace-level `node_modules` if the host uses one\n- package\n\nFile v1.0.6:skill-card.md\n\n## Description:\n\nUse when updating OpenClaw or debugging an OpenClaw instance after an update. This skill acts as a structured update runbook with emphasis on gateway startup, service-manager state, plugin registry and install drift, bundled-vs-npm/clawhub plugin confusion, stale config carried across upgrades, channel health, task ledger corruption, and logs that explain why the updated system is slow, disconnected, or half-broken.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[bkf-gitty](https://clawhub.ai/user/bkf-gitty)\n\n### License/Terms of Use:\n\nMIT\n\n## Use Case:\n\nOperators and engineers use this skill to plan OpenClaw updates, diagnose post-update regressions, verify service and plugin state, and choose the smallest repair that returns a host to a healthy state.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Troubleshooting guidance can expose live channel tokens in terminal output, logs, or agent transcripts.\n\nMitigation: Do not run token-inspection commands that print raw values. If a token appears in a transcript, support ticket, log, or backup, rotate it and remove plaintext fallbacks after recovery.\n\nRisk: Update, restart, or configuration-edit steps can affect a live OpenClaw host.\n\nMitigation: Use the skill only for explicit OpenClaw maintenance tasks, require confirmation before updates, restarts, or config edits, and verify host state before and after changes.\n\n## Reference(s):\n\n- [ClawHub Skill Page](https://clawhub.ai/bkf-gitty/skills/claw-update-runbook)\n- [Failure Patterns](references/failure-patterns.md)\n- [README](README.md)\n\n## Skill Output:\n\n**Output Type(s):** [Guidance, Shell commands, Configuration]\n\n**Output Format:** [Markdown with inline shell commands and checklists]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Includes diagnostic sequences, verification criteria, and handoff-note guidance; does not execute commands itself.]\n\n## Skill Version(s):\n\n1.0.6 (source: frontmatter and server release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nFile v1.0.6:agents/openai.yaml\n\ninterface:\n  display_name: \"OpenClaw Update Runbook\"\n  short_description: \"Runbook for OpenClaw updates and repairs\"\n  default_prompt: \"Use $openclaw-update-runbook to update OpenClaw safely, inspect post-update regressions, and verify the system is healthy.\"\n\npolicy:\n  allow_implicit_invocation: true\n\nFile v1.0.6:LICENSE\n\nMIT License\n\nCopyright (c) 2026\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\nArchive v1.0.2: 12 files, 40272 bytes\n\nFiles: agents/openai.yaml (303b), LICENSE (1056b), openclaw-beta4-audit-2026-05-13.md (6682b), openclaw-beta5-audit-2026-05-13.md (7361b), openclaw-beta8-audit-2026-05-14.md (9144b), openclaw-v2026.5.12-self-update-audit-2026-05-14.md (4681b), README.md (2932b), references/failure-patterns.md (45143b), sentinel-v2026.5.16-beta.5-audit-2026-05-17.md (5884b), skill-card.md (2918b), SKILL.md (11758b), _meta.json (138b)\n\nFile v1.0.2:SKILL.md\n\n---\nname: openclaw-update-runbook\ndescription: Use when updating OpenClaw or debugging an OpenClaw instance after an update. This skill acts as a structured update runbook with emphasis on gateway startup, service-manager state, plugin registry and install drift, bundled-vs-npm/clawhub plugin confusion, stale config carried across upgrades, channel health, task ledger corruption, and logs that explain why the updated system is slow, disconnected, or half-broken.\nversion: 1.0.2\nmetadata:\n  openclaw:\n    emoji: \"🦞\"\n---\n\n# OpenClaw Update Runbook\n\nUse this skill when an OpenClaw host was just updated, is about to be updated, or is behaving strangely after an update. It is a generic operator runbook, not a release-specific checklist.\n\nThis skill is meant to be installed as a folder, not copied as a single file. It expects `references/failure-patterns.md` to exist locally beside `SKILL.md` inside the same skill bundle.\n\nThe goal is not only to get it running, but to prove which layer is broken:\n\n- service lifecycle and service-manager state\n- host package version\n- plugin/package compatibility\n- config drift\n- model/provider runtime routing\n- channel health\n- task ledger health\n- runtime performance\n- command-path and update-channel assumptions\n\n## Quick workflow\n\n1. Establish the real starting state.\n   For remote multi-host updates, first prove SSH reachability to each host\n   with a short timeout. If a host cannot be reached directly or through an\n   available jump host, record it as a transport/access blocker instead of an\n   OpenClaw update failure, because no OpenClaw command has executed on that\n   host yet.\n\n   If you are connected over non-interactive SSH, do not assume the\n   login-shell `PATH` is available. First locate the binary with common install\n   paths such as a package-manager prefix and `~/.local/bin/openclaw`, then\n   export the correct `PATH` for the audit session.\n\n   Check:\n   - `openclaw --version`\n   - `openclaw status --deep`\n   - `openclaw doctor --non-interactive --no-workspace-suggestions`\n   - `openclaw channels status --deep`\n   - `openclaw tasks audit`\n   - current model routing: agent defaults, agent-level model maps, fallback chains, and cron payload models\n   - recent successful sessions for the primary model and runtime, not just the display model name\n\n2. Verify the gateway is actually managed correctly.\n   Look at service-manager state, running PID, and `/health`.\n   Derive the service label/name and gateway port from `openclaw status --deep`\n   and/or the service definition instead of guessing them.\n   Do not trust only one of:\n   - the host's service manager\n   - process list\n   - health endpoint\n\n   It is common to have:\n   - a service definition present but not loaded\n   - a detached gateway process still serving traffic\n   - the service manager and the live process disagreeing\n\n3. Separate bundled plugins from globally installed plugins.\n   First inspect plugin health:\n   - `openclaw plugins doctor`\n   - `openclaw plugins list --json`\n   - `openclaw plugins inspect <id>`\n\n   Important rule:\n   - If a capability is supposed to be bundled, verify whether a stale global npm install is shadowing it.\n   - If a capability is not bundled, check npm and ClawHub before assuming config is wrong.\n   - For special runtime plugins such as `codex`, compare `plugins inspect <id>`\n     with `plugins list --json`; inspect can report a runtime as loaded while\n     raw plugin metadata still says disabled.\n\n4. Check for config carried across the upgrade that no longer validates.\n   Pay attention to:\n   - `tools.web.search.provider`\n   - `plugins.allow`\n   - `plugins.entries.*`\n   - model aliases and fallback chains\n   - runtime mappings for `openai/*`, `openai-codex/*`, `codex`, and `pi`\n   - cron job payload model refs, which can be normalized separately from agent defaults\n   - update channel metadata\n\n   If doctor says a provider or plugin is unknown, inspect the actual config file and do not assume `doctor --fix` fully cleaned it.\n\n5. Compare plugin install records to what exists on disk.\n   Inspect:\n   - `~/.openclaw/plugins/installs.json`\n   - `~/.openclaw/npm/node_modules/@openclaw/...`\n   - `~/.openclaw/extensions/...`\n\n   Look for:\n   - recorded install paths that do not exist\n   - recorded versions drifting from installed versions\n   - package specs rewritten or preserved during `openclaw update --channel ...`\n   - external plugins that lack a release for the selected channel and were\n     installed from a fallback tag such as `@latest`\n   - source-only TypeScript plugin packages with no compiled `dist/`\n   - plugin runtime deps removed from third-party plugin directories\n\n6. Inspect recent gateway logs before changing too much.\n   Read:\n   - `~/.openclaw/logs/gateway.log`\n   - `~/.openclaw/logs/gateway.err.log`\n   - `/tmp/openclaw/openclaw-YYYY-MM-DD.log`\n\n   Prioritize recent startup lines and warnings involving:\n   - plugin load failures\n   - config validation\n   - provider fallback attempts and primary-route auth or module failures\n   - update lifecycle messages such as service stop fallbacks,\n     config overwrites/backups, and service reload timing\n   - channel auth (if a channel returns 401/auth-failure post-update, inspect `~/.openclaw/service-env/*.env` for token-line quote corruption — see Pattern #23 — before assuming the upstream credential was rotated)\n   - context-engine fallback\n   - active-memory timeouts\n   - event loop degradation\n   - task restart blocking\n   - transient post-restart UI/websocket scope errors that clear after the\n     gateway is ready\n\n7. Audit runtime/task health after the upgrade.\n   Check for:\n   - stale running tasks\n   - lost tasks\n   - delivery failures\n   - timestamp inconsistencies\n\n   A successful package update can still leave the system unhealthy if stale tasks block restarts or keep the audit red.\n\n8. Prove the primary model route, not just overall agent success.\n   Run a narrow direct agent smoke test with a fresh session id and inspect the returned metadata:\n   - final provider and model\n   - runtime or harness id\n   - `fallbackAttempts`\n   - provider auth errors\n   - module load errors\n   - schema validation errors\n\n   Treat `status: ok` as insufficient if the primary model failed and a fallback provider completed the run.\n   Treat a clean `plugins doctor` as insufficient for runtime plugins until a\n   fresh direct agent run proves that the intended harness can load and execute.\n\n9. Test at least one representative cron path.\n   Check:\n   - cron payload model counts\n   - named or high-value cron job status\n   - manual `cron run` behavior\n   - whether `--expect-final` actually waits for final completion on the current build\n\n   If cron verification only proves enqueue, state that clearly in the handoff notes.\n\n10. Re-run the narrowest fix, then verify again.\n   Common fix sequence:\n   - stop gateway cleanly\n   - update host package\n   - refresh plugin registry if needed\n   - repair or update broken plugin installs\n   - restart gateway\n   - re-run `doctor`, `plugins doctor`, `status --deep`, `channels status --deep`, and `tasks audit`\n\n## Where to look first\n\nUse this order when diagnosing post-update failures:\n\n- Service state: service manager, PID, `/health`\n- Host version: `openclaw --version`\n- Plugin mismatch: `openclaw plugins doctor`\n- Config drift: `openclaw doctor`\n- Channel reality: `openclaw channels status --deep`\n- Task ledger: `openclaw tasks audit`\n- Model/runtime route reality: direct smoke metadata and fallback attempts\n- Runtime symptoms: gateway logs\n\n## When to open references\n\nStart with this file first.\n\nOpen [references/failure-patterns.md](references/failure-patterns.md) when:\n\n- `doctor` or `plugins doctor` points to a known-looking regression\n- `channels status` or logs disagree with the apparent service health\n- plugin installs, install records, or config state do not match what is on disk\n- the update completed, but the host is still slow, disconnected, noisy, or half-broken\n\nUse the reference file for symptom matching and concrete examples after the main workflow has narrowed the likely failure area.\n\n## Bundled vs external plugin rule\n\nDo not assume a broken plugin means \"plugin missing.\"\n\nThere are three common cases:\n\n- Bundled plugin exists in the host package, but stale config still points at an old provider/plugin id.\n- Bundled plugin exists, but a globally installed npm plugin shadows it and is on the wrong version.\n- Plugin is not bundled, so the fix is to inspect npm or ClawHub and reconcile install records.\n\nA channel plugin is a good example of the second case: a host can upgrade correctly while still loading an older globally installed plugin package.\n\nIf the feature is not bundled, check npm and ClawHub before rewriting config.\n\n## Fixing mindset\n\nPrefer the smallest fix that makes state consistent again:\n\n- refresh registry before reinstalling everything\n- update one stale plugin before removing all plugins\n- inspect the actual config file when helper commands appear to succeed but warnings remain\n- verify whether a third-party plugin needs local runtime deps before deleting plugin-side `node_modules`\n\nDo not stop at \"service is up.\" A good finish means:\n\n- the right version is installed\n- the gateway is managed correctly\n- channels are connected\n- the intended primary model route succeeds without an unexpected fallback\n- cron payload models and representative cron jobs are healthy\n- plugin doctor is clean or explained\n- task audit is not carrying a fresh blocking error\n\n## Handoff notes\n\nIf the upgrade exposed an OpenClaw bug rather than local drift, collect enough information for the next operator or project/support contact. Do not assume the user has any particular external account or wants a public report created.\n\n- exact version before and after\n- relevant config keys\n- primary model route before and after, including runtime id\n- direct smoke result metadata, especially `fallbackAttempts`\n- plugin source path actually loaded\n- installed package version and file layout for any failing npm plugin\n- whether the plugin was bundled or globally installed\n- exact update command and selected channel\n- whether external plugins used channel-specific versions or fallbacks\n- service stop/restart messages, especially if the service manager needed a fallback stop/unload path\n- `doctor`/`plugins doctor` warning text\n- the specific log lines around startup failure or restart\n\nSanitize handoff notes before sharing externally:\n- remove hostnames, usernames, IPs, machine names, tokens, account ids, channel ids, and personal job names\n- replace local paths with placeholders such as `<state>`, `<global-openclaw>`, and `~/.openclaw`\n- summarize private prompt/session contents instead of quoting them\n- keep exact version numbers, package names, model ids, runtime ids, and error classes when they are needed to reproduce the bug\n\nFor concrete regression patterns and example symptoms, read [references/failure-patterns.md](references/failure-patterns.md).\n\n## Updating this skill\n\nWhen another operator or agent learns something new from a different OpenClaw host:\n\n- do not delete existing workflow steps unless they are clearly wrong\n- do not replace an existing failure pattern with a narrower one\n- prefer additive updates over rewrites\n- add new regression patterns to `references/failure-patterns.md`\n- only tighten the main workflow in this file if the new lesson changes the recommended audit order for most hosts\n\nIf a new finding is host-specific or uncertain, add it as a new failure pattern with:\n\n- symptom\n- what to inspect\n- why it matters\n\nDo not silently erase older patterns just because the current host did not hit them.\n\nFile v1.0.2:README.md\n\n# OpenClaw Update Runbook\n\nAn operator-focused skill and reference pack for updating OpenClaw, debugging post-update regressions, and proving which layer is actually broken before making changes.\n\nThis is designed for people using Codex or Claude-style agent workflows to maintain OpenClaw hosts. It turns the update/debug process into a repeatable audit instead of a guessy rescue mission.\n\nImportant: the repository is only the distribution point. To use this as a real skill, install or copy the whole folder locally so `SKILL.md` and `references/failure-patterns.md` stay together. The skill expects those files to exist side by side on disk.\n\n## What it includes\n\n- `SKILL.md`: the main update runbook skill\n- `references/failure-patterns.md`: concrete regression patterns seen across multiple hosts\n- `agents/openai.yaml`: lightweight agent metadata for Codex skill use\n\n## What it helps with\n\n- confirming the real service state after an update\n- separating service-manager issues from detached-process issues\n- spotting bundled-vs-global plugin drift\n- finding stale config that survives upgrades\n- checking whether plugin install records match disk reality\n- reading the right logs before changing too much\n- cleaning up task ledger problems that keep a host noisy or half-broken\n\n## Who this is for\n\n- operators maintaining one or more OpenClaw hosts\n- people helping friends or teams recover after an update\n- anyone who wants a structured checklist for \"OpenClaw feels broken after upgrade\"\n\n## Install\n\nClone or download this repository, then place the folder where your Codex skills live, or install it from the repo if your Codex setup supports repo-based skill installs.\n\nDo not copy only `SKILL.md`. The skill refers to local companion files under `references/` and `agents/`.\n\nThe main entry point is:\n\n- `SKILL.md`\n\n## How to use\n\nInvoke the skill when you are:\n\n- upgrading OpenClaw\n- checking health right after an upgrade\n- debugging a host that became slow, disconnected, or inconsistent after update\n\nThe agent should start with `SKILL.md` and open `references/failure-patterns.md` only when the main workflow points to a known regression pattern or contradictory runtime symptoms.\n\nThe runbook is intentionally conservative: verify service reality first, inspect plugin and config drift second, then apply the smallest fix that makes the host consistent again.\n\n## Maintenance model\n\nThis runbook is cumulative. New host-specific lessons should usually be added to `references/failure-patterns.md` rather than replacing existing guidance.\n\nContribution style:\n\n- additive over destructive\n- preserve older patterns unless they are clearly wrong\n- keep examples generic and free of secrets or personal host details\n\n## Suggested repository description\n\nStructured OpenClaw update runbook for Codex/Claude operators: service checks, plugin drift, config regressions, task cleanup, and post-upgrade debugging.\n\nFile v1.0.2:_meta.json\n\n{\n  \"ownerId\": \"kn72yh2bfzkawx37gayv80km7186hw0q\",\n  \"slug\": \"claw-update-runbook\",\n  \"version\": \"1.0.2\",\n  \"publishedAt\": 1779523165577\n}\n\nFile v1.0.2:references/failure-patterns.md\n\n# Failure Patterns\n\nUse this file when the main skill identifies a likely upgrade regression and you need concrete examples of what to inspect.\n\nContribution rule:\n- append new patterns or expand existing ones\n- do not delete older patterns unless they are proven false\n- preserve examples from other hosts even if the current host is healthy\n\n## 1. Update channel drift\n\nSymptom:\n- host is intentionally on beta or a newer stable build\n- `status --deep` says local version is newer than `npm latest`\n- config still says `\"update.channel\": \"stable\"` after a beta install\n\nWhat to inspect:\n- `openclaw --version`\n- `openclaw status --deep`\n- `openclaw.json` update metadata\n\nWhy it matters:\n- operators get misleading update advice\n- handoff notes should call out when install/update channel state is not persisted\n\n## 2. Stale config after upgrade\n\nSymptom:\n- `doctor` says provider or plugin is unknown\n- runtime falls back to auto-detect or legacy behavior\n- helper commands claim to fix config, but warnings remain\n\nCommon keys:\n- `tools.web.search.provider`\n- `plugins.allow`\n- `plugins.entries.*`\n\nTypical example:\n- `tools.web.search.provider=brave` remains after host/plugin changes and becomes invalid\n\n## 3. Bundled plugin vs global npm plugin shadowing\n\nSymptom:\n- bundled capability should work after host upgrade\n- `plugins list` shows a global plugin path under `~/.openclaw/npm/node_modules`\n- plugin version does not match host version\n\nExample:\n- host on `<current-version>`\n- global `@openclaw/discord` still at `<previous-version>`\n- gateway warns about missing compiled runtime output because the global plugin is source-only\n\nWhat to inspect:\n- `openclaw plugins inspect <id>`\n- plugin `source`\n- plugin `origin`\n- plugin `version`\n- presence of `dist/`\n\n## 4. Install records drift from disk reality\n\nSymptom:\n- config or install registry says a plugin is installed\n- recorded path under `~/.openclaw/npm/node_modules/@openclaw/` or `~/.openclaw/extensions/` does not exist\n- plugin not found / phantom allowlist warnings\n\nWhat to inspect:\n- `~/.openclaw/plugins/installs.json`\n- actual install path on disk\n- `openclaw plugins registry --refresh`\n\nThis is the case where reinstalling the plugin is often correct.\n\n## 5. Third-party plugin runtime deps removed\n\nSymptom:\n- after `doctor --fix` or cleanup, a third-party plugin fails to load\n- error looks like `Cannot find module ...`\n- plugin root still exists, but plugin-side `node_modules` is gone\n\nWhat to inspect:\n- plugin package directory\n- plugin `package.json`\n- whether dependencies are externalized at build time\n\nWhy it matters:\n- cleanup can be too aggressive for non-bundled plugins\n\n## 6. Context engine not registered after restart\n\nSymptom:\n- logs say context engine falls back to legacy\n- plugin may still be installed but failed to initialize\n\nLook for:\n- plugin load errors\n- missing dependencies\n- plugin contract warnings\n- plugin registry metadata drift\n\n## 7. Event loop degradation after update\n\nSymptom:\n- `channels status --deep` reports degraded event loop\n- logs show lane wait exceeded, active-memory timeouts, or restart blocked by active tasks\n\nCommon culprits:\n- stale running tasks\n- active-memory timeout loops\n- plugin load retries\n- long-running approval followups\n\nCheck:\n- `openclaw tasks audit`\n- recent `gateway.err.log`\n- recent `gateway.log`\n\n## 8. Task ledger blocks clean restart\n\nSymptom:\n- restart or drain says blocked by active task runs\n- `tasks audit` shows `stale_running`, `lost`, or repeated delivery failures\n\nUseful commands:\n- `openclaw tasks show <id>`\n- `openclaw tasks cancel <id>`\n- `openclaw tasks maintenance --apply`\n\nFix the ledger if it is obviously wrong; otherwise every later health check becomes noisy.\n\n## 9. Command-path disagreement\n\nSymptom:\n- `status --deep` says a channel token is unavailable in this command path\n- `channels status --deep` says channel is connected and healthy\n\nTreat this as a reporting mismatch first, not a real outage.\n\nAdditional example:\n- A channel can be healthy in the gateway service with `token:env`, while `doctor` still warns that the corresponding token env var is absent in the doctor environment.\n- Verify the service env file and `channels status`; do not treat the doctor shell-env warning alone as proof the live gateway is down.\n\n## 10. What to hand the next operator or support contact\n\nWhen a problem looks like an update regression, capture:\n\n- host version before and after\n- whether the capability was bundled, npm-installed, or ClawHub-installed\n- the plugin source path actually loaded\n- stale config keys still present after fix attempts\n- exact `doctor` and `plugins doctor` messages\n- startup log lines around the failure\n\n## 11. Plugin updater follows stale install records\n\nSymptom:\n- core OpenClaw is updated, but `~/.openclaw/plugins/installs.json` still records older plugin specs\n- `openclaw plugins update --all` tries to reinstall the older recorded versions instead of reconciling to the currently installed packages\n- plugin directories under `~/.openclaw/npm/node_modules/@openclaw/` may disappear or config suddenly becomes invalid until the exact desired versions are reinstalled\n\nTypical example:\n- host core is updated\n- install records still point at older plugin specs\n- running `openclaw plugins update --all` attempts the old plugin specs and leaves channel plugins missing on disk until the intended package versions are reinstalled\n\nWhat to inspect:\n- `~/.openclaw/plugins/installs.json`\n- actual package versions in `~/.openclaw/npm/node_modules/@openclaw/*/package.json`\n- whether the plugin directories still exist after `plugins update --all`\n\nWhy it matters:\n- the built-in updater can deepen an upgrade regression if install metadata drift is not corrected first\n- prefer reconciling install records or reinstalling exact target versions before trusting `openclaw plugins update --all`\n\nRefinement:\n- `openclaw plugins registry --refresh` does NOT rewrite the install record's `spec` field. It refreshes `hostContractVersion` and compatibility data only.\n- After a refresh, install records can still carry pinned specs like `<plugin>@<older-version>` even when the disk version is `<newer-version>`. `plugins update --all` will then **downgrade** the on-disk plugin to match the pinned spec.\n- Correct sequence to actually move a third-party plugin forward:\n  1. `openclaw plugins update <id> @<scope>/<pkg>@latest` (note: `update` accepts an explicit spec; this rewrites the install record's spec).\n  2. Or `openclaw plugins install <pkg>@latest --force` to drop the pin.\n- `--all` is safe only after every install record's `spec` already points at `@latest` or the desired version — never trust it after a host upgrade without spot-checking install records first.\n\n## 12. Control UI token mismatch after restart\n\nSymptom:\n- gateway is healthy and reachable\n- dashboard page loads, but websocket auth fails\n- `gateway.err.log` shows `[ws] unauthorized ... reason=token_mismatch`\n- log text may say `unauthorized: gateway token mismatch (open the dashboard URL and paste the token in Control UI settings)`\n\nWhat to inspect:\n- recent `~/.openclaw/logs/gateway.err.log` websocket auth lines\n- whether `gateway.auth.token` or its SecretRef source changed during reinstall/restart\n- whether the browser-side Control UI is still holding an older token\n\nWhy it matters:\n- this can look like a gateway outage even when the backend is healthy\n- separate UI auth cache problems from real startup or channel failures before changing server-side config again\n\n## 13. Channel SecretRef resolves but runtime account still cannot use it\n\nSymptom:\n- `openclaw config validate` passes\n- `openclaw secrets audit` reports `unresolved=0`\n- `openclaw channels status` says a channel is configured but stopped/disconnected with `secret unavailable in this command path`\n- logs say a channel token is unavailable, for example a channel delivery path says the bot token configured for account `default` is unavailable\n\nWhat to inspect:\n- the channel token config path, for example `channels.discord.token`\n- the referenced secrets provider and backing file\n- whether the gateway service env has a working token fallback\n- whether the channel plugin prefers the broken config SecretRef over the env fallback\n\nObserved workaround:\n- add the token to the service env from the existing local secret source\n- remove the broken channel token config field so the channel falls through to the env-token path\n- restart gateway and verify `channels status` reports `token:env` and connected\n\nWhy it matters:\n- schema validation and secrets audit can both pass while the channel runtime still cannot consume the SecretRef\n- this can leave a channel integration down after an update even though the secret exists\n\nConfirmed regression scope:\n- Reproduced cleanly across multiple adjacent channel-plugin versions with a SecretRef pointing at a valid `secrets.json` entry.\n- `openclaw secrets audit` reports `unresolved=0`, `openclaw secrets reload` says \"Secrets reloaded.\", but the channel plugin still throws `unresolved SecretRef ... Resolve this command against an active gateway runtime snapshot before reading it.` at startup.\n- Sibling plugins using the same SecretRef shape (e.g. brave's `/brave_api_key`) resolve fine — the bug is plugin-side, not in the secrets layer.\n- Pragmatic workaround (when env fallback isn't available): inline the literal token into the affected channel token field. This adds one entry to `secrets audit --plaintext` findings but restores the channel. Plan to revert once upstream `@openclaw/discord` ships a fix that resolves SecretRefs against the runtime snapshot.\n\nAddendum — `token:config` in `channels status` is ambiguous:\n- the same status row appears whether the token came from a successfully resolved SecretRef OR from an inline literal (workaround applied); it is not a signal that the upstream bug is fixed.\n- To disambiguate, inspect the actual config field directly:\n  - `node -e 'const c=JSON.parse(require(\"fs\").readFileSync(process.env.HOME+\"/.openclaw/openclaw.json\",\"utf8\")); console.log(typeof c.channels?.discord?.token, c.channels?.discord?.token)'`\n  - `string` value → inline literal (workaround in place)\n  - `object` value → SecretRef (relies on plugin runtime resolution)\n- An operator running this runbook on an inherited host should not assume `token:config` means the regression is gone; verify the field shape before claiming the workaround is no longer needed.\n\n## 14. Gateway CLI start reports argument error but managed service recovers\n\nSymptom:\n- after update, `openclaw gateway start` prints an argument-count error\n- the command may still re-bootstrap the managed service afterward\n- the service manager and open port check show the gateway running despite the CLI error\n\nWhat to inspect:\n- the host service-manager status command\n- listener on the configured gateway port\n- `openclaw status`\n- gateway stdout/stderr logs\n\nWhy it matters:\n- the CLI error is alarming but may not be the actual outage\n- verify service reality before retrying installs or rolling back\n\n## 15. `plugins uninstall` is destructive of every config trace, not just the install record\n\nSymptom:\n- after `openclaw plugins uninstall <id> --force`, the plugin disappears from `plugins list` as expected\n- but the plugin then shows as `disabled` once you try to re-enable a sibling install (e.g., a copy under `~/.openclaw/extensions/`)\n- exclusive slots (e.g., `plugins.slots.contextEngine`) silently revert to `legacy`\n\nWhat `uninstall` can remove:\n- the install record in `~/.openclaw/plugins/installs.json`\n- the on-disk install directory\n- `plugins.entries.<id>` from `openclaw.json`\n- the `<id>` entry from `plugins.allow`\n- exclusive slot assignments where `<id>` was the holder\n\nRecovery after rolling back to a different copy of the same plugin:\n- `openclaw plugins enable <id>` re-adds the entry, allowlist row, and slot assignment\n- restart gateway\n\nCLI flag note:\n- `plugins uninstall` does not accept `--yes`, `-y`, or `--non-interactive`. Use `--force` to skip the confirmation prompt over a non-interactive shell.\n\nWhy it matters:\n- treat `uninstall` as \"wipe all traces\", not as \"remove just the install record\"\n- if you only wanted to swap install paths (npm → extensions or vice versa), prefer manual relocation + `plugins registry --refresh` over `uninstall` + reinstall\n\n## 16. Third-party plugin declares optional peer dependency but compiled bundle imports it unconditionally\n\nSymptom:\n- after upgrading a third-party plugin, `plugins doctor` reports a load failure like `Error [ERR_MODULE_NOT_FOUND]: Cannot find package '<peer-package>'`\n- the plugin's `package.json` lists the missing package under `peerDependenciesMeta` with `optional: true`, suggesting it should be skippable\n\nRoot cause:\n- the published `dist/index.js` was emitted with an unconditional `import` of an \"optional\" peer dependency\n- Node's ESM resolver cannot satisfy the import, so the plugin fails to load even though `package.json` says the dep is optional\n\nTypical example:\n- `<plugin>@<version>` declared `<peer-package>` as `peerDependenciesMeta.<dep>.optional: true`\n- the plugin still failed to load because `dist/index.js` imported it unconditionally\n- the previous version shipped a bundled `node_modules/` next to the plugin and worked fine\n- `plugins update --all` on a host with a stale install record (pattern #11) may downgrade instead, masking this as a different failure mode\n\nWhat to inspect:\n- `package.json` `peerDependencies`, `peerDependenciesMeta`, `dependencies`, `devDependencies`\n- the actual import sites in `dist/index.js` (`grep -E \"from '@.*pi-\" dist/index.js`)\n- whether a previous version's bundled deps are still on disk (e.g., `~/.openclaw/extensions/<id>.stale-*` or `.backup-*` directories)\n\nRecovery:\n- roll back to the last known-good plugin version, ideally one that bundled its deps\n- prefer renaming the broken install dir (e.g., to `<dir>.broken-<date>`) over deleting it, so the failure can still be reproduced for an upstream report\n- share upstream or with support: declared optional deps in `package.json` vs unconditional imports in `dist`\n\nWhy two hosts on the same plugin version can show different results:\n- the bug only surfaces when Node's ESM resolver cannot find the \"optional\" peer from the plugin's location\n- on hosts where the peer is **hoisted** at `~/.openclaw/npm/node_modules/<scope>/<peer>` (sibling to the plugin), the import succeeds silently and `plugins doctor` reports clean\n- the peer can also be satisfied by a copy under `<global-openclaw>/node_modules/<scope>/<peer>` (bundled with the host package), or by leftover `~/.openclaw/plugin-backups/<id>.*/node_modules/<scope>/<peer>` directories from a prior disabled install\n- a host that recently ran a clean reinstall (or `npm prune`, or a `doctor --fix` cleanup that removed disabled plugin backups) is more likely to hit the failure than a host that has accumulated multiple historical copies of the peer\n- if you reproduce the bug, also enumerate every on-disk copy of the peer before rolling back, so you can explain the divergence to upstream:\n  ```\n  find ~/.openclaw <global-node-modules> -maxdepth 6 -type d -name \"<peer-package-name>\"\n  ```\n\nInspection note:\n- `dist/index.js` is typically a single esbuild-bundled minified line; `grep` will appear to match the entire file. Use `grep -oE \"from'@[^']+'\" dist/index.js` (or similar token-level patterns) to enumerate actual import specifiers without dumping the bundle.\n\nWhy it matters:\n- this is not a missing-dep on the operator's side — it is a packaging defect\n- avoid the temptation to manually `npm install` the missing peer into the plugin dir, because the next `plugins update` will overwrite the directory and the fix will silently disappear\n- the resolver-luck variance is itself the bug: a plugin that \"works on my host\" but breaks for the next operator is the same defect, not a host configuration difference; do not dismiss the upstream report because your host happens to satisfy the import\n\n## 17. \"Duplicate plugin id detected\" warning text wraps in a self-referential way\n\nSymptom:\n- `plugins doctor` and `openclaw doctor` warn: `plugin <id>: duplicate plugin id detected; global plugin will be overridden by global plugin (/path/A)`\n- only one path is visible at a glance; the second path is wrapped to a later line and easily missed\n- on a narrow terminal the warning can look self-referential (\"global plugin will be overridden by global plugin (X)\") and is easy to dismiss as a UI bug\n\nReality:\n- the warning is real — there are two on-disk plugin manifests for the same id\n- the conflict is almost always between `~/.openclaw/extensions/<id>/` and `~/.openclaw/npm/node_modules/<scope>/<id>/` (or two copies under the same root)\n- the npm path generally wins, but the extensions path still triggers the warning every restart\n\nWhat to inspect:\n- `find ~/.openclaw -maxdepth 4 -type d \\( -name \"<id>\" -o -name \"@*<id>*\" \\)`\n- whether `plugins.load.paths` in `openclaw.json` is empty or pointing at an extra root\n- whether a previous `plugins update --all` left a `.backup-*` directory next to the new install (those are typically ignored, but a renamed-not-deleted manual copy can be picked up)\n\nRecovery:\n- pick the canonical install (npm-tracked is preferred for plugins managed via `openclaw plugins install`)\n- rename the unwanted copy to `<dir>.stale-<date>` (safer than `rm -rf` mid-runbook)\n- restart gateway and confirm `plugins doctor` reports zero errors and the warning is gone\n\nWhy it matters:\n- operators often dismiss this as cosmetic; it is not — the second path keeps generating doctor noise that masks new regressions\n- the warning text formatter wraps poorly; always re-read the full multi-line warning before deciding the conflict is benign\n\nTrue false-positive variant:\n- after archiving every redundant on-disk copy and confirming `find ~/.openclaw -maxdepth 6 -name 'openclaw.plugin.json' | xargs grep -l '\"<id>\"'` returns only the canonical install path, the warning can still persist\n- `openclaw plugins inspect <id>` then shows the warning's path field is **identical** to the loaded plugin's `Source` path — i.e., the warning is comparing the manifest against itself\n- this looks like an OpenClaw bug where the same manifest is being matched twice (once via the `installs.json` install record, once via filesystem scan) and both lookups are tagged `Origin: global`, generating a phantom duplicate\n- distinguishing genuine #17 (two real manifests on disk) from this false-positive: run `plugins inspect <id>` and compare the `Source` line to the path inside the WARN line. Same path = false positive. Different paths = genuine duplicate, keep hunting.\n- when it is the false positive, leave it alone; do not delete the canonical install in an attempt to silence it\n\n## 18. Bundled provider discovery mode change after host upgrade\n\nSymptom:\n- after upgrading the host package, `openclaw doctor` adds a new warning:\n  `plugins.allow is restrictive, but bundled provider discovery is still in legacy compatibility mode. Bundled provider plugins can ... set plugins.bundledDiscovery to \"allowlist\" after confirming omitted providers.`\n- previously absent config key is now expected: `plugins.bundledDiscovery`\n\nBackground:\n- `plugins.allow` historically gated only third-party plugins; bundled provider plugins (anthropic, openai, gemini, etc.) were always discoverable.\n- a host release introduced `plugins.bundledDiscovery` with two modes:\n  - `\"compat\"` — preserves legacy behavior; bundled providers stay discoverable regardless of `plugins.allow`\n  - `\"allowlist\"` — bundled providers must also appear in `plugins.allow`\n- Hosts upgraded from an older config shape can inherit the legacy behavior implicitly, and doctor may flag it until the key is set explicitly.\n\nWhat to do:\n- if `plugins.allow` is restrictive and you intentionally rely on bundled providers, set `plugins.bundledDiscovery: \"compat\"` to lock in current behavior — note that this **does not silence the doctor warning**, it only pins the mode against a future default flip (see refinement below)\n- if you want strict allowlisting end-to-end and want the warning gone, audit which bundled providers your agent fallback chains require, add them to `plugins.allow`, then set `plugins.bundledDiscovery: \"allowlist\"`\n\nRefinement:\n- Some releases auto-migrate `plugins.bundledDiscovery` to `\"compat\"` during the host upgrade, so the key may already be set even on hosts that never had it explicitly. Always re-read the live config before assuming the warning means the key is unset.\n- Even with `\"compat\"` explicitly set, doctor continues to print: `plugins.allow is restrictive, but bundled provider discovery is still in legacy compatibility mode ... set plugins.bundledDiscovery to \"allowlist\" after confirming omitted bundled providers are intentionally blocked`. The warning is the doctor's nudge to migrate forward, not a \"key missing\" warning. Two paths to silence:\n  1. Migrate to `\"allowlist\"` (recommended): enumerate the bundled providers your agents actually need by walking `c.agents.defaults.model.{primary,fallbacks}` and any agent-level overrides; the model strings are typically `provider/model` shaped (e.g., `anthropic/claude-opus-4-7`, `openai-codex/gpt-5.5`). Map each `provider/` prefix to its bundled plugin id (`openai-codex` → `openai`, since the openai plugin owns both `openai` and `openai-codex` provider ids). Add the corresponding plugin ids to `plugins.allow`, set `plugins.bundledDiscovery: \"allowlist\"`, restart, and re-run doctor.\n  2. Accept the persistent warning and rely on `\"compat\"` — fine for now, but re-audit after every minor bump in case a future version changes the warning into an error.\n- When migrating to `\"allowlist\"`, also confirm the corresponding API-key env vars are present in the service env (e.g., `ANTHROPIC_API_KEY` for the `anthropic` plugin); plugins added to `plugins.allow` without credentials will load but fail at first use, which is harder to diagnose than a discovery warning.\n\nWhy it matters:\n- this is a config-shape change introduced silently by a minor version bump; treat it as a host-upgrade follow-up, not a one-off doctor warning\n- ignoring it doesn't break anything today, but a future minor that flips the default to `\"allowlist\"` will instantly regress provider discovery on every host that hasn't pinned the mode\n\n## 19. CLI uninstall confirmation prompt blocks non-interactive runbooks\n\nSymptom:\n- `openclaw plugins uninstall <id>` prints `Uninstall plugin \"<id>\"? [y/N]` and then exits without doing anything in a non-interactive shell (e.g., a single ssh command with no stdin).\n- stderr may include an unrelated `Detected unsettled top-level await` warning that obscures the real reason (no input piped to the prompt).\n\nWhat to do:\n- always pass `--force` for non-interactive uninstalls\n- `--yes` and `-y` may not be accepted; use `--force` when the command help confirms it skips the prompt\n- if you also want a preview, run `--dry-run` first\n\nWhy it matters:\n- a runbook that pipes a single `ssh` command without a TTY will silently no-op the uninstall, then proceed to \"verify\" steps that report the plugin still present and confuse the operator into deeper changes\n\n## 20. Multi-step SSH update command disconnects mid-run while the box keeps working\n\nSymptom:\n- operator runs a single multi-step `ssh user@host '... stop ... npm install ... reinstall plugins ... start ...'` command\n- the SSH session appears hung or returns no output to the operator's terminal\n- reconnecting with a fresh ssh shows the box has actually completed most or all of the work — versions bumped, gateway running, plugins on disk\n\nWhat's happening:\n- when one of the inner steps restarts launchd or replaces the wrapper script the gateway plist sources, the parent shell association can break and the local ssh client stops receiving stdout, even though the remote `zsh -c '...'` keeps running detached and finishes the script.\n- the remote orphan can persist as a `zsh -c` process for minutes after the parent ssh exits.\n\nWhat to inspect:\n- on the remote host: `pgrep -fl \"openclaw/dist/index.js gateway\"` (current gateway PID and command line)\n- `pgrep -fl \"zsh -c\"` for orphan wrapper processes from the disconnected session\n- on-disk plugin versions vs `npm view @openclaw/<id> version`\n- `~/.openclaw/logs/gateway.log` for the latest `http server listening` line (confirms a fresh restart actually happened)\n\nRecovery:\n- kill orphan wrapper zsh processes (`kill <pid>`)\n- re-run the verification suite (`openclaw --version`, `openclaw plugins doctor`, `openclaw channels status`, `openclaw tasks audit`) from a fresh ssh session\n- do NOT re-run the update script blindly; it may have completed successfully and a second run can re-pin install records to versions that were just bumped\n\nPractical advice:\n- prefer breaking the update into separate ssh invocations per phase: stop → host update → plugin reinstalls → start → verify. A disconnect then loses only the current phase, not the whole sequence.\n- where a single transactional run is unavoidable, redirect the script's output to a remote file (`> /tmp/openclaw-update.log 2>&1`) and tail it from a second ssh session, so the parent disconnect does not lose the audit trail.\n\nWhy it matters:\n- treating an apparent hang as failure and rerunning can corrupt install records mid-flight\n- the runbook's \"verify\" step must rely on freshly inspected box state, not on the success path of the update command's stdout\n\n## 21. Version drift between operator sessions on hosts with autopilot agents\n\nSymptom:\n- operator returns to a host they audited recently and finds a different `openclaw --version` than what they last left it on\n- no explicit operator-initiated update happened in the interim\n- `update.auto.enabled` may be `false` in `openclaw.json`, but the host still moved versions\n\nBackground:\n- some hosts run autopilot or scheduled cron agents (e.g., `gbrain`, `com.gbrain.autopilot.plist`, scheduled openclaw cron jobs) that may bump `openclaw` or its plugins out of band, ignoring the host-level update channel/auto flag\n- the `meta.lastTouchedVersion` field in `openclaw.json` only reflects the last writer, not the last installer\n\nWhat to do:\n- always re-snapshot the live state at session start, even within hours of the previous session:\n  - `openclaw --version`\n  - per-plugin disk versions: `for d in ~/.openclaw/npm/node_modules/@*/*/; do node -e 'process.stdout.write(JSON.parse(require(\"fs\").readFileSync(process.argv[1])).name+\" \"+JSON.parse(require(\"fs\").readFileSync(process.argv[1])).version+\"\\n\")' \"$d/package.json\"; done`\n  - any service-env or config edits applied by previous workarounds\n- do not rely on prior-session memory for current state; treat every session as a fresh audit\n\nWhy it matters:\n- a stale mental model leads to the wrong fix path — e.g., applying an env-var workaround when a literal-inline workaround is already in place, or \"rolling back\" an update the operator never made\n- two parallel operator sessions (or an operator + a long-running autopilot) can converge on contradictory workarounds if neither re-snapshots first\n\n## 22. Cohort version snapshot before host update\n\nPractice:\n- before stopping the gateway, capture every plugin's installed version with a single command:\n  ```\n  for d in ~/.openclaw/npm/node_modules/@*/*/; do\n    node -e 'const p=JSON.parse(require(\"fs\").readFileSync(process.argv[1])); process.stdout.write(p.name+\"@\"+p.version+\"\\n\")' \"$d/package.json\"\n  done | sort > /tmp/openclaw-pre-upgrade-plugins.txt\n  ```\n- after the upgrade, re-run the same command into `/tmp/openclaw-post-upgrade-plugins.txt` and `diff` them.\n- a clean cohort upgrade should show every plugin version moving in the diff; any plugin that did NOT move is a candidate for shadow drift (Pattern #3) once the host moves further.\n\nWhy it matters:\n- a `plugins install <pkg>@latest --pin --force` no-op (e.g., from a network or registry hiccup, or because npm latest temporarily lagged ClawHub) is invisible until you hit a sub-feature that depends on the new version.\n- without the snapshot/diff, the operator cannot prove the cohort actually moved — only that the host did.\n- the snapshot also documents what to roll back to if the new cohort surfaces a packaging defect (Pattern #16).\n\n## 23. Service-env writer corrupts string secrets with literal double-quote wrapping\n\nSymptom:\n- a previously working channel returns auth failure from the upstream API immediately after a host upgrade, even though `channels status` reports `token:env` and the channel was healthy before the upgrade\n- `secrets audit` reports `unresolved=0` and the underlying value in `secrets.json` is unchanged\n- the channel reconnects fine if you manually re-paste the token into the env file\n\nRoot cause:\n- the service-env writer JSON-encodes string values from `secrets.json` (wrapping them in `\"`) and **then** shell-single-quotes the result for the env file\n- the resulting line looks like `export CHANNEL_TOKEN='\"<token>\"'` — the outer single quotes are correct shell quoting, but the inner literal `\"` characters become part of the value when the env file is sourced\n- the upstream API receives a token with stray leading and trailing `\"` chars and rejects it\n- the bug only surfaces the next time the env file is regenerated (a host upgrade, certain `doctor --fix` runs, plugin reinstalls), so it presents as \"the upgrade broke the channel\" rather than a config drift\n\nWhat to inspect:\n- the raw bytes of the env line, not just the masked output:\n  ```\n  node -e 'const fs=require(\"fs\"); const p=process.env.HOME+\"/.openclaw/service-env/<service-env-file>\"; const l=fs.readFileSync(p,\"utf8\").split(\"\\n\").find(l=>l.startsWith(\"export <TOKEN_ENV_NAME>=\")); console.log(JSON.stringify(l))'\n  ```\n- a clean line has a single shell-quoted token value with no inner literal double quotes\n- a corrupted line has literal `\"` characters just inside the shell quotes\n- check every `*_TOKEN` / `*_API_KEY` line in the env file the same way; the same writer emits all of them\n\nRecovery:\n- back up the env file: `cp <env> <env>.bak-token-fix-<date>`\n- rewrite the affected lines using the value from `secrets.json` (which is the canonical clean value), shell-single-quoted with no inner JSON wrapping; only safe if the secret itself contains no single quotes (almost always the case for API tokens)\n- restart the gateway through the host service manager\n- re-run `openclaw channels status --deep` and confirm the channel reconnects\n\nWhy it matters:\n- this is a packaging defect in the env-file writer, not operator drift; the local fix is fragile because the next regeneration will re-corrupt the file\n- share upstream or with support: exact line bytes, the source `secrets.json` value type (string), and the affected host version\n- until upstream ships a fix, treat any operation that may rewrite `service-env/*.env` (host updates, plugin updates, `doctor --fix` involving secrets) as a channel-auth outage risk and re-verify channel auth immediately after\n\nWorkflow addendum:\n- when post-update channel health shows auth failure, **inspect the env file's raw bytes for quote corruption before assuming the upstream credential was rotated**. The wrong diagnosis path leads to credential rotation and operator confusion; the right diagnosis takes 30 seconds.\n\n## 24. Non-interactive SSH hides the OpenClaw binary\n\nSymptom:\n- `ssh host 'openclaw --version'` returns `command not found`\n- the same host has a working managed service and `openclaw status` works in an interactive shell\n- service-manager status may also look wrong if the operator guesses an old service label\n\nWhat to inspect:\n- `echo \"$PATH\"` inside the non-interactive SSH command\n- common binary locations for the host's package manager and `~/.local/bin/openclaw`\n- the actual service label or name\n- the gateway command and port inside the service definition or `openclaw status --deep`\n\nObserved example:\n- non-interactive SSH inherited only `/usr/bin:/bin:/usr/sbin:/sbin`\n- OpenClaw was installed under a package-manager prefix\n- the gateway service label was not the older guessed label\n- the live gateway port differed from an old hard-coded health port, so probing the old port falsely reported an outage\n\nWhy it matters:\n- a stripped SSH `PATH` can look like a missing installation\n- an old label or hard-coded port can make a healthy gateway look stopped\n- always establish the command path, label, and port before running update or repair commands\n\n## 25. Update stop phase may need service-manager fallback even after clean gateway SIGTERM\n\nSymptom:\n- `openclaw update --channel <channel>` prints that the normal service stop did not fully stop the service\n- updater reports it used a stronger stop/unload fallback and left the service unloaded before continuing\n- gateway logs may show a clean `SIGTERM` shutdown, followed by a short-lived restart that is immediately terminated before the package swap completes\n\nWhat to inspect:\n- update command stdout/stderr\n- the host service-manager status command before and after the update\n- recent gateway logs around the stop/restart window\n- final `openclaw status --deep`, `/health`, and managed-service PID\n\nWhy it matters:\n- this is a lifecycle hiccup, not necessarily an update failure\n- do not rerun the update just because the normal stop needed fallback; first verify the final service is loaded/running and the gateway responds on its configured port\n- include the stop/fallback lines in handoff notes, because they show service-manager semantics the updater had to recover from\n\n## 26. Selected update channel has no matching external plugin release\n\nSymptom:\n- host updates successfully to a selected channel such as beta\n- an external plugin cannot be found on npm for `<package>@<channel>`\n- updater falls back to another tag such as `@latest`\n- post-update `plugins doctor` can still be clean, but the host is now running a mixed channel cohort\n\nObserved example:\n- host updated to a selected channel build\n- one third-party plugin had no `@beta` release and fell back to `@latest`\n- a globally installed official channel plugin did update to the matching beta version\n- plugin peer dependency links were repaired during the update\n\nWhat to inspect:\n- update output for `Package not found on npm` and `falling back` lines\n- `openclaw plugins list --json` for each enabled plugin's `origin`, `source`, and `version`\n- `~/.openclaw/plugins/installs.json` to see whether the recorded spec now points at the intended version/tag\n\nWhy it matters:\n- \"host on beta\" does not imply every external plugin is on beta\n- a clean `plugins doctor` proves loadability, not cohort consistency\n- handoff notes should separate OpenClaw-bundled plugin behavior from external plugin publishing gaps\n\n## 27. Transient post-restart scope and pricing warnings can coexist with healthy channels\n\nSymptom:\n- immediately after restart, gateway logs show websocket responses like `missing scope: operator.read`\n- `status --deep` reports a noncritical external catalog or pricing fetch degraded\n- channels remain connected and `/health` reports live\n\nWhat to inspect:\n- whether the scope errors are confined to the seconds after restart\n- whether later `channels status --deep` is connected\n- whether `/health` returns `{\"ok\":true,\"status\":\"live\"}`\n- whether the warning is tied to a third-party catalog/pricing fetch rather than local gateway startup\n\nWhy it matters:\n- these warnings are useful to report, but they should not be conflated with a failed package update\n- stale Control UI/websocket clients can race the new gateway during restart\n- external catalog/pricing fetch failures may degrade status without affecting channel delivery or plugin loading\n\n## 28. Codex OAuth model migration succeeds in config but fails at runtime\n\nSymptom:\n- an OAuth-only OpenAI/Codex host has working `openai-codex/gpt-*` refs before upgrade\n- `doctor` or `update` rewrites agent and cron refs to `openai/gpt-*`\n- session/status tables may show the display model as `gpt-5.5` and the runtime as `OpenAI Codex`\n- a direct agent run returns `status: ok`, but metadata shows the OpenAI/Codex primary route failed and a fallback provider won\n\nWhat to inspect:\n- `agents.defaults.model.primary`\n- `agents.defaults.models` and every `agents.list[*].models` entry for `agentRuntime.id`\n- cron payload models in `~/.openclaw/cron/jobs.json`\n- direct smoke test metadata: provider, model, runtime/harness, and `fallbackAttempts`\n- recent gateway logs around `agent model:` and provider fallback decisions\n\nTypical failures:\n- direct `openai/gpt-*` route fails with direct OpenAI API-key auth on an OAuth-only host\n- migrated `openai/gpt-*` route selects a new `codex` runtime but fails before model execution\n- restored `openai-codex/gpt-*` route reaches the old provider but fails on request-shaping or tool-schema validation\n\nWhy it matters:\n- `status: ok` is not proof that the intended OpenAI/Codex route works; fallbacks can mask the primary-route regression\n- cron jobs can be silently migrated independently of agent defaults and then fail later when they fire\n- do not claim a model-routing fix is verified until a fresh direct run completes on the intended provider/runtime with no unexpected fallback\n\nVerification command shape:\n```\nopenclaw agent --agent main --session-id <fresh-id> --message \"Reply exactly: SMOKE_OK\" --timeout 120 --json\n```\n\nThe result is healthy only if:\n- the payload text is correct\n- the final provider/model match the intended primary route\n- runtime/harness matches the intended path\n- `fallbackAttempts` is empty or contains only known benign retries\n\n## 29. `@openclaw/codex` package import resolves `root-alias.cjs` as a directory\n\nSymptom:\n- update installs or enables `@openclaw/codex`\n- model entries route `openai/gpt-*` through `agentRuntime.id: \"codex\"`\n- direct agent smoke falls back with:\n  `Cannot find module '<global-openclaw>/dist/plugin-sdk/root-alias.cjs/codex-native-task-runtime'`\n- on disk, `root-alias.cjs` is a file and `codex-native-task-runtime.js` is its sibling\n\nWhat to inspect:\n- `~/.openclaw/npm/node_modules/@openclaw/codex/package.json`\n- `~/.openclaw/npm/node_modules/@openclaw/codex/dist/run-attempt-*.js`\n- `<global-openclaw>/dist/plugin-sdk/root-alias.cjs`\n- `<global-openclaw>/dist/plugin-sdk/codex-native-task-runtime.js`\n- whether `plugins.entries.codex` exists or whether `codex` is activated as a special runtime plugin outside normal plugin entries\n- both `openclaw plugins inspect codex` and `openclaw plugins list --json`; these can disagree, with `inspect` reporting `Status: loaded` while the JSON list shows `\"enabled\": false` / `\"status\": \"disabled\"` for the same package\n\nUseful snapshot:\n```\nnode -e 'const fs=require(\"fs\"); const p=process.env.HOME+\"/.openclaw/npm/node_modules/@openclaw/codex/package.json\"; console.log(JSON.stringify(JSON.parse(fs.readFileSync(p,\"utf8\")), null, 2))'\nfind <global-openclaw>/dist/plugin-sdk -maxdepth 2 -type f | grep -E \"root-alias|codex-native\"\n```\n\nWhy it matters:\n- this is likely an OpenClaw package/import-path bug, not local credential drift\n- reverting only the model id may hide the package bug by moving traffic back to an older provider path\n- handoff notes should include the exact package version and sanitized file layout\n- `plugins doctor` may still say \"No plugin issues detected\"; do not treat plugin doctor alone as proof the `codex` agent runtime can execute\n\nObserved in 2026.5.12-beta.2:\n- update auto-installed missing configured plugin `codex` from `@openclaw/codex@beta`\n- `plugins inspect codex` reported package version `2026.5.12-beta.2` and `Status: loaded`\n- raw plugin JSON showed the same plugin as disabled\n- direct smoke with `openclaw agent --model openai/gpt-5.5 --json` failed immediately with the `root-alias.cjs/codex-native-task-runtime` module path error\n- the expected file existed as `<global-openclaw>/dist/plugin-sdk/codex-native-task-runtime.js`, adjacent to `<global-openclaw>/dist/plugin-sdk/root-alias.cjs`\n\n## 30. OpenAI-compatible tool schema rejects arrays missing `items`\n\nSymptom:\n- the OpenAI/Codex route reaches request validation, then fails with a 400 schema error\n- fallback succeeds on a provider with looser or different tool-schema validation\n- error text resembles:\n  `Invalid schema for function '<tool>': In context=('properties', '<array_field>'), array schema missing items.`\n\nWhat to inspect:\n- the failing tool name and plugin owner\n- the generated tool schema passed to OpenAI/Codex\n- plugin schema source if the tool belongs to a plugin\n- request-shaping code that converts tool definitions between provider schema formats\n\nWhy it matters:\n- this blocks the primary route even when credentials and runtime selection are correct\n- fallback success can make the agent appear healthy while all GPT/OpenAI primary runs are actually rejected before completion\n- the local workaround is usually to remove/fix the bad tool from the agent toolset or fall back to another provider, but the upstream fix should validate/sanitize schemas before dispatch\n\nHandoff guidance:\n- sanitize the tool name if it reveals private app naming, but keep the field path and JSON Schema error text\n- state whether the same agent run succeeded only through fallback\n- include the OpenClaw version and provider/model that rejected the schema\n\n## 31. Updater restart step runs under the previous CLI after package swap\n\nSymptom:\n- `openclaw update --channel beta` reports a successful package swap from version X to version Y\n- during restart it warns that config was written by version Y, but the current command is running version X\n- updater then says the gateway already reports version Y and skips a redundant restart\n\nWhat to inspect:\n- `openclaw --version` from a fresh shell\n- `which openclaw`\n- `openclaw gateway status --deep` or `openclaw status --deep`\n- managed-service command path and live gateway version\n\nWhy it matters:\n- this may be harmless if the gateway is actually running the new version, but it is confusing in beta validation\n- it can mask real CLI/global-install/service path mismatches\n- capture the warning for the next operator or support contact, but verify service reality before rerunning the update\n\n## 32. `cron run --expect-final` proves enqueue but not final completion\n\nSymptom:\n- `openclaw cron run <id> --expect-final --timeout <ms>` returns quickly with an enqueue-style JSON payload\n- no final agent result is included even though help says the flag waits for the final response\n- `openclaw cron runs` may require `--id`, which makes broad post-update polling less discoverable\n\nWhat to inspect:\n- exact CLI version\n- `openclaw cron run --help`\n- `openclaw cron runs --help`\n- run history for the specific job id\n- job status after a delay\n\nWhy it matters:\n- cron verification after an update can be falsely marked complete when only enqueue was proven\n- for handoff notes, distinguish \"manual run enqueued\" from \"manual run completed successfully\"\n- pair manual cron runs with a delayed status/history poll before declaring cron healthy\n\n## 33. Discord offline because the managed gateway service is installed but unloaded\n\nSymptom:\n- Discord shows the bot offline, and local channel status can only report config because the gateway is unreachable\n- `openclaw doctor` reports `Gateway not running` and a managed service such as a LaunchAgent installed but not loaded\n- `openclaw update status` may still work from SSH because it does not require the live gateway\n\nObserved recovery:\n- From an outside SSH shell, export the real package-manager path first\n- Run the requested stable update explicitly, for example `openclaw update --channel stable --yes --timeout 1800`\n- Re-run `openclaw status --deep` and `openclaw channels status --deep`\n- A healthy recovery shows the service loaded/running, gateway reachable, the selected channel persisted, and Discord `running, connected`\n\nWhat to inspect:\n- `command -v openclaw` and `openclaw --version`\n- `openclaw update status`\n- `openclaw doctor --non-interactive --no-workspace-suggestions`\n- `openclaw status --deep`\n- `openclaw channels status --deep`\n\nWhy it matters:\n- a channel outage can be a service-manager state problem rather than a Discord plugin problem\n- updating from outside the OpenClaw-managed agent path can recover an unloaded gateway and move the host back to the intended stable channel in one pass\n- record pre-update warnings separately from the package update result, especially plaintext-secret warnings, stale session metadata, and old task-ledger warnings\n\nRemote access guardrail:\n- If another host cannot be reached over SSH with a short timeout, including from an available jump host, classify it as a transport/access blocker\n- Do not file an OpenClaw issue for an unreachable host unless you have logs or command output proving OpenClaw failed on that host\n\nFile v1.0.2:openclaw-beta4-audit-2026-05-13.md\n\n# OpenClaw Beta 4 Update Audit - 2026-05-13\n\n## Scope\n\nUpdated three remote macOS OpenClaw installs to `2026.5.12-beta.4` (`d124625`) using:\n\n```sh\nopenclaw update --channel beta --tag 2026.5.12-beta.4 --yes --timeout 1800\n```\n\nHost identifiers, usernames, IPs, local personal paths, channel tokens, account IDs, session IDs, and private prompt or workspace content are intentionally omitted or generalized.\n\n## Starting Versions\n\n- Host A: `2026.5.12-beta.3`\n- Host B: `2026.5.10-beta.3`\n- Host C: `2026.5.12-beta.2`\n\nAll three were already configured for the `beta` update channel and reported `2026.5.12-beta.4` available before update.\n\n## Update Result\n\nAll three installs completed the package update successfully:\n\n- `Root: /opt/homebrew/lib/node_modules/openclaw`\n- `After: 2026.5.12-beta.4`\n- Package manager/install mode reported as `pnpm`\n- Managed LaunchAgent was stopped before package update\n- Gateway ended up running after update\n\nPost-update verification on all three:\n\n- `openclaw --version`: `OpenClaw 2026.5.12-beta.4 (d124625)`\n- `openclaw update status`: `up to date · npm beta 2026.5.12-beta.4`\n- `openclaw gateway status --deep`: LaunchAgent loaded, gateway running, connectivity probe OK, CLI version and gateway version both `2026.5.12-beta.4`\n- `openclaw plugins doctor`: `No plugin issues detected`, with a deprecation warning: `plugin runtime config.loadConfig() is deprecated (runtime-config-load-write); use config.current().`\n- Channel checks were reachable after update\n- Direct non-delivered agent checks succeeded on all three with `openai/gpt-5.5`, `agentHarnessId: codex`, and `fallbackUsed: false`\n\n## Maintainer-Facing Bugs/Issues\n\n### 1. Update restart phase emits stale CLI/config-version mismatch on all three npm installs\n\nAfter the package update and plugin update completed, all three hosts emitted the same restart-time warning:\n\n```text\nRestarting service...\nYour OpenClaw config was written by version 2026.5.12-beta.4, but this command is running <previous-version>.\nCheck: `openclaw --version`, `which openclaw`, and `openclaw gateway status --deep`.\nIf unexpected, update PATH so `openclaw` points to the version you want, or reinstall the Gateway service from that same OpenClaw install.\nGateway already reports the updated version after service refresh; skipped redundant restart.\n```\n\nThe `<previous-version>` value matched each host's pre-update CLI (`2026.5.12-beta.3`, `2026.5.10-beta.3`, and `2026.5.12-beta.2` respectively).\n\nObserved outcome was healthy, but the warning is confusing and looks like a real version-skew failure during a successful update. It also suggests the post-install restart logic is still executing in the pre-update process after config has been written by the new version.\n\nExpected behavior: for package-manager updates, post-install restart/verification should either re-exec through the updated entrypoint or report this as an expected updater self-staleness case without alarming operators. If an older process intentionally remains in charge of the restart, the message should distinguish that known case from an actual operator PATH/service mismatch.\n\nLikely source area in the local checkout:\n\n- `src/cli/update-cli/update-command.ts`\n- `src/cli/update-cli.test.ts`\n- related future-config guard tests under `src/cli/daemon-cli/`\n\n### 2. `plugins doctor` reports a deprecated runtime config API even while saying no plugin issues\n\nOn all three hosts, `openclaw plugins doctor` printed:\n\n```text\nplugin runtime config.loadConfig() is deprecated (runtime-config-load-write); use config.current().\nNo plugin issues detected.\n```\n\nThis may be expected while third-party plugins migrate, but as operator output it is awkward: the command says no plugin issues while also surfacing a runtime deprecation. It is not clear which plugin caused it or whether action is required.\n\nExpected behavior: either attribute the deprecation to a plugin ID/path or treat it as a doctor finding with actionable output. If the deprecation is purely internal/noise, suppress it from `plugins doctor` success output.\n\nRelevant source area:\n\n- `src/plugins/runtime/runtime-config.ts`\n- plugin implementations still using `runtime.config.loadConfig()`\n\n### 3. External plugin beta fallback is not summarized as drift after update\n\nOn one host, a configured external plugin had no beta npm release:\n\n```text\nPlugin \"lossless-claw\" has no beta npm release for @martian-engineering/lossless-claw@beta; using @martian-engineering/lossless-claw@latest instead. Core update can still complete.\n```\n\nThis is probably a reasonable fallback, but the end state leaves the host on a beta OpenClaw core with at least one external plugin intentionally pinned to `latest`. The update result says OK, and later security output reports unpinned npm specs, but there is no compact update-summary section calling out the mixed-channel plugin state.\n\nExpected behavior: the final update summary should include a clear \"plugin channel fallback/mixed channel\" note when `@beta` falls back to `@latest`, so operators do not have to spot it in the middle of install logs.\n\nRelevant source area:\n\n- `src/plugins/update.ts`\n- `src/plugins/plugin-peer-link.ts`\n\n## Additional Operator Notes\n\nThese were not treated as beta-update regressions:\n\n- One host had a pre-update stalled agent run causing gateway timeout during baseline doctor. Restart during update cleared gateway reachability; post-update gateway status was OK.\n- One host had a pre-existing gateway token source conflict (`OPENCLAW_GATEWAY_TOKEN` vs `gateway.auth.token`) that remained after update.\n- Task audits continued to show stale/lost/delivery warnings that predated the update.\n- One direct agent check used the phrase \"smoke test\"; that triggered a local `smoke-test` skill and caused tool calls plus a memory write before returning `OK`. This looks like a skill-trigger/operator-footgun observation, not evidence that the beta update itself failed.\n\n## PR Candidates For A Non-Engineer Using Codex/Claude\n\n1. Update the restart-phase message for package updates so the known stale parent updater process is not reported like an unexpected PATH/config mismatch. Start in `src/cli/update-cli/update-command.ts` and add/adjust a focused test in `src/cli/update-cli.test.ts`.\n2. Improve plugin update summary output when a channel-specific plugin version falls back to `@latest`. Start in `src/plugins/update.ts`; likely mostly formatting and tests.\n3. Attribute or suppress the `runtime.config.loadConfig()` deprecation warning in `plugins doctor` success output. Start in `src/plugins/runtime/runtime-config.ts` and search for remaining plugin `loadConfig()` callers.\n\nFile v1.0.2:openclaw-beta5-audit-2026-05-13.md\n\n# OpenClaw Beta 5 Update Audit - 2026-05-13\n\n## Scope\n\nUpdated two remote macOS OpenClaw installs to `2026.5.12-beta.5` (`2cdd69a`) using:\n\n```sh\nopenclaw update --channel beta --tag 2026.5.12-beta.5 --yes --timeout 1800\n```\n\nThe third known install was intentionally excluded because it was already down before this run. Host identifiers, usernames, IPs, local personal paths, channel tokens, account IDs, session IDs, and private prompt or workspace content are intentionally omitted or generalized.\n\nThe upstream tag was present at `refs/tags/v2026.5.12-beta.5` with SHA `e8f4811d79cfc27778ea862a69eb0e6173233c97`.\n\n## Starting Versions\n\n- Host A: `2026.5.12-beta.4`\n- Host B: `2026.5.12-beta.4`\n\nBoth hosts were already configured for the `beta` update channel and reported `2026.5.12-beta.5` available before update.\n\n## Update Result\n\nBoth installs completed the core package update successfully:\n\n- `Root: /opt/homebrew/lib/node_modules/openclaw`\n- `After: 2026.5.12-beta.5`\n- Package manager/install mode reported as `pnpm`\n- Managed LaunchAgent was stopped before package update\n- Gateway ended up running after update\n\nPost-update verification on both hosts:\n\n- \n\nArchive v1.0.1: 6 files, 23235 bytes\n\nFiles: agents/openai.yaml (303b), LICENSE (1056b), README.md (2932b), references/failure-patterns.md (43342b), SKILL.md (11437b), _meta.json (138b)\n\nArchive v1.0.0: 6 files, 22841 bytes\n\nFiles: agents/openai.yaml (303b), LICENSE (1056b), README.md (2932b), references/failure-patterns.md (42394b), SKILL.md (11073b), _meta.json (138b)","readmeExcerpt":"Skill: OpenClaw Update Runbook Owner: bkf-gitty Summary: Use when updating OpenClaw or debugging an OpenClaw instance after an update. This skill acts as a structured update runbook with emphasis on gateway startup... Tags: latest:1.0.6 Version history: v1.0.6 | 2026-05-28T16:55:26.552Z | user Sanitized public runbook update with service-user diagnostics, ClawHub Codex extension drift checks, isolated Codex-home guid","codeSnippets":[],"executableExamples":[{"language":"text","snippet":"find ~/.openclaw <global-node-modules> -maxdepth 6 -type d -name \"<peer-package-name>\""},{"language":"text","snippet":"for d in ~/.openclaw/npm/node_modules/@*/*/; do\n    node -e 'const p=JSON.parse(require(\"fs\").readFileSync(process.argv[1])); process.stdout.write(p.name+\"@\"+p.version+\"\\n\")' \"$d/package.json\"\n  done | sort > /tmp/openclaw-pre-upgrade-plugins.txt"},{"language":"text","snippet":"node -e 'const fs=require(\"fs\"); const p=process.env.HOME+\"/.openclaw/service-env/<service-env-file>\"; const l=fs.readFileSync(p,\"utf8\").split(\"\\n\").find(l=>l.startsWith(\"export <TOKEN_ENV_NAME>=\")); console.log(JSON.stringify(l))'"},{"language":"text","snippet":"openclaw agent --agent main --session-id <fresh-id> --message \"Reply exactly: SMOKE_OK\" --timeout 120 --json"},{"language":"text","snippet":"node -e 'const fs=require(\"fs\"); const p=process.env.HOME+\"/.openclaw/npm/node_modules/@openclaw/codex/package.json\"; console.log(JSON.stringify(JSON.parse(fs.readFileSync(p,\"utf8\")), null, 2))'\nfind <global-openclaw>/dist/plugin-sdk -maxdepth 2 -type f | grep -E \"root-alias|codex-native\""},{"language":"text","snippet":"openclaw update --channel stable --yes --timeout 1800"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: openclaw-update-runbook\ndescription: Use when updating OpenClaw or debugging an OpenClaw instance after an update. This skill acts as a structured update runbook with emphasis on gateway startup, service-manager state, plugin registry and install drift, bundled-vs-npm/clawhub plugin confusion, stale config carried across upgrades, channel health, task ledger corruption, and logs that explain why the updated system is slow, disconnected, or half-broken.\nversion: 1.0.6\nmetadata:\n  openclaw:\n    emoji: \"🦞\"\n---\n\n# OpenClaw Update Runbook\n\nUse this skill when an OpenClaw host was just updated, is about to be updated, or is behaving strangely after an update. It is a generic operator runbook, not a release-specific checklist.\n\nThis skill is meant to be installed as a folder, not copied as a single file. It expects `references/failure-patterns.md` to exist locally beside `SKILL.md` inside the same skill bundle.\n\nThe goal is not only to get it running, but to prove which layer is broken:\n\n- service lifecycle and service-manager state\n- host package version\n- plugin/package compatibility\n- config drift\n- model/provider runtime routing\n- channel health\n- task ledger health\n- cron/session isolation and channel-lane ownership\n- runtime performance\n- command-path and update-channel assumptions\n- self-update hazards when an agent updates the gateway that is running it\n- supply-chain and package-integrity spot checks after plugin/npm churn\n\n## Quick workflow\n\n1. Establish the real starting state.\n   For remote multi-host updates, first prove SSH reachability to each host\n   with a short timeout. If a host cannot be reached directly or through an\n   available jump host, record it as a transport/access blocker instead of an\n   OpenClaw update failure, because no OpenClaw command has executed on that\n   host yet.\n\n   If you are connected over non-interactive SSH, do not assume the\n   login-shell `PATH` is available. First locate the binary with common install\n   paths such as a package-manager prefix and `~/.local/bin/openclaw`, then\n   export the correct `PATH` for the audit session.\n\n   If the gateway process is owned by a different OS user than the SSH login\n   user, run OpenClaw diagnostics as the gateway service user. The SSH user can\n   have no `openclaw` on PATH, or a private package-manager shim can be\n   unreadable, while the LaunchAgent/systemd service is healthy under another\n   home directory. Derive the service user, state dir, CLI path, and port from\n   the live process/service definition before running `doctor` or editing\n   config.\n\n   Check:\n   - `openclaw --version`\n   - `openclaw update status`\n   - `openclaw status --deep`\n   - `openclaw doctor --non-interactive --no-workspace-suggestions`\n   - `openclaw channels status --deep`\n   - `openclaw tasks audit`\n   - current model routing: agent defaults, agent-level model maps, fallback chains, and cron payload models\n   - recent successful sessions for the primary model and runtime, not j"},{"path":"README.md","content":"# OpenClaw Update Runbook\n\nAn operator-focused skill and reference pack for updating OpenClaw, debugging post-update regressions, and proving which layer is actually broken before making changes.\n\nThis skill turns the update/debug process into a repeatable audit: establish the real host state, inspect service and plugin drift, verify model routing, then apply the smallest repair that makes the system consistent again.\n\nInstall or copy the whole folder so `SKILL.md` and `references/failure-patterns.md` stay together. The skill expects those files to exist side by side on disk.\n\n## What it includes\n\n- `SKILL.md`: the main update runbook skill\n- `references/failure-patterns.md`: concrete regression patterns seen across multiple hosts\n- `agents/openai.yaml`: lightweight agent metadata for skill catalogs that use it\n\n## What it helps with\n\n- confirming the real service state after an update\n- separating service-manager issues from detached-process issues\n- spotting bundled-vs-global plugin drift\n- finding stale config that survives upgrades\n- checking whether plugin install records match disk reality\n- reading the right logs before changing too much\n- cleaning up task ledger problems that keep a host noisy or half-broken\n\n## Who this is for\n\n- operators maintaining one or more OpenClaw hosts\n- operators helping a team or another maintainer recover after an update\n- anyone who wants a structured checklist for \"OpenClaw feels broken after upgrade\"\n\n## Install\n\nPlace the folder where your agent skills live, or install it through a compatible skill manager.\n\nDo not copy only `SKILL.md`. The skill refers to local companion files under `references/` and `agents/`.\n\nThe main entry point is:\n\n- `SKILL.md`\n\n## How to use\n\nInvoke the skill when you are:\n\n- upgrading OpenClaw\n- checking health right after an upgrade\n- debugging a host that became slow, disconnected, or inconsistent after update\n\nThe agent should start with `SKILL.md` and open `references/failure-patterns.md` only when the main workflow points to a known regression pattern or contradictory runtime symptoms.\n\nThe runbook is intentionally conservative: verify service reality first, inspect plugin and config drift second, then apply the smallest fix that makes the host consistent again.\n\n## Maintenance model\n\nThis runbook is cumulative. New host-specific lessons should usually be added to `references/failure-patterns.md` rather than replacing existing guidance.\n\nContribution style:\n\n- additive over destructive\n- preserve older patterns unless they are clearly wrong\n- keep examples generic and free of secrets or personal host details\n\n## Suggested catalog description\n\nStructured OpenClaw update runbook for AI-agent operators: service checks, plugin drift, config regressions, task cleanup, and post-upgrade debugging."},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn72yh2bfzkawx37gayv80km7186hw0q\",\n  \"slug\": \"claw-update-runbook\",\n  \"version\": \"1.0.6\",\n  \"publishedAt\": 1779987326552\n}"},{"path":"references/failure-patterns.md","content":"# Failure Patterns\n\nUse this file when the main skill identifies a likely upgrade regression and you need concrete examples of what to inspect.\n\nContribution rule:\n- append new patterns or expand existing ones\n- do not delete older patterns unless they are proven false\n- preserve examples from other hosts even if the current host is healthy\n\n## 1. Update channel drift\n\nSymptom:\n- host is intentionally on beta or a newer stable build\n- `status --deep` says local version is newer than `npm latest`\n- config still says `\"update.channel\": \"stable\"` after a beta install\n\nWhat to inspect:\n- `openclaw --version`\n- `openclaw status --deep`\n- `openclaw.json` update metadata\n\nWhy it matters:\n- operators get misleading update advice\n- handoff notes should call out when install/update channel state is not persisted\n\n## 2. Stale config after upgrade\n\nSymptom:\n- `doctor` says provider or plugin is unknown\n- runtime falls back to auto-detect or legacy behavior\n- helper commands claim to fix config, but warnings remain\n\nCommon keys:\n- `tools.web.search.provider`\n- `plugins.allow`\n- `plugins.entries.*`\n\nTypical example:\n- `tools.web.search.provider=brave` remains after host/plugin changes and becomes invalid\n\n## 3. Bundled plugin vs global npm plugin shadowing\n\nSymptom:\n- bundled capability should work after host upgrade\n- `plugins list` shows a global plugin path under `~/.openclaw/npm/node_modules`\n- plugin version does not match host version\n\nExample:\n- host on `<current-version>`\n- global `@openclaw/discord` still at `<previous-version>`\n- gateway warns about missing compiled runtime output because the global plugin is source-only\n\nWhat to inspect:\n- `openclaw plugins inspect <id>`\n- plugin `source`\n- plugin `origin`\n- plugin `version`\n- presence of `dist/`\n\n## 4. Install records drift from disk reality\n\nSymptom:\n- config or install registry says a plugin is installed\n- recorded path under `~/.openclaw/npm/node_modules/@openclaw/` or `~/.openclaw/extensions/` does not exist\n- plugin not found / phantom allowlist warnings\n\nWhat to inspect:\n- `~/.openclaw/plugins/installs.json`\n- actual install path on disk\n- `openclaw plugins registry --refresh`\n\nThis is the case where reinstalling the plugin is often correct.\n\n## 5. Third-party plugin runtime deps removed\n\nSymptom:\n- after `doctor --fix` or cleanup, a third-party plugin fails to load\n- error looks like `Cannot find module ...`\n- plugin root still exists, but plugin-side `node_modules` is gone\n\nWhat to inspect:\n- plugin package directory\n- plugin `package.json`\n- whether dependencies are externalized at build time\n\nWhy it matters:\n- cleanup can be too aggressive for non-bundled plugins\n\n## 6. Context engine not registered after restart\n\nSymptom:\n- logs say context engine falls back to legacy\n- plugin may still be installed but failed to initialize\n\nLook for:\n- plugin load errors\n- missing dependencies\n- plugin contract warnings\n- plugin registry metadata drift\n\n## 7. Event loop degradation after update\n\nSymptom"},{"path":"skill-card.md","content":"## Description:\n\nUse when updating OpenClaw or debugging an OpenClaw instance after an update. This skill acts as a structured update runbook with emphasis on gateway startup, service-manager state, plugin registry and install drift, bundled-vs-npm/clawhub plugin confusion, stale config carried across upgrades, channel health, task ledger corruption, and logs that explain why the updated system is slow, disconnected, or half-broken.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[bkf-gitty](https://clawhub.ai/user/bkf-gitty)\n\n### License/Terms of Use:\n\nMIT\n\n## Use Case:\n\nOperators and engineers use this skill to plan OpenClaw updates, diagnose post-update regressions, verify service and plugin state, and choose the smallest repair that returns a host to a healthy state.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Troubleshooting guidance can expose live channel tokens in terminal output, logs, or agent transcripts.\n\nMitigation: Do not run token-inspection commands that print raw values. If a token appears in a transcript, support ticket, log, or backup, rotate it and remove plaintext fallbacks after recovery.\n\nRisk: Update, restart, or configuration-edit steps can affect a live OpenClaw host.\n\nMitigation: Use the skill only for explicit OpenClaw maintenance tasks, require confirmation before updates, restarts, or config edits, and verify host state before and after changes.\n\n## Reference(s):\n\n- [ClawHub Skill Page](https://clawhub.ai/bkf-gitty/skills/claw-update-runbook)\n- [Failure Patterns](references/failure-patterns.md)\n- [README](README.md)\n\n## Skill Output:\n\n**Output Type(s):** [Guidance, Shell commands, Configuration]\n\n**Output Format:** [Markdown with inline shell commands and checklists]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Includes diagnostic sequences, verification criteria, and handoff-note guidance; does not execute commands itself.]\n\n## Skill Version(s):\n\n1.0.6 (source: frontmatter and server release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment."}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":null,"editorialQuality":{"score":100,"threshold":65,"status":"thin","wordCount":2039,"uniquenessScore":41,"reasons":["uniqueness-below-45"]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-11T16:20:44.716Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-11T16:20:44.716Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-11T20:57:50.579Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}