diff --git a/docs/help/faq.md b/docs/help/faq.md
index 4d4fb852855..e28549c9bd5 100644
--- a/docs/help/faq.md
+++ b/docs/help/faq.md
@@ -630,12 +630,16 @@ Quick answers plus deeper troubleshooting for real-world setups (local dev, VPS,
+
+
-
-That means your **Anthropic quota/rate limit** is exhausted for the current window. If you
-use **Claude CLI**, wait for the window to reset or upgrade your plan. If you
-use an **Anthropic API key**, check the Anthropic Console
-for usage/billing and raise limits as needed.
+
+
+
+ That means your **Anthropic quota/rate limit** is exhausted for the current window. If you
+ use **Claude CLI**, wait for the window to reset or upgrade your plan. If you
+ use an **Anthropic API key**, check the Anthropic Console
+ for usage/billing and raise limits as needed.
If the message is specifically:
`Extra usage is required for long context requests`, the request is trying to use
diff --git a/docs/help/troubleshooting.md b/docs/help/troubleshooting.md
index b9f5b98ae8d..f55074caa82 100644
--- a/docs/help/troubleshooting.md
+++ b/docs/help/troubleshooting.md
@@ -268,120 +268,120 @@ flowchart TD
- [/automation/cron-jobs#troubleshooting](/automation/cron-jobs#troubleshooting)
- [/gateway/heartbeat](/gateway/heartbeat)
-
+
-
- ```bash
- openclaw status
- openclaw gateway status
- openclaw nodes status
- openclaw nodes describe --node
- openclaw logs --follow
- ```
+
+ ```bash
+ openclaw status
+ openclaw gateway status
+ openclaw nodes status
+ openclaw nodes describe --node
+ openclaw logs --follow
+ ```
- Good output looks like:
+ Good output looks like:
- - Node is listed as connected and paired for role `node`.
- - Capability exists for the command you are invoking.
- - Permission state is granted for the tool.
+ - Node is listed as connected and paired for role `node`.
+ - Capability exists for the command you are invoking.
+ - Permission state is granted for the tool.
- Common log signatures:
+ Common log signatures:
- - `NODE_BACKGROUND_UNAVAILABLE` → bring node app to foreground.
- - `*_PERMISSION_REQUIRED` → OS permission was denied/missing.
- - `SYSTEM_RUN_DENIED: approval required` → exec approval is pending.
- - `SYSTEM_RUN_DENIED: allowlist miss` → command not on exec allowlist.
+ - `NODE_BACKGROUND_UNAVAILABLE` → bring node app to foreground.
+ - `*_PERMISSION_REQUIRED` → OS permission was denied/missing.
+ - `SYSTEM_RUN_DENIED: approval required` → exec approval is pending.
+ - `SYSTEM_RUN_DENIED: allowlist miss` → command not on exec allowlist.
- Deep pages:
+ Deep pages:
- - [/gateway/troubleshooting#node-paired-tool-fails](/gateway/troubleshooting#node-paired-tool-fails)
- - [/nodes/troubleshooting](/nodes/troubleshooting)
- - [/tools/exec-approvals](/tools/exec-approvals)
+ - [/gateway/troubleshooting#node-paired-tool-fails](/gateway/troubleshooting#node-paired-tool-fails)
+ - [/nodes/troubleshooting](/nodes/troubleshooting)
+ - [/tools/exec-approvals](/tools/exec-approvals)
-
+
-
- ```bash
- openclaw config get tools.exec.host
- openclaw config get tools.exec.security
- openclaw config get tools.exec.ask
- openclaw gateway restart
- ```
+
+ ```bash
+ openclaw config get tools.exec.host
+ openclaw config get tools.exec.security
+ openclaw config get tools.exec.ask
+ openclaw gateway restart
+ ```
- What changed:
+ What changed:
- - If `tools.exec.host` is unset, the default is `auto`.
- - `host=auto` resolves to `sandbox` when a sandbox runtime is active, `gateway` otherwise.
- - `host=auto` is routing only; the no-prompt "YOLO" behavior comes from `security=full` plus `ask=off` on gateway/node.
- - On `gateway` and `node`, unset `tools.exec.security` defaults to `full`.
- - Unset `tools.exec.ask` defaults to `off`.
- - Result: if you are seeing approvals, some host-local or per-session policy tightened exec away from the current defaults.
+ - If `tools.exec.host` is unset, the default is `auto`.
+ - `host=auto` resolves to `sandbox` when a sandbox runtime is active, `gateway` otherwise.
+ - `host=auto` is routing only; the no-prompt "YOLO" behavior comes from `security=full` plus `ask=off` on gateway/node.
+ - On `gateway` and `node`, unset `tools.exec.security` defaults to `full`.
+ - Unset `tools.exec.ask` defaults to `off`.
+ - Result: if you are seeing approvals, some host-local or per-session policy tightened exec away from the current defaults.
- Restore current default no-approval behavior:
+ Restore current default no-approval behavior:
- ```bash
- openclaw config set tools.exec.host gateway
- openclaw config set tools.exec.security full
- openclaw config set tools.exec.ask off
- openclaw gateway restart
- ```
+ ```bash
+ openclaw config set tools.exec.host gateway
+ openclaw config set tools.exec.security full
+ openclaw config set tools.exec.ask off
+ openclaw gateway restart
+ ```
- Safer alternatives:
+ Safer alternatives:
- - Set only `tools.exec.host=gateway` if you just want stable host routing.
- - Use `security=allowlist` with `ask=on-miss` if you want host exec but still want review on allowlist misses.
- - Enable sandbox mode if you want `host=auto` to resolve back to `sandbox`.
+ - Set only `tools.exec.host=gateway` if you just want stable host routing.
+ - Use `security=allowlist` with `ask=on-miss` if you want host exec but still want review on allowlist misses.
+ - Enable sandbox mode if you want `host=auto` to resolve back to `sandbox`.
- Common log signatures:
+ Common log signatures:
- - `Approval required.` → command is waiting on `/approve ...`.
- - `SYSTEM_RUN_DENIED: approval required` → node-host exec approval is pending.
- - `exec host=sandbox requires a sandbox runtime for this session` → implicit/explicit sandbox selection but sandbox mode is off.
+ - `Approval required.` → command is waiting on `/approve ...`.
+ - `SYSTEM_RUN_DENIED: approval required` → node-host exec approval is pending.
+ - `exec host=sandbox requires a sandbox runtime for this session` → implicit/explicit sandbox selection but sandbox mode is off.
- Deep pages:
+ Deep pages:
- - [/tools/exec](/tools/exec)
- - [/tools/exec-approvals](/tools/exec-approvals)
- - [/gateway/security#what-the-audit-checks-high-level](/gateway/security#what-the-audit-checks-high-level)
+ - [/tools/exec](/tools/exec)
+ - [/tools/exec-approvals](/tools/exec-approvals)
+ - [/gateway/security#what-the-audit-checks-high-level](/gateway/security#what-the-audit-checks-high-level)
-
+
-
- ```bash
- openclaw status
- openclaw gateway status
- openclaw browser status
- openclaw logs --follow
- openclaw doctor
- ```
+
+ ```bash
+ openclaw status
+ openclaw gateway status
+ openclaw browser status
+ openclaw logs --follow
+ openclaw doctor
+ ```
- Good output looks like:
+ Good output looks like:
- - Browser status shows `running: true` and a chosen browser/profile.
- - `openclaw` starts, or `user` can see local Chrome tabs.
+ - Browser status shows `running: true` and a chosen browser/profile.
+ - `openclaw` starts, or `user` can see local Chrome tabs.
- Common log signatures:
+ Common log signatures:
- - `unknown command "browser"` or `unknown command 'browser'` → `plugins.allow` is set and does not include `browser`.
- - `Failed to start Chrome CDP on port` → local browser launch failed.
- - `browser.executablePath not found` → configured binary path is wrong.
- - `browser.cdpUrl must be http(s) or ws(s)` → the configured CDP URL uses an unsupported scheme.
- - `browser.cdpUrl has invalid port` → the configured CDP URL has a bad or out-of-range port.
- - `No Chrome tabs found for profile="user"` → the Chrome MCP attach profile has no open local Chrome tabs.
- - `Remote CDP for profile "" is not reachable` → the configured remote CDP endpoint is not reachable from this host.
- - `Browser attachOnly is enabled ... not reachable` or `Browser attachOnly is enabled and CDP websocket ... is not reachable` → attach-only profile has no live CDP target.
- - stale viewport / dark-mode / locale / offline overrides on attach-only or remote CDP profiles → run `openclaw browser stop --browser-profile ` to close the active control session and release emulation state without restarting the gateway.
+ - `unknown command "browser"` or `unknown command 'browser'` → `plugins.allow` is set and does not include `browser`.
+ - `Failed to start Chrome CDP on port` → local browser launch failed.
+ - `browser.executablePath not found` → configured binary path is wrong.
+ - `browser.cdpUrl must be http(s) or ws(s)` → the configured CDP URL uses an unsupported scheme.
+ - `browser.cdpUrl has invalid port` → the configured CDP URL has a bad or out-of-range port.
+ - `No Chrome tabs found for profile="user"` → the Chrome MCP attach profile has no open local Chrome tabs.
+ - `Remote CDP for profile "" is not reachable` → the configured remote CDP endpoint is not reachable from this host.
+ - `Browser attachOnly is enabled ... not reachable` or `Browser attachOnly is enabled and CDP websocket ... is not reachable` → attach-only profile has no live CDP target.
+ - stale viewport / dark-mode / locale / offline overrides on attach-only or remote CDP profiles → run `openclaw browser stop --browser-profile ` to close the active control session and release emulation state without restarting the gateway.
- Deep pages:
+ Deep pages:
- - [/gateway/troubleshooting#browser-tool-fails](/gateway/troubleshooting#browser-tool-fails)
- - [/tools/browser#missing-browser-command-or-tool](/tools/browser#missing-browser-command-or-tool)
- - [/tools/browser-linux-troubleshooting](/tools/browser-linux-troubleshooting)
- - [/tools/browser-wsl2-windows-remote-cdp-troubleshooting](/tools/browser-wsl2-windows-remote-cdp-troubleshooting)
+ - [/gateway/troubleshooting#browser-tool-fails](/gateway/troubleshooting#browser-tool-fails)
+ - [/tools/browser#missing-browser-command-or-tool](/tools/browser#missing-browser-command-or-tool)
+ - [/tools/browser-linux-troubleshooting](/tools/browser-linux-troubleshooting)
+ - [/tools/browser-wsl2-windows-remote-cdp-troubleshooting](/tools/browser-wsl2-windows-remote-cdp-troubleshooting)
-
+
-
+
## Related
diff --git a/docs/tools/exec-approvals.md b/docs/tools/exec-approvals.md
index 75cd2c00e5c..b3809bfa262 100644
--- a/docs/tools/exec-approvals.md
+++ b/docs/tools/exec-approvals.md
@@ -304,73 +304,65 @@ allowlist entries for their non-stdin workflows. For `grep` in safe-bin mode,
provide the pattern with `-e`/`--regexp`; positional pattern form is rejected
so file operands cannot be smuggled as ambiguous positionals.
-
-
- Validation is deterministic from argv shape only (no host filesystem
- existence checks), which prevents file-existence oracle behavior from
- allow/deny differences. File-oriented options are denied for default safe
- bins; long options are validated fail-closed (unknown flags and ambiguous
- abbreviations are rejected).
+### Argv validation and denied flags
- Denied flags by safe-bin profile:
+Validation is deterministic from argv shape only (no host filesystem existence
+checks), which prevents file-existence oracle behavior from allow/deny
+differences. File-oriented options are denied for default safe bins; long
+options are validated fail-closed (unknown flags and ambiguous abbreviations are
+rejected).
- [//]: # "SAFE_BIN_DENIED_FLAGS:START"
+Denied flags by safe-bin profile:
+
+[//]: # "SAFE_BIN_DENIED_FLAGS:START"
- `grep`: `--dereference-recursive`, `--directories`, `--exclude-from`, `--file`, `--recursive`, `-R`, `-d`, `-f`, `-r`
- `jq`: `--argfile`, `--from-file`, `--library-path`, `--rawfile`, `--slurpfile`, `-L`, `-f`
- `sort`: `--compress-program`, `--files0-from`, `--output`, `--random-source`, `--temporary-directory`, `-T`, `-o`
- `wc`: `--files0-from`
- [//]: # "SAFE_BIN_DENIED_FLAGS:END"
+[//]: # "SAFE_BIN_DENIED_FLAGS:END"
- Safe bins also force argv tokens to be treated as **literal text** at
- execution time (no globbing and no `$VARS` expansion) for stdin-only
- segments, so patterns like `*` or `$HOME/...` cannot be used to smuggle
- file reads.
+Safe bins also force argv tokens to be treated as **literal text** at execution
+time (no globbing and no `$VARS` expansion) for stdin-only segments, so patterns
+like `*` or `$HOME/...` cannot be used to smuggle file reads.
-
+### Trusted binary directories
-
- Safe bins must resolve from trusted binary directories (system defaults
- plus optional `tools.exec.safeBinTrustedDirs`). `PATH` entries are never
- auto-trusted. Default trusted directories are intentionally minimal:
- `/bin`, `/usr/bin`. If your safe-bin executable lives in
- package-manager/user paths (for example `/opt/homebrew/bin`,
- `/usr/local/bin`, `/opt/local/bin`, `/snap/bin`), add them explicitly to
- `tools.exec.safeBinTrustedDirs`.
-
+Safe bins must resolve from trusted binary directories (system defaults plus
+optional `tools.exec.safeBinTrustedDirs`). `PATH` entries are never auto-trusted.
+Default trusted directories are intentionally minimal: `/bin`, `/usr/bin`. If
+your safe-bin executable lives in package-manager/user paths (for example
+`/opt/homebrew/bin`, `/usr/local/bin`, `/opt/local/bin`, `/snap/bin`), add them
+explicitly to `tools.exec.safeBinTrustedDirs`.
-
- Shell chaining (`&&`, `||`, `;`) is allowed when every top-level segment
- satisfies the allowlist (including safe bins or skill auto-allow).
- Redirections remain unsupported in allowlist mode. Command substitution
- (`$()` / backticks) is rejected during allowlist parsing, including inside
- double quotes; use single quotes if you need literal `$()` text.
+### Shell chaining, wrappers, and multiplexers
- On macOS companion-app approvals, raw shell text containing shell control
- or expansion syntax (`&&`, `||`, `;`, `|`, `` ` ``, `$`, `<`, `>`, `(`,
- `)`) is treated as an allowlist miss unless the shell binary itself is
- allowlisted.
+Shell chaining (`&&`, `||`, `;`) is allowed when every top-level segment
+satisfies the allowlist (including safe bins or skill auto-allow). Redirections
+remain unsupported in allowlist mode. Command substitution (`$()` / backticks) is
+rejected during allowlist parsing, including inside double quotes; use single
+quotes if you need literal `$()` text.
- For shell wrappers (`bash|sh|zsh ... -c/-lc`), request-scoped env
- overrides are reduced to a small explicit allowlist (`TERM`, `LANG`,
- `LC_*`, `COLORTERM`, `NO_COLOR`, `FORCE_COLOR`).
+On macOS companion-app approvals, raw shell text containing shell control or
+expansion syntax (`&&`, `||`, `;`, `|`, `` ` ``, `$`, `<`, `>`, `(`, `)`) is
+treated as an allowlist miss unless the shell binary itself is allowlisted.
- For `allow-always` decisions in allowlist mode, known dispatch wrappers
- (`env`, `nice`, `nohup`, `stdbuf`, `timeout`) persist the inner executable
- path instead of the wrapper path. Shell multiplexers (`busybox`, `toybox`)
- are unwrapped for shell applets (`sh`, `ash`, etc.) the same way. If a
- wrapper or multiplexer cannot be safely unwrapped, no allowlist entry is
- persisted automatically.
+For shell wrappers (`bash|sh|zsh ... -c/-lc`), request-scoped env overrides are
+reduced to a small explicit allowlist (`TERM`, `LANG`, `LC_*`, `COLORTERM`,
+`NO_COLOR`, `FORCE_COLOR`).
- If you allowlist interpreters like `python3` or `node`, prefer
- `tools.exec.strictInlineEval=true` so inline eval still requires an
- explicit approval. In strict mode, `allow-always` can still persist benign
- interpreter/script invocations, but inline-eval carriers are not persisted
- automatically.
+For `allow-always` decisions in allowlist mode, known dispatch wrappers (`env`,
+`nice`, `nohup`, `stdbuf`, `timeout`) persist the inner executable path instead
+of the wrapper path. Shell multiplexers (`busybox`, `toybox`) are unwrapped for
+shell applets (`sh`, `ash`, etc.) the same way. If a wrapper or multiplexer
+cannot be safely unwrapped, no allowlist entry is persisted automatically.
-
-
+If you allowlist interpreters like `python3` or `node`, prefer
+`tools.exec.strictInlineEval=true` so inline eval still requires an explicit
+approval. In strict mode, `allow-always` can still persist benign
+interpreter/script invocations, but inline-eval carriers are not persisted
+automatically.
### Safe bins versus allowlist
diff --git a/scripts/check-docs-mdx.mjs b/scripts/check-docs-mdx.mjs
index b44a7b76d30..3dfcce78447 100644
--- a/scripts/check-docs-mdx.mjs
+++ b/scripts/check-docs-mdx.mjs
@@ -119,8 +119,58 @@ function formatMdxError(filePath, error) {
};
}
+function checkMintlifyMdxStructure(filePath, raw) {
+ const errors = [];
+ const lines = stripFrontmatter(raw).split(/\r?\n/u);
+ const accordionStack = [];
+ let inCodeFence = false;
+
+ for (let index = 0; index < lines.length; index += 1) {
+ const line = lines[index];
+ if (/^\s*(```|~~~)/u.test(line)) {
+ inCodeFence = !inCodeFence;
+ continue;
+ }
+ if (inCodeFence) {
+ continue;
+ }
+
+ const openAccordion = line.match(/^(\s*)/u);
+ if (!closeAccordion) {
+ continue;
+ }
+
+ const opening = accordionStack.pop();
+ if (opening && closeAccordion[1].length > opening.indent) {
+ errors.push({
+ type: "mintlify-mdx",
+ file: filePath,
+ line: index + 1,
+ column: closeAccordion[1].length + 1,
+ message:
+ "Accordion closing tag is indented deeper than its opening tag; Mintlify can parse following markdown as nested content.",
+ });
+ }
+ }
+
+ return errors;
+}
+
async function checkMdxFile(filePath) {
const raw = fs.readFileSync(filePath, "utf8");
+ const structureErrors = checkMintlifyMdxStructure(filePath, raw);
+ if (structureErrors.length > 0) {
+ return structureErrors;
+ }
const value = stripFrontmatter(raw);
await compile(
{ path: filePath, value },
@@ -129,6 +179,7 @@ async function checkMdxFile(filePath) {
jsx: false,
},
);
+ return [];
}
function findDocsJsonPaths(roots) {
@@ -230,7 +281,7 @@ async function main() {
for (const file of files) {
try {
- await checkMdxFile(file);
+ errors.push(...(await checkMdxFile(file)));
} catch (error) {
errors.push(formatMdxError(file, error));
if (errors.length >= args.maxErrors) {