#Custom Skills

1 messages · Page 1 of 1 (latest)

calm hearth
#

I have a custom skill file (.md file) that I created locally.

I am running OpenClaw with a named profile using the --profile flag
on Linux/WSL2, OpenClaw

I want to know:

  1. How do I register or install a local custom skill .md file so
    OpenClaw recognizes and can use it?
  2. How do I trigger a custom skill from Discord?
  3. Can a skill run automatically on a schedule rather than being
    triggered manually?
rapid groveBOT
#

To help others find answers, you can mark your question as solved via Right click solution message -> Apps -> âś… Mark Solution

wet lotusBOT
#
  1. “Install/register” a local custom skill (.md)
  • A skill is not a single loose .md file — OpenClaw expects an AgentSkills-style folder:
    <some-skill-dir>/
      <skill-name>/
        SKILL.md
        (optional: scripts/, references/, assets/)
    
  • Put it in one of these locations (highest precedence first):
    1. Workspace skills: <workspace>/skills/<skill-name>/SKILL.md
    2. Managed/shared skills: $OPENCLAW_STATE_DIR/skills/<skill-name>/SKILL.md
      • With --profile foo, your state dir is typically ~/.openclaw-foo/, so: ~/.openclaw-foo/skills/...
    3. Extra folders (lowest precedence): set skills.load.extraDirs in openclaw.json

You can confirm what OpenClaw sees with:

#
openclaw --profile <name> skills list
openclaw --profile <name> skills list --eligible
openclaw --profile <name> skills check

Docs:

Important detail: OpenClaw snapshots eligible skills when a session starts. After adding/changing skills, do /new in Discord (or restart the gateway) to guarantee the new skill list is picked up.


  1. Trigger a custom skill from Discord
    You’ve got three practical options:
#
  • Let the model pick it automatically: just ask for something that matches the skill’s description (that description is the trigger).
  • Force-run it by name (works everywhere):
    • Send a standalone command message in Discord:
      /skill <skill-name> optional input text
      
  • Make it a dedicated slash command: in your SKILL.md frontmatter set user-invocable: true. Then it’ll be exposed as a slash command (name is sanitized to a-z0-9_).

Docs:


  1. Run a skill on a schedule
    Yes — but conceptually you schedule an agent run, and that run can invoke the skill.

Use cron jobs:

#
  • For “run daily/weekly and post results somewhere” → isolated cron + --announce
  • For “poke the main session with context on the next heartbeat” → main session + --system-event

Example (isolated, recurring) that calls your skill via the command text:

openclaw --profile <name> cron add \
  --name "Run my skill daily" \
  --cron "0 9 * * *" \
  --tz "UTC" \
  --session isolated \
  --message "/skill <skill-name> <input>" \
  --announce \
  --channel discord \
  --to "channel:<discord-channel-id>"

Docs:

calm hearth
#

when i try to use /skill in my discord, it says i am not authorized to use this command. how do i enable?

wet lotusBOT
#

That “not authorized to use this command” can come from two different layers:

A) Discord is blocking the slash command (Discord permissions)

If Discord shows the error immediately and the bot never even responds, it’s usually server command permissions.

Fix (needs server admin perms):

  1. Discord Server Settings → Integrations
  2. Select your OpenClaw app/bot
  3. Find Commands and make sure /skill is enabled for:
    • your user/role, and
    • the channel you’re running it in
  4. Also ensure your role has the channel permission “Use Application Commands”.

B) OpenClaw is allowing chat, but blocking commands (OpenClaw authorization)

If the bot does respond (often ephemerally) saying you’re not authorized, you need to allow yourself in OpenClaw’s commands.allowFrom.

On the gateway host (WSL2), get your Discord user ID (Discord Developer Mode → right-click yourself → Copy ID), then:

#
openclaw --profile <yourProfile> config set commands.allowFrom.discord '["user:<YOUR_DISCORD_USER_ID>"]' --json
openclaw --profile <yourProfile> gateway restart

Or in ~/.openclaw-<yourProfile>/openclaw.json:

{
  commands: {
    allowFrom: {
      discord: ["user:123456789012345678"],
    },
  },
}
#

Notes:

  • If you already set commands.allowFrom, it becomes the only authorization source for commands — so if your ID isn’t in there, /skill will be blocked.
  • Restart is important, and make sure you’re using the same --profile your gateway/service is actually running with.

Docs: https://docs.openclaw.ai/tools/slash-commands

If you tell me whether the error appears before the bot responds (Discord-level) or as a bot reply (OpenClaw-level), I can point you to the exact fix.

