openclaw - ✅(Solved) Fix Schema doesn't expose hot-reload vs restart-required behavior for config fields [2 pull requests, 2 comments, 3 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#81409Fetched 2026-05-14 03:32:35
View on GitHub
Comments
2
Participants
3
Timeline
4
Reactions
2
Timeline (top)
commented ×2cross-referenced ×2

The runtime config schema (runtime-schema-OL6hE5dN.js) does not expose whether changing a given config path triggers a hot reload, requires a gateway restart, or is a no-op. This information exists internally (config-reload-plan-CT3ozyNA.js's BASE_RELOAD_RULES + matchRule()), but is not surfaced via openclaw config schema, gateway.config.schema.lookup, or any requiresRestart/reloadKind field hint.

As a result, agents and humans must change a config field, watch the gateway log, and observe [reload] config change requires gateway restart (...) to learn the field's reload policy — which is essentially trial-and-error.

Error Message

As a result, agents and humans must change a config field, watch the gateway log, and observe [reload] config change requires gateway restart (...) to learn the field's reload policy — which is essentially trial-and-error.

Root Cause

For automated agents (the primary consumer of the schema), the absence of this metadata means we have to:

  • Encode field-by-field restart knowledge in our own runbooks (LRN-066-style learning entries)
  • Trigger a deferred restart for every config patch, then observe logs
  • Keep "default to restart" as a hard-coded fallback policy

Surfacing reload behavior would let agents reason about restart impact before applying the patch, schedule restarts more thoughtfully, and reduce log-grep noise.

Fix Action

Fix / Workaround

  1. Change any field that the schema describes neutrally (e.g. gateway.handshakeTimeoutMs):
    echo '{"gateway":{"handshakeTimeoutMs":30000}}' | openclaw config patch --stdin

For automated agents (the primary consumer of the schema), the absence of this metadata means we have to:

  • Encode field-by-field restart knowledge in our own runbooks (LRN-066-style learning entries)
  • Trigger a deferred restart for every config patch, then observe logs
  • Keep "default to restart" as a hard-coded fallback policy

Surfacing reload behavior would let agents reason about restart impact before applying the patch, schedule restarts more thoughtfully, and reduce log-grep noise.

PR fix notes

PR #81574: Expose reload kind in config schema lookup

Description (problem / solution / changelog)

Summary

Describe the problem and fix in 2–5 bullets:

  • Problem: config.schema.lookup exposed field schema and UI hints, but not whether changing the field can hot-reload or requires a Gateway restart.
  • Why it matters: users and tools could not tell from schema lookup whether config changes like gateway.handshakeTimeoutMs are hot-reloadable or restart-required.
  • What changed: lookup results and immediate child summaries now include optional reloadKind metadata (restart, hot, or none) resolved through the existing config reload rule matcher.
  • What did NOT change (scope boundary): this does not alter config patch behavior, reload planning semantics, the full generated JSON schema, or add a second reload rule table.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #81409
  • Related #
  • This PR fixes a bug or regression

Real behavior proof (required for external PRs)

  • Behavior or issue addressed: config.schema.lookup now reports the reload behavior for a looked-up config path and its immediate children.
  • Real environment tested: local OpenClaw checkout, isolated dev Gateway using HOME=/tmp/oc81409-pr-home, port 19809, built from this branch.
  • Exact steps or command run after this patch:
pnpm build:strict-smoke
HOME=/tmp/oc81409-pr-home node openclaw.mjs gateway run --dev --auth none --port 19809 --tailscale off --allow-unconfigured
TOKEN=$(node -e "console.log(require('/tmp/oc81409-pr-home/.openclaw/openclaw.json').gateway.auth.token)")
HOME=/tmp/oc81409-pr-home node openclaw.mjs gateway call --url ws://127.0.0.1:19809 --token "$TOKEN" --json --params '{"path":"gateway.handshakeTimeoutMs"}' config.schema.lookup
HOME=/tmp/oc81409-pr-home node openclaw.mjs gateway call --url ws://127.0.0.1:19809 --token "$TOKEN" --json --params '{"path":"gateway"}' config.schema.lookup
  • Evidence after fix (screenshot, recording, terminal capture, console output, redacted runtime log, linked artifact, or copied live output):
{
  "path": "gateway.handshakeTimeoutMs",
  "schema": {
    "type": "integer",
    "minimum": 1,
    "maximum": 9007199254740991,
    "title": "Gateway Handshake Timeout",
    "description": "Pre-auth Gateway WebSocket handshake timeout in milliseconds. Use higher values on loaded or low-powered hosts where local clients can connect during startup warmup. OPENCLAW_HANDSHAKE_TIMEOUT_MS still takes precedence."
  },
  "reloadKind": "restart",
  "hint": {
    "label": "Gateway Handshake Timeout",
    "help": "Pre-auth Gateway WebSocket handshake timeout in milliseconds. Use higher values on loaded or low-powered hosts where local clients can connect during startup warmup. OPENCLAW_HANDSHAKE_TIMEOUT_MS still takes precedence.",
    "tags": ["network", "performance"]
  },
  "hintPath": "gateway.handshakeTimeoutMs",
  "children": []
}
{
  "path": "gateway",
  "reloadKind": "restart",
  "children": [
    {
      "path": "gateway.handshakeTimeoutMs",
      "reloadKind": "restart"
    },
    {
      "path": "gateway.channelHealthCheckMinutes",
      "reloadKind": "hot"
    }
  ]
}
  • Observed result after fix: restart-required and hot-reloadable fields are distinguishable through config.schema.lookup.
  • What was not tested: plugin-provided reload metadata beyond existing config-reload unit coverage.
  • Before evidence (optional but encouraged): issue #81409 documents that the same lookup output did not expose hot-reload vs restart-required behavior.

Root Cause (if applicable)

  • Root cause: schema lookup and config reload planning were implemented as separate paths. lookupConfigSchema() returned schema/UI hint metadata only, while restart/hot/no-op decisions lived in config-reload-plan.ts.
  • Missing detection / guardrail: no lookup-level test asserted that reload planning metadata was surfaced to schema consumers.
  • Contributing context (if known): config patch planning already had this information, but schema lookup had no resolver hook to reuse it.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/config/schema.test.ts
  • Scenario the test should lock in: when a reload metadata resolver is provided, lookupConfigSchema() includes reloadKind on the looked-up path and child summaries.
  • Why this is the smallest reliable guardrail: it validates the schema lookup behavior without requiring a live Gateway or duplicating reload plan tests.
  • Existing test that already covers this (if any): src/gateway/config-reload.test.ts covers the reload rule semantics themselves.
  • If no new test is added, why not: N/A; a test was added.

User-visible / Behavior Changes

config.schema.lookup responses now include optional reloadKind metadata for the requested path and immediate children.

Diagram (if applicable)

Before:
config.schema.lookup -> schema + UI hints

After:
config.schema.lookup -> schema + UI hints + reloadKind from existing reload rules

Security Impact (required)

  • New permissions/capabilities? (Yes/No) No
  • Secrets/tokens handling changed? (Yes/No) No
  • New/changed network calls? (Yes/No) No
  • Command/tool execution surface changed? (Yes/No) No
  • Data access scope changed? (Yes/No) No
  • If any Yes, explain risk + mitigation: N/A

Repro + Verification

Environment

  • OS: Linux 6.8.0-111-generic x64
  • Runtime/container: local Node.js v24.13.0, isolated dev Gateway with HOME=/tmp/oc81409-pr-home
  • Model/provider: N/A
  • Integration/channel (if any): Gateway RPC / CLI
  • Relevant config (redacted): dev config generated under /tmp/oc81409-pr-home/.openclaw/openclaw.json; Gateway token used locally only and not included here.

Steps

  1. Build the local checkout with pnpm build:strict-smoke.
  2. Start a dev Gateway from this branch with isolated HOME and port 19809.
  3. Call config.schema.lookup for gateway.handshakeTimeoutMs.
  4. Call config.schema.lookup for gateway and inspect child summaries.

Expected

  • gateway.handshakeTimeoutMs reports reloadKind: "restart".
  • gateway.channelHealthCheckMinutes appears in child summaries with reloadKind: "hot".

Actual

  • Matches expected output shown in the Real behavior proof section.

Evidence

Attach at least one:

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Targeted checks run locally:

node scripts/run-vitest.mjs run --config test/vitest/vitest.runtime-config.config.ts src/config/schema.test.ts
# 34 passed

node scripts/run-vitest.mjs run --config test/vitest/vitest.gateway.config.ts src/gateway/config-reload.test.ts
# 73 passed

pnpm tsgo:test
# passed

pnpm build:strict-smoke
# passed

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios:
    • gateway.handshakeTimeoutMs lookup now returns reloadKind: "restart".
    • gateway lookup child summaries include both restart-required and hot-reloadable children.
    • Existing reload rule tests still pass.
  • Edge cases checked:
    • Resolver is optional, so existing direct schema lookup callers can continue without reload metadata.
    • Metadata is attached only to lookup result/children, avoiding a broader full-schema contract change.
  • What you did not verify:
    • Plugin-provided reload rule metadata through a third-party plugin runtime.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.

Compatibility / Migration

  • Backward compatible? (Yes/No) Yes
  • Config/env changes? (Yes/No) No
  • Migration needed? (Yes/No) No
  • If yes, exact upgrade steps: N/A

Risks and Mitigations

  • Risk: schema lookup consumers may ignore the new optional field.
    • Mitigation: field is additive and optional.
  • Risk: reload metadata could diverge if a second rule source were introduced.
    • Mitigation: this PR reuses the existing reload rule matcher instead of duplicating rules.

AI-assisted disclosure

This PR was prepared with AI assistance. I reviewed the change, understand the code path, and ran the local verification listed above.

Changed files

  • .agents/maintainer-notes/telegram.md (added, +37/-0)
  • .agents/skills/clawdtributor/SKILL.md (added, +159/-0)
  • .agents/skills/clawsweeper/SKILL.md (added, +340/-0)
  • .agents/skills/clawsweeper/agents/openai.yaml (added, +4/-0)
  • .agents/skills/crabbox/SKILL.md (added, +591/-0)
  • .agents/skills/discord-clawd/SKILL.md (added, +37/-0)
  • .agents/skills/discord-clawd/agents/openai.yaml (added, +4/-0)
  • .agents/skills/gitcrawl/SKILL.md (added, +68/-0)
  • .agents/skills/gitcrawl/agents/openai.yaml (added, +4/-0)
  • .agents/skills/openclaw-debugging/SKILL.md (added, +114/-0)
  • .agents/skills/openclaw-debugging/agents/openai.yaml (added, +4/-0)
  • .agents/skills/openclaw-docs/SKILL.md (added, +238/-0)
  • .agents/skills/openclaw-ghsa-maintainer/SKILL.md (added, +87/-0)
  • .agents/skills/openclaw-parallels-smoke/SKILL.md (added, +164/-0)
  • .agents/skills/openclaw-pr-maintainer/SKILL.md (added, +227/-0)
  • .agents/skills/openclaw-pr-maintainer/scripts/github-activity.sh (added, +178/-0)
  • .agents/skills/openclaw-pre-release-plugin-testing/SKILL.md (added, +234/-0)
  • .agents/skills/openclaw-pre-release-plugin-testing/agents/openai.yaml (added, +4/-0)
  • .agents/skills/openclaw-qa-testing/SKILL.md (added, +269/-0)
  • .agents/skills/openclaw-qa-testing/agents/openai.yaml (added, +4/-0)
  • .agents/skills/openclaw-refactor-docs/SKILL.md (added, +196/-0)
  • .agents/skills/openclaw-release-maintainer/SKILL.md (added, +625/-0)
  • .agents/skills/openclaw-secret-scanning-maintainer/SKILL.md (added, +220/-0)
  • .agents/skills/openclaw-secret-scanning-maintainer/scripts/secret-scanning.mjs (added, +797/-0)
  • .agents/skills/openclaw-small-bugfix-sweep/SKILL.md (added, +77/-0)
  • .agents/skills/openclaw-test-heap-leaks/SKILL.md (added, +109/-0)
  • .agents/skills/openclaw-test-heap-leaks/agents/openai.yaml (added, +4/-0)
  • .agents/skills/openclaw-test-heap-leaks/scripts/heapsnapshot-delta.mjs (added, +553/-0)
  • .agents/skills/openclaw-test-performance/SKILL.md (added, +266/-0)
  • .agents/skills/openclaw-test-performance/agents/openai.yaml (added, +6/-0)
  • .agents/skills/openclaw-testing/SKILL.md (added, +644/-0)
  • .agents/skills/openclaw-testing/agents/openai.yaml (added, +4/-0)
  • .agents/skills/optimizetests/SKILL.md (added, +41/-0)
  • .agents/skills/optimizetests/agents/openai.yaml (added, +6/-0)
  • .agents/skills/parallels-discord-roundtrip/SKILL.md (added, +63/-0)
  • .agents/skills/security-triage/SKILL.md (added, +140/-0)
  • .agents/skills/tag-duplicate-prs-issues/SKILL.md (added, +439/-0)
  • .agents/skills/tag-duplicate-prs-issues/agents/openai.yaml (added, +4/-0)
  • .agents/skills/telegram-crabbox-e2e-proof/SKILL.md (added, +196/-0)
  • .crabbox.yaml (added, +46/-0)
  • .dockerignore (added, +78/-0)
  • .env.example (added, +95/-0)
  • .gitattributes (added, +3/-0)
  • .github/CODEOWNERS (added, +58/-0)
  • .github/ISSUE_TEMPLATE/bug_report.yml (added, +148/-0)
  • .github/ISSUE_TEMPLATE/config.yml (added, +8/-0)
  • .github/ISSUE_TEMPLATE/feature_request.yml (added, +70/-0)
  • .github/actionlint.yaml (added, +27/-0)
  • .github/actions/detect-docs-changes/action.yml (added, +53/-0)
  • .github/actions/docker-e2e-plan/action.yml (added, +152/-0)
  • .github/actions/ensure-base-commit/action.yml (added, +61/-0)
  • .github/actions/setup-node-env/action.yml (added, +110/-0)
  • .github/actions/setup-pnpm-store-cache/action.yml (added, +91/-0)
  • .github/codeql/codeql-actions-critical-security.yml (added, +21/-0)
  • .github/codeql/codeql-agent-runtime-boundary-critical-quality.yml (added, +53/-0)
  • .github/codeql/codeql-android-critical-security.yml (added, +30/-0)
  • .github/codeql/codeql-channel-runtime-boundary-critical-quality.yml (added, +55/-0)
  • .github/codeql/codeql-channel-runtime-boundary-critical-security.yml (added, +48/-0)
  • .github/codeql/codeql-config-boundary-critical-quality.yml (added, +33/-0)
  • .github/codeql/codeql-core-auth-secrets-critical-quality.yml (added, +53/-0)
  • .github/codeql/codeql-core-auth-secrets-critical-security.yml (added, +55/-0)
  • .github/codeql/codeql-gateway-runtime-boundary-critical-quality.yml (added, +37/-0)
  • .github/codeql/codeql-macos-critical-security.yml (added, +17/-0)
  • .github/codeql/codeql-mcp-process-runtime-boundary-critical-quality.yml (added, +35/-0)
  • .github/codeql/codeql-mcp-process-tool-boundary-critical-security.yml (added, +56/-0)
  • .github/codeql/codeql-memory-runtime-boundary-critical-quality.yml (added, +41/-0)
  • .github/codeql/codeql-network-runtime-boundary-critical-quality.yml (added, +28/-0)
  • .github/codeql/codeql-network-ssrf-boundary-critical-security.yml (added, +41/-0)
  • .github/codeql/codeql-plugin-boundary-critical-quality.yml (added, +75/-0)
  • .github/codeql/codeql-plugin-sdk-package-contract-critical-quality.yml (added, +36/-0)
  • .github/codeql/codeql-plugin-sdk-reply-runtime-critical-quality.yml (added, +44/-0)
  • .github/codeql/codeql-plugin-trust-boundary-critical-security.yml (added, +86/-0)
  • .github/codeql/codeql-provider-runtime-boundary-critical-quality.yml (added, +44/-0)
  • .github/codeql/codeql-session-diagnostics-boundary-critical-quality.yml (added, +48/-0)
  • .github/codeql/codeql-ui-control-plane-critical-quality.yml (added, +36/-0)
  • .github/codeql/codeql-web-media-runtime-boundary-critical-quality.yml (added, +39/-0)
  • .github/codeql/openclaw-boundary/codeql-pack.lock.yml (added, +30/-0)
  • .github/codeql/openclaw-boundary/qlpack.yml (added, +6/-0)
  • .github/codeql/openclaw-boundary/queries/managed-proxy-runtime-mutation.ql (added, +325/-0)
  • .github/codeql/openclaw-boundary/queries/raw-socket-callsite-classification.ql (added, +92/-0)
  • .github/codex/prompts/docs-agent.md (added, +33/-0)
  • .github/codex/prompts/docs-mdx-repair.md (added, +25/-0)
  • .github/codex/prompts/mantis-telegram-desktop-proof.md (added, +98/-0)
  • .github/codex/prompts/test-performance-agent.md (added, +44/-0)
  • .github/dependabot.yml (added, +127/-0)
  • .github/images/live-media-runner/Dockerfile (added, +16/-0)
  • .github/instructions/copilot.instructions.md (added, +64/-0)
  • .github/labeler.yml (added, +544/-0)
  • .github/pull_request_template.md (added, +159/-0)
  • .github/workflows/auto-response.yml (added, +55/-0)
  • .github/workflows/ci-build-artifacts-testbox.yml (added, +227/-0)
  • .github/workflows/ci-check-testbox.yml (added, +129/-0)
  • .github/workflows/ci.yml (added, +2175/-0)
  • .github/workflows/clawsweeper-dispatch.yml (added, +289/-0)
  • .github/workflows/codeql-android-critical-security.yml (added, +51/-0)
  • .github/workflows/codeql-critical-quality.yml (added, +691/-0)
  • .github/workflows/codeql-macos-critical-security.yml (added, +89/-0)
  • .github/workflows/codeql.yml (added, +92/-0)
  • .github/workflows/control-ui-locale-refresh.yml (added, +172/-0)
  • .github/workflows/crabbox-hydrate.yml (added, +183/-0)

PR #81612: Expose reload kind in config schema lookup

Description (problem / solution / changelog)

Summary

Replacement for closed PR #81574. The earlier branch/PR metadata became corrupted after a bad force-push from a shallow/grafted local state and showed the whole repository as added. This replacement branch is rebuilt directly on current origin/main and GitHub compare reports only the intended 10 files (+78/-6).

Describe the problem and fix in 2–5 bullets:

  • Problem: config.schema.lookup exposed field schema and UI hints, but not whether changing the field can hot-reload or requires a Gateway restart.
  • Why it matters: users and tools could not tell from schema lookup whether config changes like gateway.handshakeTimeoutMs are hot-reloadable or restart-required.
  • What changed: lookup results and immediate child summaries now include optional reloadKind metadata (restart, hot, or none) resolved through the existing config reload rule matcher.
  • What did NOT change (scope boundary): this does not alter config patch behavior, reload planning semantics, the full generated JSON schema, or add a second reload rule table.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #81409
  • Related #
  • This PR fixes a bug or regression

Real behavior proof (required for external PRs)

  • Behavior or issue addressed: config.schema.lookup now reports the reload behavior for a looked-up config path and its immediate children.
  • Real environment tested: local OpenClaw checkout, isolated dev Gateway using HOME=/tmp/oc81409-pr-home, port 19809, built from this branch.
  • Exact steps or command run after this patch:
pnpm build:strict-smoke
HOME=/tmp/oc81409-pr-home node openclaw.mjs gateway run --dev --auth none --port 19809 --tailscale off --allow-unconfigured
TOKEN=$(node -e "console.log(require('/tmp/oc81409-pr-home/.openclaw/openclaw.json').gateway.auth.token)")
HOME=/tmp/oc81409-pr-home node openclaw.mjs gateway call --url ws://127.0.0.1:19809 --token "$TOKEN" --json --params '{"path":"gateway.handshakeTimeoutMs"}' config.schema.lookup
HOME=/tmp/oc81409-pr-home node openclaw.mjs gateway call --url ws://127.0.0.1:19809 --token "$TOKEN" --json --params '{"path":"gateway"}' config.schema.lookup
  • Evidence after fix (screenshot, recording, terminal capture, console output, redacted runtime log, linked artifact, or copied live output):
{
  "path": "gateway.handshakeTimeoutMs",
  "schema": {
    "type": "integer",
    "minimum": 1,
    "maximum": 9007199254740991,
    "title": "Gateway Handshake Timeout",
    "description": "Pre-auth Gateway WebSocket handshake timeout in milliseconds. Use higher values on loaded or low-powered hosts where local clients can connect during startup warmup. OPENCLAW_HANDSHAKE_TIMEOUT_MS still takes precedence."
  },
  "reloadKind": "restart",
  "hint": {
    "label": "Gateway Handshake Timeout",
    "help": "Pre-auth Gateway WebSocket handshake timeout in milliseconds. Use higher values on loaded or low-powered hosts where local clients can connect during startup warmup. OPENCLAW_HANDSHAKE_TIMEOUT_MS still takes precedence.",
    "tags": ["network", "performance"]
  },
  "hintPath": "gateway.handshakeTimeoutMs",
  "children": []
}
{
  "path": "gateway",
  "reloadKind": "restart",
  "children": [
    {
      "path": "gateway.handshakeTimeoutMs",
      "reloadKind": "restart"
    },
    {
      "path": "gateway.channelHealthCheckMinutes",
      "reloadKind": "hot"
    }
  ]
}
  • Observed result after fix: restart-required and hot-reloadable fields are distinguishable through config.schema.lookup.
  • What was not tested: plugin-provided reload metadata beyond existing config-reload unit coverage.
  • Before evidence (optional but encouraged): issue #81409 documents that the same lookup output did not expose hot-reload vs restart-required behavior.

Root Cause (if applicable)

  • Root cause: schema lookup and config reload planning were implemented as separate paths. lookupConfigSchema() returned schema/UI hint metadata only, while restart/hot/no-op decisions lived in config-reload-plan.ts.
  • Missing detection / guardrail: no lookup-level test asserted that reload planning metadata was surfaced to schema consumers.
  • Contributing context (if known): config patch planning already had this information, but schema lookup had no resolver hook to reuse it.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/config/schema.test.ts
  • Scenario the test should lock in: when a reload metadata resolver is provided, lookupConfigSchema() includes reloadKind on the looked-up path and child summaries.
  • Why this is the smallest reliable guardrail: it validates the schema lookup behavior without requiring a live Gateway or duplicating reload plan tests.
  • Existing test that already covers this (if any): src/gateway/config-reload.test.ts covers the reload rule semantics themselves.
  • If no new test is added, why not: N/A; a test was added.

User-visible / Behavior Changes

config.schema.lookup responses now include optional reloadKind metadata for the requested path and immediate children.

Diagram (if applicable)

Before:
config.schema.lookup -> schema + UI hints

After:
config.schema.lookup -> schema + UI hints + reloadKind from existing reload rules

Security Impact (required)

  • New permissions/capabilities? (Yes/No) No
  • Secrets/tokens handling changed? (Yes/No) No
  • New/changed network calls? (Yes/No) No
  • Command/tool execution surface changed? (Yes/No) No
  • Data access scope changed? (Yes/No) No
  • If any Yes, explain risk + mitigation: N/A

Repro + Verification

Environment

  • OS: Linux 6.8.0-111-generic x64
  • Runtime/container: local Node.js v24.13.0, isolated dev Gateway with HOME=/tmp/oc81409-pr-home
  • Model/provider: N/A
  • Integration/channel (if any): Gateway RPC / CLI
  • Relevant config (redacted): dev config generated under /tmp/oc81409-pr-home/.openclaw/openclaw.json; Gateway token used locally only and not included here.

Steps

  1. Build the local checkout with pnpm build:strict-smoke.
  2. Start a dev Gateway from this branch with isolated HOME and port 19809.
  3. Call config.schema.lookup for gateway.handshakeTimeoutMs.
  4. Call config.schema.lookup for gateway and inspect child summaries.

Expected

  • gateway.handshakeTimeoutMs reports reloadKind: "restart".
  • gateway.channelHealthCheckMinutes appears in child summaries with reloadKind: "hot".

Actual

  • Matches expected output shown in the Real behavior proof section.

Evidence

Attach at least one:

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Targeted checks run locally:

node scripts/run-vitest.mjs run --config test/vitest/vitest.runtime-config.config.ts src/config/schema.test.ts
# 34 passed

node scripts/run-vitest.mjs run --config test/vitest/vitest.gateway.config.ts src/gateway/config-reload.test.ts
# 73 passed

pnpm tsgo:test
# passed

pnpm build:strict-smoke
# passed

OPENCLAW_VITEST_INCLUDE_FILE=/tmp/plugin-contract-include-81574.json node scripts/run-vitest.mjs run --config test/vitest/vitest.contracts-plugin.config.ts --maxWorkers=1
# plugin-sdk-package-contract-guardrails.test.ts: 17 passed

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios:
    • gateway.handshakeTimeoutMs lookup now returns reloadKind: "restart".
    • gateway lookup child summaries include both restart-required and hot-reloadable children.
    • Existing reload rule tests still pass.
  • Edge cases checked:
    • Resolver is optional, so existing direct schema lookup callers can continue without reload metadata.
    • Metadata is attached only to lookup result/children, avoiding a broader full-schema contract change.
  • What you did not verify:
    • Plugin-provided reload rule metadata through a third-party plugin runtime.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.

Compatibility / Migration

  • Backward compatible? (Yes/No) Yes
  • Config/env changes? (Yes/No) No
  • Migration needed? (Yes/No) No
  • If yes, exact upgrade steps: N/A

Risks and Mitigations

  • Risk: schema lookup consumers may ignore the new optional field.
    • Mitigation: field is additive and optional.
  • Risk: reload metadata could diverge if a second rule source were introduced.
    • Mitigation: this PR reuses the existing reload rule matcher instead of duplicating rules.

AI-assisted disclosure

This PR was prepared with AI assistance. I reviewed the change, understand the code path, and ran the local verification listed above.

Changed files

  • apps/shared/OpenClawKit/Sources/OpenClawProtocol/GatewayModels.swift (modified, +4/-0)
  • docs/gateway/protocol.md (modified, +1/-1)
  • docs/plugins/sdk-subpaths.md (modified, +5/-3)
  • src/config/schema.test.ts (modified, +21/-0)
  • src/config/schema.ts (modified, +19/-1)
  • src/gateway/config-reload-plan.ts (modified, +11/-0)
  • src/gateway/config-reload.test.ts (modified, +7/-0)
  • src/gateway/config-reload.ts (modified, +2/-0)
  • src/gateway/protocol/schema/config.ts (modified, +6/-0)
  • src/gateway/server-methods/config.ts (modified, +2/-1)

Code Example

echo '{"gateway":{"handshakeTimeoutMs":30000}}' | openclaw config patch --stdin

---

[reload] config change requires gateway restart (gateway.handshakeTimeoutMs) — deferring until ...

---

{
     "label": "Gateway Handshake Timeout",
     "help": "Pre-auth Gateway WebSocket handshake timeout in milliseconds...",
     "tags": ["network", "performance"]
   }

---

for (const path of changedPaths) {
  const rule = matchRule(path);
  if (!rule) {
    plan.restartGateway = true;       // default: any unmatched path triggers restart
    plan.restartReasons.push(path);
    continue;
  }
  if (rule.kind === "restart") { /* explicit restart */ }
  else if (rule.kind === "none") { /* no-op */ }
  else { /* hot reload via actions */ }
}

---

{
  "label": "Gateway Handshake Timeout",
  "help": "...",
  "tags": ["network", "performance"],
  "reloadKind": "restart"  // or "hot" / "none"
}
RAW_BUFFERClick to expand / collapse

Summary

The runtime config schema (runtime-schema-OL6hE5dN.js) does not expose whether changing a given config path triggers a hot reload, requires a gateway restart, or is a no-op. This information exists internally (config-reload-plan-CT3ozyNA.js's BASE_RELOAD_RULES + matchRule()), but is not surfaced via openclaw config schema, gateway.config.schema.lookup, or any requiresRestart/reloadKind field hint.

As a result, agents and humans must change a config field, watch the gateway log, and observe [reload] config change requires gateway restart (...) to learn the field's reload policy — which is essentially trial-and-error.

Repro

  1. Change any field that the schema describes neutrally (e.g. gateway.handshakeTimeoutMs):

    echo '{"gateway":{"handshakeTimeoutMs":30000}}' | openclaw config patch --stdin
  2. The CLI prints "Restart the gateway to apply." and the log shows:

    [reload] config change requires gateway restart (gateway.handshakeTimeoutMs) — deferring until ...
  3. Inspect the schema for the same field via gateway.config.schema.lookup action or openclaw config schema:

    {
      "label": "Gateway Handshake Timeout",
      "help": "Pre-auth Gateway WebSocket handshake timeout in milliseconds...",
      "tags": ["network", "performance"]
    }

    No indication that this field requires a restart.

Examples of fields hit during 5-13 troubleshooting (one operator, one day)

FieldSchema hint mentions restart?Actual behavior
gateway.handshakeTimeoutMsNoRestart required
memory.qmd.limits.timeoutMsNoRestart required (deferred auto-restart)
agents.defaults.memorySearch.providerNoRestart required
agents.defaults.memorySearch.fallbackNoRestart required

We see this pattern at least 5 times per LRN-066 in our internal log (memory-config-default-restart recurrence).

Root cause (from dist source reading)

config-reload-plan-CT3ozyNA.js line ~344:

for (const path of changedPaths) {
  const rule = matchRule(path);
  if (!rule) {
    plan.restartGateway = true;       // default: any unmatched path triggers restart
    plan.restartReasons.push(path);
    continue;
  }
  if (rule.kind === "restart") { /* explicit restart */ }
  else if (rule.kind === "none") { /* no-op */ }
  else { /* hot reload via actions */ }
}

So the reload policy is essentially:

  • Explicit rule (restart / hot / none / restart-channel:X) for paths matched by BASE_RELOAD_RULES + plugin-contributed prefixes
  • Default = restart for everything else

This information would be valuable to surface in schema metadata.

Proposed solutions (pick one or combine)

1. Add reloadKind to schema field hints (most aligned with current schema structure):

{
  "label": "Gateway Handshake Timeout",
  "help": "...",
  "tags": ["network", "performance"],
  "reloadKind": "restart"  // or "hot" / "none"
}

2. Expose the reload-rules table separately via a new CLI/RPC, e.g. openclaw config reload-rules that prints the matched policy for each known prefix.

3. Document the "default = restart" rule in docs/gateway/configuration.md so users know unmatched fields require restart by convention.

Why this matters

For automated agents (the primary consumer of the schema), the absence of this metadata means we have to:

  • Encode field-by-field restart knowledge in our own runbooks (LRN-066-style learning entries)
  • Trigger a deferred restart for every config patch, then observe logs
  • Keep "default to restart" as a hard-coded fallback policy

Surfacing reload behavior would let agents reason about restart impact before applying the patch, schedule restarts more thoughtfully, and reduce log-grep noise.

Environment

  • OpenClaw version: 2026.5.7 (eeef486)
  • Node: v24.14.1
  • Platform: Darwin 25.3.0 (arm64)

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix Schema doesn't expose hot-reload vs restart-required behavior for config fields [2 pull requests, 2 comments, 3 participants]