feat(agents): narrow gateway tool to read-only config

Phase 3 of #107237. Removes config.apply/config.patch/restart from the
regular-agent gateway tool (mirroring Phase 2's update.run removal); only
config.get and config.schema.lookup reads remain. Persistent config changes
and restarts now go exclusively through the human-approved openclaw
delegation path — closing the last unmediated agent config-write surface.
gateway stays owner-only/control-plane gated (config reads expose secrets and
host topology). Legacy setups can re-enable writes via the existing per-agent
tool allowlist; no new config key. Net -2271 LOC.

Refs #107237
This commit is contained in:
Peter Steinberger
2026-07-14 19:23:24 -07:00
parent ea1b524d8d
commit a97bdfb687
30 changed files with 134 additions and 2406 deletions
@@ -1148,62 +1148,22 @@
},
{
"deferLoading": true,
"description": "Gateway restart/config/update. Before config edit: config.schema.lookup exact dot path. Partial merge: config.patch; full replace only: config.apply. Removing array entries via patch needs exact array replacePaths. Writes hot-reload/restart as needed. Always human note for post-restart delivery. Internal continuation: one-shot continuationMessage; its visible follow-up uses message tool. Never write restart sentinel directly.",
"description": "Read gateway config + schema. Writes/restart: use openclaw tool.",
"inputSchema": {
"properties": {
"action": {
"enum": [
"restart",
"config.get",
"config.schema.lookup",
"config.apply",
"config.patch",
"update.run"
],
"enum": ["config.get", "config.schema.lookup"],
"type": "string"
},
"baseHash": {
"type": "string"
},
"continuationMessage": {
"type": "string"
},
"delayMs": {
"minimum": 0,
"type": "integer"
},
"gatewayToken": {
"type": "string"
},
"gatewayUrl": {
"type": "string"
},
"note": {
"type": "string"
},
"path": {
"type": "string"
},
"raw": {
"type": "string"
},
"reason": {
"type": "string"
},
"replacePaths": {
"items": {
"type": "string"
},
"maxItems": 256,
"type": "array"
},
"restartDelayMs": {
"minimum": 0,
"type": "integer"
},
"sessionKey": {
"type": "string"
},
"timeoutMs": {
"minimum": 1,
"type": "integer"
@@ -1180,62 +1180,22 @@
},
{
"deferLoading": true,
"description": "Gateway restart/config/update. Before config edit: config.schema.lookup exact dot path. Partial merge: config.patch; full replace only: config.apply. Removing array entries via patch needs exact array replacePaths. Writes hot-reload/restart as needed. Always human note for post-restart delivery. Internal continuation: one-shot continuationMessage; its visible follow-up uses message tool. Never write restart sentinel directly.",
"description": "Read gateway config + schema. Writes/restart: use openclaw tool.",
"inputSchema": {
"properties": {
"action": {
"enum": [
"restart",
"config.get",
"config.schema.lookup",
"config.apply",
"config.patch",
"update.run"
],
"enum": ["config.get", "config.schema.lookup"],
"type": "string"
},
"baseHash": {
"type": "string"
},
"continuationMessage": {
"type": "string"
},
"delayMs": {
"minimum": 0,
"type": "integer"
},
"gatewayToken": {
"type": "string"
},
"gatewayUrl": {
"type": "string"
},
"note": {
"type": "string"
},
"path": {
"type": "string"
},
"raw": {
"type": "string"
},
"reason": {
"type": "string"
},
"replacePaths": {
"items": {
"type": "string"
},
"maxItems": 256,
"type": "array"
},
"restartDelayMs": {
"minimum": 0,
"type": "integer"
},
"sessionKey": {
"type": "string"
},
"timeoutMs": {
"minimum": 1,
"type": "integer"
@@ -1144,62 +1144,22 @@
},
{
"deferLoading": true,
"description": "Gateway restart/config/update. Before config edit: config.schema.lookup exact dot path. Partial merge: config.patch; full replace only: config.apply. Removing array entries via patch needs exact array replacePaths. Writes hot-reload/restart as needed. Always human note for post-restart delivery. Internal continuation: one-shot continuationMessage; its visible follow-up uses message tool. Never write restart sentinel directly.",
"description": "Read gateway config + schema. Writes/restart: use openclaw tool.",
"inputSchema": {
"properties": {
"action": {
"enum": [
"restart",
"config.get",
"config.schema.lookup",
"config.apply",
"config.patch",
"update.run"
],
"enum": ["config.get", "config.schema.lookup"],
"type": "string"
},
"baseHash": {
"type": "string"
},
"continuationMessage": {
"type": "string"
},
"delayMs": {
"minimum": 0,
"type": "integer"
},
"gatewayToken": {
"type": "string"
},
"gatewayUrl": {
"type": "string"
},
"note": {
"type": "string"
},
"path": {
"type": "string"
},
"raw": {
"type": "string"
},
"reason": {
"type": "string"
},
"replacePaths": {
"items": {
"type": "string"
},
"maxItems": 256,
"type": "array"
},
"restartDelayMs": {
"minimum": 0,
"type": "integer"
},
"sessionKey": {
"type": "string"
},
"timeoutMs": {
"minimum": 1,
"type": "integer"
@@ -208,8 +208,8 @@ This is the deterministic model-bound layer stack OpenClaw can snapshot for the
"roughTokens": 0
},
"dynamicToolsJson": {
"chars": 52583,
"roughTokens": 13146
"chars": 52524,
"roughTokens": 13131
},
"openClawDeveloperInstructions": {
"chars": 3431,
@@ -220,8 +220,8 @@ This is the deterministic model-bound layer stack OpenClaw can snapshot for the
"roughTokens": 6989
},
"totalWithDynamicToolsJson": {
"chars": 80541,
"roughTokens": 20136
"chars": 80482,
"roughTokens": 20121
},
"userInputText": {
"chars": 1442,
@@ -208,8 +208,8 @@ This is the deterministic model-bound layer stack OpenClaw can snapshot for the
"roughTokens": 0
},
"dynamicToolsJson": {
"chars": 52310,
"roughTokens": 13078
"chars": 52251,
"roughTokens": 13063
},
"openClawDeveloperInstructions": {
"chars": 2322,
@@ -220,8 +220,8 @@ This is the deterministic model-bound layer stack OpenClaw can snapshot for the
"roughTokens": 6610
},
"totalWithDynamicToolsJson": {
"chars": 78750,
"roughTokens": 19688
"chars": 78691,
"roughTokens": 19673
},
"userInputText": {
"chars": 1033,
@@ -209,8 +209,8 @@ This is the deterministic model-bound layer stack OpenClaw can snapshot for the
"roughTokens": 0
},
"dynamicToolsJson": {
"chars": 53600,
"roughTokens": 13400
"chars": 53541,
"roughTokens": 13386
},
"openClawDeveloperInstructions": {
"chars": 2341,
@@ -221,8 +221,8 @@ This is the deterministic model-bound layer stack OpenClaw can snapshot for the
"roughTokens": 6745
},
"totalWithDynamicToolsJson": {
"chars": 80579,
"roughTokens": 20145
"chars": 80520,
"roughTokens": 20130
},
"userInputText": {
"chars": 1271,