calm hearth
#

I tried B) but it didn't work.

wet lotusBOT
#

That specific Discord wording (“you are not authorized to use this command”) is usually Discord-side command permissions, not OpenClaw’s commands.allowFrom — so B won’t affect it.

1) Fix the Discord-side permission (most likely)

You need someone with server admin perms to do:

Server Settings → Integrations → (your OpenClaw app/bot) → Commands

  • Find /skill (and/or the per-skill commands)
  • Set it to allowed for your role/user (or “everyone”), and ensure it’s allowed in the channel you’re trying it in.
    Also verify the channel permissions include Use Application Commands for your role.

If you’re not an admin on that server, you’ll need an admin to flip this.

2) Workaround: disable native skill slash commands and use text commands instead

If you control the gateway config, you can avoid Discord’s native command permission system by turning off native skill commands:

Set:

  • channels.discord.commands.nativeSkills = false (or commands.nativeSkills = false)
#

Then restart the gateway. On startup, OpenClaw will clear the registered skill commands on Discord (per docs), and you can run skills via the text command path (assuming commands.text=true).

Docs: https://docs.openclaw.ai/tools/slash-commands

3) Quick sanity check: are you editing the same --profile the service is running?

This bites people a lot. Run:

openclaw --profile <name> gateway status
openclaw gateway status

If you see “Config (cli)” vs “Config (service)” mismatch, reinstall the service from the right profile:

openclaw --profile <name> gateway install --force
openclaw --profile <name> gateway restart
#

(From the FAQ: profile mismatches are a common cause.)


If you paste exactly where the denial appears (Discord UI error before anything is sent vs a bot reply), I can tell you 100% which layer it is. A screenshot is perfect here.

calm hearth
#

the error message is coming from the openclaw bot not discord. no slash commands are working t all. i'm owner of the discord server.

i put the numbers in like this:
openclaw --profile <yourProfile> config set commands.allowFrom.discord '["user:123456789"]' --json

restarted and reinstalled the gateway, it's the proper profile too. nothing

wet lotusBOT
#

Your example ID is almost certainly the problem.

Discord user IDs (“snowflakes”) are 17–19 digits. 123456789 (9 digits) will never match what OpenClaw sees as SenderId, so you’ll stay “not authorized”.

Fastest way to debug (and fix) in 2 minutes

  1. Temporarily allow everyone to use commands (just for debugging):
openclaw --profile <yourProfile> config set commands.allowFrom.discord '["*"]' --json
openclaw --profile <yourProfile> gateway restart
  1. In Discord, run:
/whoami

(or /id)

#

That will show the exact sender id OpenClaw is evaluating.

  1. Lock it back down to just you (use the full ID /whoami printed):
openclaw --profile <yourProfile> config set commands.allowFrom.discord '["user:<FULL_ID_HERE>"]' --json
openclaw --profile <yourProfile> gateway restart

If you want to grab your ID manually (without the wildcard step)

In Discord:

  • User Settings → Advanced → Developer Mode ON
  • Right click your user → Copy User ID
  • It should look like 123456789012345678 (18 digits)

Then use that in commands.allowFrom.discord.

If you paste what /whoami prints (or your config get commands.allowFrom output), I can tell you if anything else is off.

calm hearth
#

Temporarily allowing everyone didn't work, still no commands work.

wet lotusBOT
#

That exact string “You are not authorized to use this command.” is coming from OpenClaw’s Discord native slash-command handler (src/discord/monitor/native-command.ts) — and (importantly) it does NOT use commands.allowFrom for guild slash commands.

For native Discord commands, authorization is based on your Discord channel access config + commands.useAccessGroups + (optionally) channels.discord.allowFrom (used as an “owner” allowlist).

Fix 1 (recommended): allow yourself via channels.discord.allowFrom

Add your Discord user ID to the Discord allowFrom list:

openclaw --profile <yourProfile> config set channels.discord.allowFrom '["user:<YOUR_FULL_DISCORD_ID>"]' --json
openclaw --profile <yourProfile> gateway restart

(Your ID should be 17–19 digits.)

This makes you pass the “ownerOk” check for native commands.

Fix 2: if you have guild member restrictions configured, add yourself there too

#

If your config has something like channels.discord.guilds.<guildId>.users or .roles, native commands will require you to match those.

To inspect what you currently have:

openclaw --profile <yourProfile> config get channels.discord.guilds
openclaw --profile <yourProfile> config get commands.useAccessGroups
openclaw --profile <yourProfile> config get channels.discord.allowFrom

