diff --git a/CHANGELOG.md b/CHANGELOG.md
index 99ae2bc526b..7201b58a72e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -88,6 +88,7 @@ Docs: https://docs.openclaw.ai
plain prompts instead of OpenClaw internal runtime-context envelopes, while
keeping those envelopes out of ACP transcripts.
- TTS/status: show configured TTS model, voice, and sanitized custom endpoint in `/status`, preserve OpenAI-compatible TTS instructions on custom endpoints, and retry empty Microsoft/Edge TTS output once. Addresses #46602, #47232, and #43936. Thanks @leekuangtao, @Huntterxx, and @rex993.
+- Agents/Gateway: steer agent-driven config edits and restarts through the owner-only `gateway` tool, document `config.schema.lookup` as the field-doc source, and warn against using `gateway stop && gateway start` as a restart substitute on macOS. Fixes #71929. Thanks @ygc3817922006-sketch.
- Providers/vLLM: send Nemotron 3 chat-template kwargs when thinking is off
and honor configured `params.chat_template_kwargs` for OpenAI-compatible
completions, so vLLM/Nemotron replies stay visible instead of becoming
diff --git a/docs/cli/gateway.md b/docs/cli/gateway.md
index 3237ac2aab4..4c2cf07954a 100644
--- a/docs/cli/gateway.md
+++ b/docs/cli/gateway.md
@@ -324,6 +324,7 @@ Command options:
Notes:
- `gateway install` supports `--port`, `--runtime`, `--token`, `--force`, `--json`.
+- Use `gateway restart` to restart a managed service. Do not chain `gateway stop` and `gateway start` as a restart substitute; on macOS, `gateway stop` intentionally disables the LaunchAgent before stopping it.
- When token auth requires a token and `gateway.auth.token` is SecretRef-managed, `gateway install` validates that the SecretRef is resolvable but does not persist the resolved token into service environment metadata.
- If token auth requires a token and the configured token SecretRef is unresolved, install fails closed instead of persisting fallback plaintext.
- For password auth on `gateway run`, prefer `OPENCLAW_GATEWAY_PASSWORD`, `--password-file`, or a SecretRef-backed `gateway.auth.password` over inline `--password`.
diff --git a/docs/concepts/system-prompt.md b/docs/concepts/system-prompt.md
index 40521da24d7..660632f82b9 100644
--- a/docs/concepts/system-prompt.md
+++ b/docs/concepts/system-prompt.md
@@ -214,6 +214,10 @@ stale. The prompt also notes the public docs mirror, community Discord, and Claw
([https://clawhub.ai](https://clawhub.ai)) for skills discovery. It tells the model to
consult docs first for OpenClaw behavior, commands, configuration, or architecture, and to
run `openclaw status` itself when possible (asking the user only when it lacks access).
+For configuration specifically, it points agents to the `gateway` tool action
+`config.schema.lookup` for exact field-level docs and constraints, then to
+`docs/gateway/configuration.md` and `docs/gateway/configuration-reference.md`
+for broader guidance.
## Related
diff --git a/docs/gateway/configuration-reference.md b/docs/gateway/configuration-reference.md
index 26a930ec22f..8c8402affee 100644
--- a/docs/gateway/configuration-reference.md
+++ b/docs/gateway/configuration-reference.md
@@ -16,6 +16,11 @@ Code truth:
- `config.schema.lookup` returns one path-scoped schema node for drill-down tooling
- `pnpm config:docs:check` / `pnpm config:docs:gen` validate the config-doc baseline hash against the current schema surface
+Agent lookup path: use the `gateway` tool action `config.schema.lookup` for
+exact field-level docs and constraints before edits. Use
+[Configuration](/gateway/configuration) for task-oriented guidance and this page
+for the broader field map, defaults, and links to subsystem references.
+
Dedicated deep references:
- [Memory configuration reference](/reference/memory-config) for `agents.defaults.memorySearch.*`, `memory.qmd.*`, `memory.citations`, and dreaming config under `plugins.entries.memory-core.config.dreaming`
diff --git a/docs/gateway/configuration.md b/docs/gateway/configuration.md
index 14cd62e331c..2d944edb481 100644
--- a/docs/gateway/configuration.md
+++ b/docs/gateway/configuration.md
@@ -21,6 +21,11 @@ If the file is missing, OpenClaw uses safe defaults. Common reasons to add a con
See the [full reference](/gateway/configuration-reference) for every available field.
+Agents and automation should use `config.schema.lookup` for exact field-level
+docs before editing config. Use this page for task-oriented guidance and
+[Configuration reference](/gateway/configuration-reference) for the broader
+field map and defaults.
+
**New to configuration?** Start with `openclaw onboard` for interactive setup, or check out the [Configuration Examples](/gateway/configuration-examples) guide for complete copy-paste configs.
@@ -575,6 +580,11 @@ For tooling that writes config over the gateway API, prefer this flow:
- `config.apply` only when you intend to replace the entire config
- `update.run` for explicit self-update plus restart
+Agents should treat `config.schema.lookup` as the first stop for exact
+field-level docs and constraints. Use [Configuration reference](/gateway/configuration-reference)
+when they need the broader config map, defaults, or links to dedicated
+subsystem references.
+
Control-plane writes (`config.apply`, `config.patch`, `update.run`) are
rate-limited to 3 requests per 60 seconds per `deviceId+clientIp`. Restart
diff --git a/docs/gateway/index.md b/docs/gateway/index.md
index 8af2ee77c6e..d527be86dd8 100644
--- a/docs/gateway/index.md
+++ b/docs/gateway/index.md
@@ -251,6 +251,8 @@ openclaw gateway restart
openclaw gateway stop
```
+Use `openclaw gateway restart` for restarts. Do not chain `openclaw gateway stop` and `openclaw gateway start`; on macOS, `gateway stop` intentionally disables the LaunchAgent before stopping it.
+
LaunchAgent labels are `ai.openclaw.gateway` (default) or `ai.openclaw.` (named profile). `openclaw doctor` audits and repairs service config drift.
diff --git a/docs/tools/index.md b/docs/tools/index.md
index 53842f0c7f0..7e2d1293f01 100644
--- a/docs/tools/index.md
+++ b/docs/tools/index.md
@@ -95,6 +95,8 @@ active runtime model label from the latest transcript usage entry.
For partial changes, prefer `config.schema.lookup` then `config.patch`. Use
`config.apply` only when you intentionally replace the entire config.
+For broader config docs, read [Configuration](/gateway/configuration) and
+[Configuration reference](/gateway/configuration-reference).
The tool also refuses to change `tools.exec.ask` or `tools.exec.security`;
legacy `tools.bash.*` aliases normalize to the same protected exec paths.
diff --git a/src/agents/openclaw-gateway-tool.test.ts b/src/agents/openclaw-gateway-tool.test.ts
index 3a14533d021..9daffdeb3cc 100644
--- a/src/agents/openclaw-gateway-tool.test.ts
+++ b/src/agents/openclaw-gateway-tool.test.ts
@@ -25,6 +25,29 @@ function requireGatewayTool(agentSessionKey?: string) {
});
}
+function collectActionValues(schema: unknown, values: Set): void {
+ if (!schema || typeof schema !== "object") {
+ return;
+ }
+
+ const record = schema as Record;
+ if (typeof record.const === "string") {
+ values.add(record.const);
+ }
+ if (Array.isArray(record.enum)) {
+ for (const value of record.enum) {
+ if (typeof value === "string") {
+ values.add(value);
+ }
+ }
+ }
+ if (Array.isArray(record.anyOf)) {
+ for (const variant of record.anyOf) {
+ collectActionValues(variant, values);
+ }
+ }
+}
+
function expectConfigMutationCall(params: {
callGatewayTool: {
mock: {
@@ -96,6 +119,19 @@ describe("gateway tool", () => {
expect(tool.ownerOnly).toBe(true);
});
+ it("exposes restart and config actions in the gateway tool schema", async () => {
+ const tool = requireGatewayTool();
+ const parameters = tool.parameters as {
+ properties?: Record;
+ };
+ const values = new Set();
+ collectActionValues(parameters.properties?.action, values);
+
+ expect([...values]).toEqual(
+ expect.arrayContaining(["restart", "config.get", "config.patch", "config.apply"]),
+ );
+ });
+
it("schedules SIGUSR1 restart", async () => {
const kill = vi.spyOn(process, "kill").mockImplementation(() => true);
const restartSignalKillCalls = () =>
diff --git a/src/agents/pi-tools.create-openclaw-coding-tools.test.ts b/src/agents/pi-tools.create-openclaw-coding-tools.test.ts
index f7d90fac9ab..1b4193ce1c3 100644
--- a/src/agents/pi-tools.create-openclaw-coding-tools.test.ts
+++ b/src/agents/pi-tools.create-openclaw-coding-tools.test.ts
@@ -86,6 +86,25 @@ function expectNoSubagentControlTools(tools: ReturnType {
const testConfig: OpenClawConfig = {};
+ it("exposes gateway config and restart actions to owner sessions", () => {
+ const tools = createOpenClawCodingTools({ config: testConfig, senderIsOwner: true });
+ const gateway = tools.find((tool) => tool.name === "gateway");
+ expect(gateway).toBeDefined();
+
+ const parameters = gateway?.parameters as {
+ properties?: Record;
+ };
+ const action = parameters.properties?.action as
+ | { const?: unknown; enum?: unknown[] }
+ | undefined;
+ const values = new Set();
+ collectActionValues(action, values);
+
+ expect([...values]).toEqual(
+ expect.arrayContaining(["restart", "config.get", "config.patch", "config.apply"]),
+ );
+ });
+
it("preserves action enums in normalized schemas", () => {
const defaultTools = createOpenClawCodingTools({ config: testConfig, senderIsOwner: true });
const toolNames = ["canvas", "nodes", "cron", "gateway", "message"];
diff --git a/src/agents/system-prompt.test.ts b/src/agents/system-prompt.test.ts
index 35c56877dc1..f2ea67fd90e 100644
--- a/src/agents/system-prompt.test.ts
+++ b/src/agents/system-prompt.test.ts
@@ -226,10 +226,27 @@ describe("buildAgentSystemPrompt", () => {
});
expect(prompt).toContain("## OpenClaw CLI Quick Reference");
+ expect(prompt).toContain("use the first-class `gateway` tool");
+ expect(prompt).toContain(
+ "Only use CLI service lifecycle commands when the user explicitly asks",
+ );
expect(prompt).toContain("openclaw gateway restart");
+ expect(prompt).toContain("Do not chain `openclaw gateway stop`");
expect(prompt).toContain("Do not invent commands");
});
+ it("points agents to config field docs and broader configuration docs", () => {
+ const prompt = buildAgentSystemPrompt({
+ workspaceDir: "/tmp/openclaw",
+ docsPath: "/tmp/openclaw/docs",
+ });
+
+ expect(prompt).toContain("For config field docs");
+ expect(prompt).toContain("`gateway` tool action `config.schema.lookup`");
+ expect(prompt).toContain("docs/gateway/configuration.md");
+ expect(prompt).toContain("docs/gateway/configuration-reference.md");
+ });
+
it("guides runtime completion events without exposing internal metadata", () => {
const prompt = buildAgentSystemPrompt({
workspaceDir: "/tmp/openclaw",
@@ -559,6 +576,7 @@ describe("buildAgentSystemPrompt", () => {
expect(prompt).toContain("config.schema.lookup");
expect(prompt).toContain("config.apply");
expect(prompt).toContain("config.patch");
+ expect(prompt).toContain("Config writes hot-reload when possible");
expect(prompt).toContain("update.run");
expect(prompt).not.toContain("Use config.schema to");
expect(prompt).not.toContain("config.schema, config.apply");
diff --git a/src/agents/system-prompt.ts b/src/agents/system-prompt.ts
index 315152ab832..2f91cc155fd 100644
--- a/src/agents/system-prompt.ts
+++ b/src/agents/system-prompt.ts
@@ -422,6 +422,7 @@ function buildDocsSection(params: {
docsPath
? "For OpenClaw behavior, commands, config, or architecture: consult local docs first."
: "For OpenClaw behavior, commands, config, or architecture: consult the docs mirror first.",
+ "For config field docs, prefer the `gateway` tool action `config.schema.lookup`; for broader config guidance, read `docs/gateway/configuration.md` and `docs/gateway/configuration-reference.md`.",
sourcePath
? "If docs are incomplete or stale, inspect the local OpenClaw source code before answering."
: "If docs are incomplete or stale, review the OpenClaw source on GitHub before answering.",
@@ -784,11 +785,15 @@ export function buildAgentSystemPrompt(params: {
...safetySection,
"## OpenClaw CLI Quick Reference",
"OpenClaw is controlled via subcommands. Do not invent commands.",
- "To manage the Gateway daemon service (start/stop/restart):",
+ "For config changes, use the first-class `gateway` tool (`config.schema.lookup`, `config.get`, `config.patch`, `config.apply`) instead of editing config through exec; the gateway tool hot-reloads config when possible and uses a safe restart only when required.",
+ "Use the `gateway` tool action `restart` for Gateway restarts. Only use CLI service lifecycle commands when the user explicitly asks for them.",
+ "Gateway service lifecycle quick reference:",
"- openclaw gateway status",
+ "- openclaw gateway restart",
+ "Operator-only, explicit user request:",
"- openclaw gateway start",
"- openclaw gateway stop",
- "- openclaw gateway restart",
+ "Do not chain `openclaw gateway stop` and `openclaw gateway start` as a restart substitute.",
"If unsure, ask the user to run `openclaw help` (or `openclaw gateway --help`) and paste the output.",
"",
...skillsSection,
@@ -800,7 +805,7 @@ export function buildAgentSystemPrompt(params: {
"Get Updates (self-update) is ONLY allowed when the user explicitly asks for it.",
"Do not run config.apply or update.run unless the user explicitly requests an update or config change; if it's not explicit, ask first.",
"Use config.schema.lookup with a specific dot path to inspect only the relevant config subtree before making config changes or answering config-field questions; avoid guessing field names/types.",
- "Actions: config.schema.lookup, config.get, config.apply (validate + write full config, then restart), config.patch (partial update, merges with existing), update.run (update deps or git, then restart).",
+ "Actions: config.schema.lookup, config.get, config.patch (partial update, merges with existing), config.apply (validate + write full config), update.run (update deps or git, then restart). Config writes hot-reload when possible and use a safe restart only when required.",
"After restart, OpenClaw pings the last active session automatically.",
].join("\n")
: "",
diff --git a/src/agents/test-helpers/fast-openclaw-tools.ts b/src/agents/test-helpers/fast-openclaw-tools.ts
index bfaff6c89f7..aa71bacc98c 100644
--- a/src/agents/test-helpers/fast-openclaw-tools.ts
+++ b/src/agents/test-helpers/fast-openclaw-tools.ts
@@ -22,7 +22,14 @@ const coreTools = [
stubActionTool("nodes", ["list", "invoke"]),
stubActionTool("cron", ["schedule", "cancel"]),
stubActionTool("message", ["send", "reply"]),
- stubActionTool("gateway", ["status"]),
+ stubActionTool("gateway", [
+ "restart",
+ "config.get",
+ "config.schema.lookup",
+ "config.apply",
+ "config.patch",
+ "update.run",
+ ]),
stubActionTool("agents_list", ["list", "show"]),
stubActionTool("sessions_list", ["list", "show"]),
stubActionTool("sessions_history", ["read", "tail"]),