#Creating skills
78 messages · Page 1 of 1 (latest)
I think the main issue is the filename.
SKILL.md is case-sensitive.
If you created ~/.openclaw/skills/<skill_name>/SKILL.MD, OpenClaw will usually not discover it on Linux/macOS. Rename it to:
~/.openclaw/skills/<skill_name>/SKILL.md
A few other gotchas here:
-
“requires installation” but no buttons
- That usually means your skill has
metadata.openclaw.requires... - but does not have
metadata.openclaw.install - missing requirements can be shown without any install action
- That usually means your skill has
-
missing binaries: openon the node
openis a macOS-only binary- if that node is Linux, use
xdg-openinstead, or gate the skill with:metadata: {"openclaw":{"os":["darwin"]}}
- if that node is Linux, use
- CLI doesn’t list the skill
- most common causes:
- wrong filename case (
SKILL.MDvsSKILL.md) - invalid frontmatter
- wrong folder
- wrong filename case (
- most common causes:
Minimum valid frontmatter:
---
name: my_skill
description: What this skill does
---
After fixing it, start a new session or restart the gateway, then check:
openclaw --version
openclaw skills list --verbose
openclaw skills check --json
Docs:
If you paste your SKILL.md, I can sanity-check it fast.
---
name: seo-page-builder
description: Build an SEO-optimized HTML page from a user topic and an existing donor page. Use when the user wants competitor research, SEO structure and keywords, article text generation, or a new page assembled from an existing page design.
metadata:
openclaw:
os: ["darwin"]
requires:
bins:
- curl
- unzip
- open
anyBins:
- node
emoji: "🚀"
---
- How to install open on macos
- How to enable slash command
A few things are colliding here.
-
You do not install
openon macOSopenis built into macOS, normally at/usr/bin/open- so if OpenClaw says
missing binaries: open, that usually means:- that machine is not actually macOS
- or the node host has a weird
PATH
Quick check on the Mac/node host:
which open echo $PATH -
Your
metadataformat is wrong for skills- for OpenClaw skills,
metadatashould be a single-line JSON/JSON5 object, not nested YAML
- for OpenClaw skills,
So use this instead:
---
name: seo-page-builder
description: Build an SEO-optimized HTML page from a user topic and an existing donor page.
metadata: {"openclaw":{"os":["darwin"],"requires":{"bins":["curl","unzip","open"],"anyBins":["node"]},"emoji":"🚀"}}
user-invocable: true
---
-
Filename matters
- it must be exactly
SKILL.md - not
SKILL.MD
- it must be exactly
-
Why there are no install buttons
- buttons only show up if you define
metadata.openclaw.install
- buttons only show up if you define
requiresalone only marks the skill as missing requirements
- Slash commands
- once the skill is loaded, the generic command should work:
/skill seo-page-builder - the direct native command on Discord will be sanitized, so this name becomes:
/seo_page_builder - if native skill commands are disabled, enable:
{ commands: { nativeSkills: true }, channels: { discord: { commands: { nativeSkills: true } } } }
- once the skill is loaded, the generic command should work:
(`auto` is normally enough on Discord)
If it still doesn’t show up after fixing the file, paste:
```bash
openclaw --version
openclaw skills list --verbose
openclaw skills check --json
Docs:
Agent answer:
I got stuck with accessing the Mac node: I can't open a browser on your Mac from this session, and the skill is tied specifically to ChatGPT in the browser and further assembly via Mac/Codex.
{
"command": "open -a 'Google Chrome' 'https://chat.openai.com'",
"host": "node",
"node": "MacBook Pro",
"security": "allowlist",
"ask": "on-miss",
"yieldMs": 5000
}
{
"status": "error",
"tool": "exec",
"error": "exec node not allowed (bound to 76526ff3f25550ae6df5354e16c56dc9eafe3bfe84ffc530bed65566cdbe0480)"
}
I have two nodes on one macbook.
6f1e541dd94c5a90db49d8576c0ad17f744401155486d440b737ce8cbe63f40c (Mac app):
client: openclaw-macos/node · device: Mac · hw: MacBookPro18,1 · browser, canvas, screen. perms: [accessibility=yes, appleScript=yes, camera=no, location=no, microphone=yes, notifications=yes, screenRecording=yes, speechRecognition=yes] · ui v2026.4.11
76526ff3f25550ae6df5354e16c56dc9eafe3bfe84ffc530bed65566cdbe0480 (Mac exec):
client: node-host/node · core v2026.4.11 · path: /opt/homebrew, Cellar/node/25.9.0_2/bin:/usr/bin:…:/Users/user/.yarn/bin. caps: browser, system
I would like to give "Mac exec" all possible permissions and caps.
Short version: you can’t turn the headless Mac exec node into the full Mac app node.
Those are two different node types, and caps are exposed by the node implementation, not by a permission toggle.
What’s going on:
-
That exec error is just node binding
- your session is bound to
76526f...(Mac exec) - the tool call tried
node: "MacBook Pro"(the other node) - so OpenClaw rejected it with:
exec node not allowed (bound to 76526f...)
- your session is bound to
-
“All possible permissions/caps”
- not really possible for the headless node host
screen,canvas, camera/TCC-style stuff belongs to the Mac app node- the headless node host is mainly for
system.run/system.whichstyle exec
-
What you can do
-
make the
Mac execnode run commands through the Mac app- on the Mac node-host service, set:
OPENCLAW_NODE_EXEC_HOST=app OPENCLAW_NODE_EXEC_FALLBACK=0 - then restart the node host
That’s the supported way to get exec routed through the app’s macOS/TCC context.
- on the Mac node-host service, set:
- If you want the exec node to stop prompting / be fully permissive
- set node approvals to full/off:
openclaw approvals set --node 76526ff3f25550ae6df5354e16c56dc9eafe3bfe84ffc530bed65566cdbe0480 --stdin <<'EOF' { version: 1, defaults: {
- set node approvals to full/off:
security: "full",
ask: "off",
askFallback: "full"
}
}
EOF
```
- and align requested policy too:
openclaw config set tools.exec.host node openclaw config set tools.exec.node "76526ff3f25550ae6df5354e16c56dc9eafe3bfe84ffc530bed65566cdbe0480" openclaw config set tools.exec.security full openclaw config set tools.exec.ask off
- If you want to target the other node instead
- change or unset the exec binding:
openclaw config unset tools.exec.node
```
or bind it to the app node explicitly.
So the real answer is:
- **No**, you can’t make `Mac exec` gain every Mac app capability.
- **Yes**, you can make `Mac exec` forward `system.run` through the Mac app, which is probably what you actually want.
Docs:
- <https://docs.openclaw.ai/nodes/index>
- <https://docs.openclaw.ai/platforms/macos>
- <https://docs.openclaw.ai/cli/approvals>
If you want, paste:
openclaw --version
openclaw approvals get --node 76526ff3f25550ae6df5354e16c56dc9eafe3bfe84ffc530bed65566cdbe0480
and I can tell you the exact clean setup.
Where should I insert it?
OPENCLAW_NODE_EXEC_HOST=app
OPENCLAW_NODE_EXEC_FALLBACK=0
version: OpenClaw 2026.4.12 (1c0672b)
scope: tools.exec
requested: security=full (tools.exec.security) ask=off (tools.exec.ask)
Host: security=full, ask=off, askFallback=full
Effective: security=full, ask=off
Notes: requested security applies; requested ask applies
Put them on the Mac that runs the node-host service, not in SKILL.md.
If Mac exec was installed with openclaw node install, the clean place is:
~/.openclaw/.env
Add:
OPENCLAW_NODE_EXEC_HOST=app
OPENCLAW_NODE_EXEC_FALLBACK=0
Then restart the node host:
openclaw node restart
If you run the node in the foreground instead of as a service, do it inline:
OPENCLAW_NODE_EXEC_HOST=app OPENCLAW_NODE_EXEC_FALLBACK=0 openclaw node run ...
A couple of important notes:
- Do not put these in
SKILL.md - Do not put them under
openclaw.json - your approvals are already fine, this output shows
security=full, ask=off, so the remaining issue is routing/host mode, not approvals
So the shortest path is:
- edit
~/.openclaw/.envon that Mac - add those 2 vars
- run
openclaw node restart
If you want, I can also give you the exact “sanity check” commands to confirm it picked them up after restart.
yes, give me
Yep, here’s a clean sanity-check sequence.
1) Confirm the env vars are in place on the Mac
rg 'OPENCLAW_NODE_EXEC_(HOST|FALLBACK)' ~/.openclaw/.env
You want to see:
OPENCLAW_NODE_EXEC_HOST=app
OPENCLAW_NODE_EXEC_FALLBACK=0
2) Restart the node-host service
openclaw node restart
3) Make sure the node comes back
openclaw nodes status
4) Inspect the exact exec node
openclaw nodes describe --node 76526ff3f25550ae6df5354e16c56dc9eafe3bfe84ffc530bed65566cdbe0480
5) Check that the Mac can resolve open
openclaw nodes invoke --node 76526ff3f25550ae6df5354e16c56dc9eafe3bfe84ffc530bed65566cdbe0480 --command system.which --params '{"name":"open"}'
You should get something like /usr/bin/open.
6) Confirm your exec binding is pointed at the right node
openclaw config get tools.exec.node
If it’s wrong, set it:
openclaw config set tools.exec.node "76526ff3f25550ae6df5354e16c56dc9eafe3bfe84ffc530bed65566cdbe0480"
7) End-to-end test from chat
Then in chat, ask the agent to run something tiny on the node, for example:
run `which open && sw_vers` with host=node
If you want, paste the output of steps 4 and 5 and I’ll tell you immediately whether it’s wired correctly.
openclaw nodes describe --node 76526ff3f25550ae6df5354e16c56dc9eafe3bfe84ffc530bed65566cdbe0480
ID │ 76526ff3f25550ae6df5354e16c56dc9eafe3bfe84ffc530bed65566cdbe0480 Name │ MacBook Pro Client │ node-host/node Version │ core v2026.4.11 PATH │ /opt/homebrew/Cellar/node/25.9.0_2/bin:/usr/bin:/bin:/opt/homebrew/opt/node/bin:/Users/user/.nvm:/Users/user/.local/bin:/Users/user/.npm-global/bin:/Users/user/bin:/Users/user/.volta/bin:/Users/user/.asdf/shims:/Users/user/.bun/bin:/Users/user/Library/Application Support/fnm/aliases/default/bin:/Users/user/.fnm/aliases/default/bin:/Users/user/Library/pnpm:/Users/user/.local/share/pnpm:/opt/homebrew/bin:/usr/local/bin:/Users/user/.yarn/bin
Status │ paired · connected Caps │ browser, system
- nodes invoke failed: GatewayClientRequestError: INVALID_REQUEST: Error: INVALID_REQUEST: bins required
Nice, this actually tells us a lot.
Your node looks healthy:
- it’s paired + connected
PATHincludes/usr/bin- so
openshould be available on that Mac
The nodes invoke failure is just the wrong payload shape.
For system.which, this runtime expects bins, not name.
Try this:
openclaw nodes invoke --node 76526ff3f25550ae6df5354e16c56dc9eafe3bfe84ffc530bed65566cdbe0480 --command system.which --params '{"bins":["open","curl","unzip","node"]}'
If that returns paths, then the node side is fine and the problem is back in the skill itself.
At that point, double-check these 3 things:
-
filename is exactly:
~/.openclaw/skills/seo-page-builder/SKILL.mdnot
SKILL.MD -
metadata is inline JSON5, for example:
--- name: seo-page-builder description: Build an SEO-optimized HTML page from a user topic and an existing donor page. metadata: {"openclaw":{"os":["darwin"],"requires":{"bins":["curl","unzip","open"],"anyBins":["node"]},"emoji":"🚀"}}
user-invocable: true
---
- start a new session or restart the gateway again
So, I’m pretty confident now that the missing-binary issue is not your Mac exec node, it’s the skill discovery/parsing path. If you paste the output of that system.which call, I can confirm it.
Agent answer:
I tried, but the problem is the same: The Mac is visible as paired/connected, but the browser proxy is unavailable from this session, and exec to the desired node is not allowed here.
That is, now the blocker is not in the skill, but in the access route to the node/browser.
What can be done:
either I continue without a Mac and build the SEO page manually here,
or you fix node access first, and I immediately repeat full flow.
If you want to fix access, I can further help diagnose this as a node/browser connectivity issue.
Yep, that answer means you’ve moved past skill discovery and hit a runtime routing problem.
My honest take: opening ChatGPT in Chrome from a skill is the wrong shape for OpenClaw. It’s brittle, and now you’re fighting node binding + browser proxy + exec routing all at once.
So there are really two paths:
Better path, recommended
Make the skill OpenClaw-native instead of browser-driven:
- research:
web_search+web_fetch - inspect donor page:
web_fetchorbrowser - build HTML locally
- if you need Codex, use the ACP harness, not chat.openai.com in Chrome
That removes the whole Mac/browser binding mess.
Current path, if you keep the browser flow
Then yes, the blocker is now:
- browser access on the right node
- exec bound to the right node
- both being usable in the same run
That’s a node/browser plumbing problem, not a SKILL.md format problem anymore.
So, good news: your skill parsing issue is basically solved.
Bad news: the skill design is still fighting the platform.
If you want, paste the full skill and I’ll rewrite it into a cleaner OpenClaw-native version that avoids the browser dependency entirely.
I have a theme and a donor URL, but I don't have access to execute commands on my MacBook Pro from this session, so I can't honestly run seo-page-builder locally, as the skill requires.
There are 2 normal ways:
I'll try to raise a separate ACP/Codex session on node if you want me to continue on my own.
I'll give you a ready-made local command set/script that will run the entire pipeline on your Mac.
I recommend option 1 if you want to be as “turnkey" as possible. Just write: "try using ACP."
I want the skill to use the codex cli command on the node.
Then I would not use ACP for this.
If your requirement is specifically:
run the
codexCLI on the node
then the skill should be built around exec host=node, because ACP sessions run on the host/gateway runtime, not the paired node.
So the shape should be:
- drop browser/
open - drop ACP
- require
codexon the node - instruct the model to use
execwithhost=node
Something closer to this:
---
name: seo-page-builder
description: Build an SEO-optimized HTML page from a topic and donor URL by running Codex CLI on the paired node.
metadata: {"openclaw":{"os":["darwin"],"requires":{"anyBins":["codex"],"bins":["curl","unzip"]},"emoji":"🚀"}}
user-invocable: true
---
# SEO Page Builder
When the user provides a theme and donor URL:
1. Use `web_fetch` or `curl` to inspect the donor page.
2. Use `exec` with `host=node` on the configured node.
3. Run the `codex` CLI on that node to generate/refine the page.
4. Return the resulting HTML and a short summary of what was built.
Important:
- Do not use browser automation unless the user explicitly asks for it.
- Do not open chat.openai.com.
- Prefer the node-host Codex CLI path.
So the key distinction is:
- ACP = Codex harness on the gateway host
exec host=node= literalcodexbinary on the paired node
Since you want the second one, your agent’s “try using ACP” suggestion is actually the wrong path.
If you want, I can draft the full SKILL.md for the node-exec Codex version.
{
"command": "zsh -lc 'cd ~/Downloads/seo-page-builder/kak-razrabatyvat-prilozheniya && codex exec --skip-git-repo-check -C ~/Downloads/seo-page-builder/kak-razrabatyvat-prilozheniya -s workspace-write --full-auto "На основе файла competitors.md подготовь полноценный SEO-brief для страницы по теме \"Как разрабатывать приложения\". Определи идеальную структуру страницы, H1, H2 и порядок блоков, обязательные SEO-элементы, конверсионные блоки, Title, Description, Canonical, облако ключевых слов, группировку ключей: основной, LSI, коммерческие, информационные, и секцию FAQ. Сохрани результат в seo-brief.md."'",
"host": "node",
"node": "76526ff3f25550ae6df5354e16c56dc9eafe3bfe84ffc530bed65566cdbe0480",
"yieldMs": 1000,
"background": true,
"timeout": 3600
}
{
"status": "error",
"tool": "exec",
"error": "TIMEOUT: node invoke timed out"
}
That timeout looks like a runtime hang, not a skill/discovery issue.
The first thing I’d change is this:
- don’t wrap it in
zsh -lc - do set
pty: truefor Codex - don’t start with the giant prompt first
Codex is exactly the kind of CLI where PTY helps.
Try this ladder
1) Smoke test the node + Codex binary
{
"command": "which codex && codex --version",
"host": "node",
"node": "76526ff3f25550ae6df5354e16c56dc9eafe3bfe84ffc530bed65566cdbe0480",
"pty": true,
"yieldMs": 10000,
"timeout": 60
}
2) Smoke test the working dir
{
"command": "pwd && ls -la",
"workdir": "~/Downloads/seo-page-builder/kak-razrabatyvat-prilozheniya",
"host": "node",
"node": "76526ff3f25550ae6df5354e16c56dc9eafe3bfe84ffc530bed65566cdbe0480",
"pty": true,
"yieldMs": 10000,
"timeout": 60
}
3) Then run Codex directly, no shell wrapper
{
"command": "codex exec --skip-git-repo-check -C . -s workspace-write --full-auto \"На основе файла competitors.md подготовь полноценный SEO-brief... Сохрани результат в seo-brief.md.\"",
"workdir": "~/Downloads/seo-page-builder/kak-razrabatyvat-prilozheniya",
"host": "node",
"node": "76526ff3f25550ae6df5354e16c56dc9eafe3bfe84ffc530bed65566cdbe0480",
"pty": true,
"yieldMs": 20000,
"timeout": 3600
}
Why
TIMEOUT: node invoke timed out usually means the node never returned from system.run, often because:
- the CLI wants a TTY
- first-run Codex auth/setup is blocking
- shell startup/profile is hanging
- the shell wrapper is making the invocation brittle
So I’d test:
which codex && codex --versionpwd && ls -la
- only then the real
codex exec
If step 1 hangs too, the problem is Codex on the Mac, not the skill.
If step 1 works and step 3 hangs, it’s probably TTY/auth/first-run behavior.
Paste step 1 output, that’ll narrow it down fast.
/opt/homebrew/bin/codex
codex-cli 0.118.0
Perfect, that’s a good sign.
So now we know:
- the node is reachable
- the
codexbinary exists - the remaining issue is specifically
codex exec, not node access in general
Next I’d test the smallest real Codex run with PTY and no shell wrapper:
{
"command": "codex exec --skip-git-repo-check -C . -s workspace-write --full-auto \"Reply with exactly OK\"",
"workdir": "~/Downloads/seo-page-builder/kak-razrabatyvat-prilozheniya",
"host": "node",
"node": "76526ff3f25550ae6df5354e16c56dc9eafe3bfe84ffc530bed65566cdbe0480",
"pty": true,
"yieldMs": 20000,
"timeout": 600
}
If that works, then scale up to your real SEO prompt.
If that still times out, then the problem is likely one of:
- Codex first-run/auth flow
- Codex waiting on something interactive even with PTY
codex execbehavior on that node specifically
At that point I’d do one more tiny check:
{
"command": "codex exec --help",
"host": "node",
"node": "76526ff3f25550ae6df5354e16c56dc9eafe3bfe84ffc530bed65566cdbe0480",
"pty": true,
"yieldMs": 10000,
"timeout": 60
}
You’re pretty close now. The big blocker is gone, we’re just narrowing down the exact codex exec behavior.
Now next error
{
"status": "error",
"tool": "exec",
"error": "exec host not allowed (requested sandbox; configured host is node; set tools.exec.host=sandbox or auto to allow this override)."
}
Yep, that one makes sense.
You currently have exec pinned to host=node, and now the agent tried to call host=sandbox. OpenClaw blocks that override.
So you have 2 valid setups:
Option A, recommended for this skill
Keep it node-only and make the skill explicit:
tools.exec.host = "node"tools.exec.node = "76526f..."- in
SKILL.md, tell it:
For this skill, all
execcalls must usehost=nodeon the configured node. Do not usesandboxorgatewayexec.
That matches your goal: run Codex on the node.
Option B, more flexible
Set the default back to auto:
openclaw config set tools.exec.host auto
Then the agent can use sandbox normally, and the skill can explicitly request host=node only when it needs Codex.
My recommendation: Option B globally, Option A inside the skill.
That is:
- global default:
auto - skill instructions: “when using Codex, force
host=node”
That avoids this exact conflict.
If you want, I can write the exact final SKILL.md text that hard-pins Codex steps to the node without breaking normal sandbox behavior.
On vps in gateway openclaw.conf:
"tools": {
"exec": {
"security": "full",
"ask": "off"
}
}
exec-approvals.json:
"defaults": {
"security": "full",
"ask": "off",
"askFallback": "full"
},
On node same, but a always get approval modal like this:
Exec approval needed
expires in 25m
/bin/sh -lc "cd /Users/user/PhpstormProjects/OpenClaw/pages && ls -la"
Host
node
Agent
main
Session
agent:main:main
Security
allowlist
Ask
on-miss
The modal is the clue here.
If the approval sheet says:
- Security:
allowlist - Ask:
on-miss
then the request itself / session state is still asking for allowlist + on-miss.
So this is not coming from the node exec-approvals.json you pasted.
Something higher up is overriding your global defaults, usually one of these:
- A persisted
/execsession override in that chat/session - An agent-specific override for
main - Less commonly, the tool call itself is explicitly sending
security=allowlist ask=on-miss
What to check
1) Check the current session override
In that chat, run:
/exec
If it shows allowlist / on-miss, that’s your answer.
Then set it explicitly:
/exec host=node security=full ask=off node=<your-node-id>
Or just start a fresh session with /new after fixing config.
2) Check agent-specific config
Look for something like this in config:
agents: {
list: [
{
id: "main",
tools: {
exec: {
security: "allowlist",
ask: "on-miss"
}
}
}
]
}
If that exists, it overrides your global tools.exec.
3) Check the merged policy from CLI
On the gateway, run:
openclaw approvals get --node <id>
That should show:
- requested policy
- host approvals policy
- effective result
Most likely cause
Honestly, I’d bet on a stale /exec session override from earlier testing.
Those can survive config changes and keep forcing allowlist/on-miss.
So the short fix is:
/execin the current chat- if it shows old values, set:
/exec host=node security=full ask=off node=<id> - or use
/new
If you paste the output of /exec, I can tell you in one message where it’s coming from.
"agents": {
"main": {
"allowlist": [
{
"id": "6716da38-f65e-4d7c-a98c-8dead8926d9c",
"pattern": "/bin/ls",
"source": "allow-always",
"lastUsedAt": 1776330646132,
"lastUsedCommand": "/bin/sh -lc "ls -lah /Users/user/PhpstormProjects/OpenClaw/skills/seo-page-builder/scripts/ && echo '---' && sed -n '1,220p' /Users/user/PhpstormProjects/OpenClaw/skills/seo-page-builder/scripts/codex-step.sh"",
"lastResolvedPath": "/bin/ls"
},
{
"id": "8d6476af-75fa-4228-a672-e63e5ba84bd6",
"pattern": "/usr/bin/which",
"source": "allow-always",
"lastUsedAt": 1776341019793
},
{
"id": "fc24e304-649e-4365-aae2-d455161a3dc9",
"pattern": "=command:e251ac2da3174643",
"source": "allow-always",
"lastUsedAt": 1776341073738
},
{
"id": "f19c0cde-8c4e-440b-bc33-0eccc0ff7b88",
"pattern": "=command:39c36c5291981f67",
"source": "allow-always",
"lastUsedAt": 1776341221431
},
{
"id": "4bbf111d-d903-494c-ac5a-ee84e1fdc2e7",
"pattern": "=command:2b2275860f0253dd",
"source": "allow-always",
"lastUsedAt": 1776341223994
},
{
"id": "0f26ef5e-d20e-49e3-a8c5-74812a56a729",
"pattern": "=command:cede0f1499e77098",
"source": "allow-always",
"lastUsedAt": 1776341232551
},
{
"id": "d36c6524-3657-49a5-8d13-573b0f313498",
"pattern": "=command:2415e5aa250a75e2",
"source": "allow-always",
"lastUsedAt": 1776341386246
},
]
}
Yep, this snippet is not the thing forcing the modal.
What you pasted is just the node’s stored allowlist entries for agent main:
source: "allow-always"pattern: "/bin/ls"pattern: "=command:..."
Those are basically remembered approvals / command fingerprints.
They do not by themselves mean:
security = allowlistask = on-miss
So the approval modal is still being driven by one of these instead:
- current session
/execoverride - agent config override for
mainundertools.exec - explicit params on the actual exec tool call
That’s why the modal says Security allowlist / Ask on-miss even though your defaults are full / off.
Important detail
If exec is called with explicit params like:
{
"security": "allowlist",
"ask": "on-miss"
}
then that will absolutely override your nice global defaults.
So the next thing to inspect is:
- the actual exec tool call payload
- or the merged policy view, not the raw allowlist file
Best checks:
openclaw approvals get --node <id>
and in the chat/session:
/exec
If you want, paste either of those and I’ll tell you exactly where the allowlist/on-miss is coming from. Right now, the allowlist block you sent is normal and not the root cause.
what do I need to prescribe so that I don't ask for permission anymore?
To stop permission prompts completely, you need all 3 layers aligned to YOLO:
1) Node host approvals file
On the node:
openclaw approvals set --node <id> --stdin <<'EOF'
{
version: 1,
defaults: {
security: "full",
ask: "off",
askFallback: "full"
}
}
EOF
2) Gateway requested exec policy
On the gateway:
openclaw config set tools.exec.host node
openclaw config set tools.exec.node "<id>"
openclaw config set tools.exec.security full
openclaw config set tools.exec.ask off
3) No narrower override anywhere
This is the part that usually bites people.
Make sure you do not still have one of these:
- a session override from
/exec - an agent-specific override under
agents.list[].tools.exec
- explicit tool-call params like:
"security": "allowlist", "ask": "on-miss"
If you do, they can still force prompts.
So in the current chat/session, reset it explicitly:
/exec host=node security=full ask=off node=<id>
or just start a fresh /new after changing config.
Short version
You want the final effective state to be:
- host =
node - security =
full - ask =
off
both in:
- the node approvals file
- the gateway
tools.exec.*config - the current session/tool call
If you still get a modal after that, then the actual exec call is explicitly sending allowlist/on-miss.
If you want, I can give you one exact “known-good” config snippet for both the gateway and node.
approvals on node:
│ Path │ ~/.openclaw/exec-approvals.json
│ Exists │ yes
│ Version │ 1
│ Socket │ default
│ Defaults │ security=full, ask=off, askFallback=full
│ Agents │ 0
│ Allowlist │ 0
tools.exec │ security=full (tools. │ security=full (~/.openclaw/exec-approvals.json defaults.security) │ security=full │ requested
│ │ exec.security) │ ask=off (~/.openclaw/exec-approvals.json defaults.ask) │ ask=off │ security applies; │
│ │ ask=off (tools.exec. │ askFallback=full (~/.openclaw/exec-approvals.json defaults.askFallback) │ │ requested ask │
│ │ ask) │ │ │ applies
I still get request for permission.
Exec approval needed
/bin/sh -lc "printf 'cwd=%s\n' "$PWD"; which codex || true; ls -ld /Users/user/PhpstormProjects/OpenClaw/pages /Users/user/PhpstormProjects/OpenClaw/skills/seo-page-builder/scripts 2>/dev/null"
Hostnode
Agent
main
Security
allowlist
Ask
on-miss
Ah, I think I see the mismatch now.
You previously set:
OPENCLAW_NODE_EXEC_HOST=app
That means system.run is being forwarded through the macOS companion app, not executed directly by the headless node-host.
So:
openclaw approvals get --node ...is showing you the node-host policy- but the modal you’re seeing is coming from the macOS app exec host
And per docs, when exec is routed through the app:
- prompts + output stay in the app
system.runis controlled by the macOS app Exec approvals
So you have 2 options
Option 1, keep OPENCLAW_NODE_EXEC_HOST=app
Then fix the macOS app approvals:
- open the macOS app
- go to Settings → Exec approvals
- set:
- Security = full
- Ask = off
Then restart the app (and honestly the node host too).
Option 2, simpler for debugging
Remove this env var:
OPENCLAW_NODE_EXEC_HOST=app
Then restart the node host.
That will keep execution on the headless node-host, where your full/off policy is already showing correctly.
So the short answer is:
you’re checking the node-host policy, but the prompt is coming from the Mac app policy.
That’s why they don’t match.
If you want, I can give you the exact “debug-safe” setup I’d use here, with one recommendation for either:
- pure node-host exec
- or app-routed exec
No, I deleted it from env.
Got it, but deleting it from .env is not enough if the processes were already running.
You need to make sure the old env is no longer live in the running node/app process.
Do this next
- Restart the node host
openclaw node restart
-
Fully quit and reopen the macOS app
- don’t just close the window, actually quit it
-
If it still behaves the same, do a clean reinstall of the node service:
openclaw node uninstall
openclaw node install --force --host <gateway-host> --port 18789 --display-name "MacBook Pro"
openclaw node restart
Why
A running launchd/service process can keep the old env until restart.
So “I removed it from .env” does not prove the active process stopped using it.
If it still prompts after that
Then I’d stop blaming env and look at the actual exec request payload again, because something may still be explicitly sending:
"security": "allowlist",
"ask": "on-miss"
So the order is:
- restart node host
- restart mac app
- if needed, reinstall node service
- if still broken, inspect the actual exec tool call again
If you want, I can give you the exact shortest verification sequence after restart so we can prove which process path is active.
Hello. I am a Senior Software Engineer. I think I can help you resolve your issue. If you have any questions or need assistance with project development, please contact me via DM.