If guilds has users/roles, add yourself (bracket notation for numeric keys):

openclaw --profile <yourProfile> config set 'channels.discord.guilds["<GUILD_ID>"].users' '["user:<YOUR_ID>"]' --json
openclaw --profile <yourProfile> gateway restart
#

Fix 3 (workaround): disable native commands and use text commands instead

If you want commands.allowFrom to be the authority, you can avoid native commands entirely:

  • set channels.discord.commands.native=false
  • set channels.discord.commands.nativeSkills=false
  • keep commands.text=true

Then restart (this unregisters Discord slash commands on startup), and you’ll be able to send /status, /skill ... as plain messages.


If you paste the output of:

  • openclaw --profile <yourProfile> config get channels.discord.allowFrom
  • openclaw --profile <yourProfile> config get channels.discord.guilds

…I can tell you exactly which gate is blocking you.

calm hearth
#

i just set up allowed channels when i setup openclaw that's it. the server is fresh server and i'm admin on it. what bot permissions should it have enabled in discord exactly?

here is the output:

openclaw --profile prospect config get commands.allowFrom

(venv) cxxxx@coxxxxe:~$ openclaw --profile prospect config get commands.allowFrom

🦞 OpenClaw 2026.2.19-2 (45d9b20) — Gateway online—please keep hands, feet, and appendages inside the shell at all times.

{
"discord": [
"*"
]
}
(venv) coren@corenode:~$ openclaw --profile prospect config get channels.discord.allowFrom

🦞 OpenClaw 2026.2.19-2 (45d9b20) — I'll butter your workflow like a lobster roll: messy, delicious, effective.

[]
(venv) cxxx@cxxxxxde:~$ openclaw --profile prospect config get channels.discord.guilds

🦞 OpenClaw 2026.2.19-2 (45d9b20) — WhatsApp automation without the "please accept our new privacy policy".

{
"126456565206": {
"channels": {
"1324544352301": {
"allow": true
},
"1892347398472372": {
"allow": true
},
"125354345402": {
"allow": true
},
"1452542345435": {
"allow": true
}
}
}
}
(venv) xxxx@xxxx:~$

wet lotusBOT
#

For Discord, OpenClaw only needs a pretty small baseline set.

Discord Developer Portal → Bot → Privileged Gateway Intents

  • Message Content Intent âś… (required; docs note the bot can crash without it)
  • Server Members Intent âś… recommended (not strictly required for basic chatting)
  • Presence Intent: optional

OAuth2 → URL Generator

  • Scopes: bot + applications.commands (so native slash commands can be registered)

Bot permissions (recommended baseline)

  • View Channels
  • Send Messages
  • Read Message History
  • Embed Links
  • Attach Files
  • Add Reactions (optional)
#

If you’re using threads: also ensure it can Send Messages in Threads (Discord has that as a separate permission in some setups).

Docs reference (this exact list is in here): https://docs.openclaw.ai/channels/discord

Side note on your config output: channels.discord.allowFrom isn’t the key you want (DM access uses channels.discord.dm.allowFrom / channels.discord.dm.policy). Your guild/channel allowlisting via channels.discord.guilds...channels...allow:true is the right mechanism for server channels.

calm hearth
#

I want to change my cron jobs to run less often, how do i edit them?

wet lotusBOT
#

1) “Install” / register a local custom skill .md

OpenClaw only loads skills that are skill folders containing a SKILL.md (not an arbitrary .md file).

Put your file here (pick one):

  • Per-workspace (recommended): <your-workspace>/skills/<skill-folder>/SKILL.md
  • Shared on that machine (all agents): ~/.openclaw/skills/<skill-folder>/SKILL.md
  • Extra custom dirs: via skills.load.extraDirs in ~/.openclaw/openclaw.json (lowest precedence)

Minimum required SKILL.md frontmatter:

---
name: my-skill
description: What it does
---
#

Then start a new session (e.g. /new) or restart the gateway so the session picks up the new skills snapshot.

Docs: https://docs.openclaw.ai/tools/skills


2) Trigger a custom skill from Discord

On Discord, user-invocable skills can be run via:

  • Generic runner: /skill <name> [input]
  • Native per-skill slash command (when enabled): /<skill_name>
    (skill names get sanitized to a-z0-9_)

Whether the per-skill commands show up depends on slash command settings (defaults are usually fine on Discord):

  • commands.nativeSkills: "auto" (or true)

Docs:

#

3) Can a skill run automatically on a schedule?

Yes — but the scheduler is cron/heartbeat, not the skill itself.

  • Cron = exact times / intervals, can run isolated + deliver back to Discord
  • Heartbeat = periodic “checklist” in the main session (good for batching lots of small checks)

Docs:


#

Editing cron jobs to “run less often”

  1. List your jobs and copy the jobId:
openclaw cron list
  1. Edit the schedule (cron supports patching fields via openclaw cron edit; exact flags can vary by version, so check help if needed):
openclaw cron edit <jobId> --help

Typical examples:

  • Change to every 6 hours:
openclaw cron edit <jobId> --every "6h"
  • Or switch to a cron expression:
#
openclaw cron edit <jobId> --cron "0 */6 * * *"

If you’d rather do it the blunt/safe way: openclaw cron remove <jobId> then openclaw cron add ... again with the new frequency.

(And avoid manually editing ~/.openclaw/cron/jobs.json unless the gateway is stopped — the docs call that out as unsafe while running.)

If you paste one openclaw cron list entry (redact anything sensitive), I can tell you the exact edit command for that job.

calm hearth
#

how do I change the name of my sports_news (sports-news) skill? also after that how do i set up a cron job for it?

wet lotusBOT
#

To “rename” a skill in OpenClaw you’re really renaming the name: in the skill’s SKILL.md frontmatter (the folder name can be anything, it’s the frontmatter name that becomes the skill ID + slash command).

1) Rename sports_news / sports-news

Open the skill file:

  • If it’s per-workspace: <workspace>/skills/<some-folder>/SKILL.md
  • If it’s shared: ~/.openclaw/skills/<some-folder>/SKILL.md

Then change the frontmatter, e.g. from:

---
name: sports-news
description: ...
---
#

to:

---
name: sports_news # or whatever new name you want
description: ...
---

Notes:

  • Discord slash commands get sanitized to a-z0-9_, so sports-news already becomes /sports_news. If your goal is “change the slash command”, you generally want name: something_new.
  • If you have per-skill config in ~/.openclaw/openclaw.json under skills.entries.<name>, you must also update that key to the new name or set a stable metadata.openclaw.skillKey (advanced; see Skills docs).
  • Changes are picked up on the next session (e.g. /new) or after a gateway restart.

Docs: https://docs.openclaw.ai/tools/skills

2) Set up a cron job to run it

#

Cron doesn’t “run a skill” directly; it runs an agent turn on a schedule. So you schedule a message that tells the agent to use the skill.

Example: daily at 7am, post into this Discord channel:

openclaw cron add \
--name "Sports news" \
--cron "0 7 * * *" \
--tz "America/Chicago" \
--session isolated \
--message "Use the sports_news skill to fetch today's sports news and post a concise summary." \
--announce \
--channel discord \
--to "channel:1474517828366372884"

Then test-run it immediately:

#
openclaw cron list
openclaw cron run <jobId>

Docs: https://docs.openclaw.ai/automation/cron-jobs

Quick question (so I can give you the exact --to target)

Do you want the cron output posted:

  1. in #custom-skills (channel), or
  2. into this thread specifically?

(Threads have their own id; if you paste the thread id, you can target it as channel:<thread_id>.)

calm hearth
#

ok i edited the SKILL.md file on windows. now how do i transfer it over to my WSL . it's for the project1 profile

wet lotusBOT
#

WSL2 can read your Windows files directly, so you don’t need “transfer” tools — just copy (ideally the whole skill folder, not only SKILL.md).

Option A (recommended): copy from /mnt/c/... inside WSL

  1. In WSL, find where you want the skill to live (workspace or ~/.openclaw/skills).
  • Per-workspace: <workspace>/skills/<skill-folder>/SKILL.md
  • Shared: ~/.openclaw/skills/<skill-folder>/SKILL.md

If you’re using the project1 profile and you’re not sure what its workspace is, run status using that same profile and look for the workspace path:

openclaw --profile project1 status
  1. Copy the folder from Windows into WSL (example assumes the skill folder is on your Windows Desktop):
mkdir -p "<workspace>/skills/"
#
cp -r "/mnt/c/Users/<YourWindowsUser>/Desktop/sports-news" "<workspace>/skills/"

(Replace <workspace> with the actual workspace path you saw in status.)

Option B: drag & drop via Windows Explorer into WSL

In Windows Explorer, go to:

  • \\wsl$\ → your distro → navigate to your workspace → skills\
    Then drag the sports-news folder in.

Option C: edit it “in place” (no copying) next time

Open the WSL file directly from Windows using:

  • VS Code “Remote - WSL” (best), or
  • Windows path \\wsl$\...

After copying