Skills in OpenClaw: How They Work and Writing Your First One
There’s a moment most OpenClaw users hit around week two. The assistant works, but you keep typing the same paragraph of instructions. “Check the deploy log, look for lines matching ERROR after the last successful build marker, summarise them, and if there are more than three, include the timestamp of the first one.” Every time. Slightly differently. With slightly different results.
Skills are the fix. A skill is a Markdown file that teaches your agent how and when to do something — packaged once, loaded automatically, invoked consistently.
The concept is simple. Writing a skill the agent actually uses at the right moment is less simple, and that’s mostly what this page is about.
What a Skill Actually Is
A skill is a folder containing a SKILL.md file: YAML frontmatter plus a Markdown body. It may also carry reference documents or executable scripts the instructions depend on.
The critical distinction, and the one that trips people up:
A tool is a capability. A skill is knowledge about using capabilities.
A tool is code — exec can run a command, web_fetch can retrieve a URL. Those are abilities the agent either has or doesn’t.
A skill is instruction. It doesn’t grant the agent any new power. It tells the agent that a particular combination of existing powers is the right response to a particular kind of request, and exactly how to sequence them.
This means a skill can never exceed the tools available to the agent running it. A brilliantly written deployment skill on an agent with exec denied does nothing but produce an apology. If your skill isn’t working, check the tool policy before you rewrite the prose — see Tools and MCP.
It also means skills are safe to share in a way tools aren’t. A skill is instructions; the recipient’s own tool policy still governs what can actually run.
Where Skills Come From
Three sources, loaded together:
① Bundled skills shipped with the install │ ▼ ② Managed / local ~/.openclaw/skills/ │ shared across all agents ▼ ③ Workspace skills <workspace>/skills/ specific to one agent's workspaceDiscovery walks each configured root looking for SKILL.md, up to six levels deep — so you can organise skills in subfolders by category without breaking loading.
The layering matters for how you work. Put personal, cross-cutting skills in ~/.openclaw/skills/. Put project-specific ones in the workspace, where they live and version alongside the thing they describe. A deploy skill that only makes sense for one codebase belongs with that codebase.
To see what’s currently loaded:
openclaw skills listRun this first when a skill isn’t firing. Half the time it simply isn’t loaded — wrong directory, or a gating condition excluded it.
Installing Skills Others Wrote
Skills are shareable, and there’s an ecosystem of them:
openclaw skills install @owner/skill-nameStraight from a Git repository:
openclaw skills install git:owner/repo@mainBy default this installs into the active workspace. For a skill you want everywhere, install globally:
openclaw skills install @owner/skill-name --globalKeep them current:
openclaw skills update --allRead before you install
A skill is instructions injected into your agent’s context — the same context that holds your tool permissions. A hostile or careless skill can’t invent capabilities, but it can absolutely instruct an agent that already has exec and web_fetch to do something you wouldn’t want.
Treat third-party skills roughly like npm packages with shell access. Open the SKILL.md. Read the body. Check what scripts ship alongside it. There’s a verification command worth using:
openclaw skills verify @owner/skill-nameThe strongest protection isn’t inspection, though — it’s the trust-tier pattern. Install unvetted skills on an agent that has nothing dangerous to grant.
The SKILL.md Format
Minimum viable skill:
---name: standup-notesdescription: Summarise yesterday's commits and open PRs into standup notes---
When the user asks for standup notes, or says "what did I do yesterday":
1. Run `git log --since="yesterday" --oneline --author="$(git config user.email)"` in the current workspace repository.2. Fetch open pull requests assigned to the user via the `gh` CLI: `gh pr list --assignee @me --json number,title,isDraft`3. Produce three short sections: **Done**, **In progress**, **Blocked**.4. Keep it under 120 words. No preamble, no "here are your notes" — just the notes.
If the repository has no commits from yesterday, say so plainly rather thanpadding the Done section with older work.That’s a complete, working skill.
Frontmatter fields
Required:
| Field | Purpose |
|---|---|
name | Identifier, and the slash-command name |
description | What the skill does — this is what the agent matches against |
Optional, and worth knowing:
| Field | Effect |
|---|---|
homepage | Link for the skill’s docs |
user-invocable | Expose as a slash command (default true) |
disable-model-invocation | Hide from the agent’s prompt — command-only (default false) |
command-dispatch | Set to "tool" to dispatch straight to a tool, skipping the model |
command-tool | Which tool, when using command-dispatch |
command-arg-mode | "raw" passes arguments through unprocessed |
metadata.openclaw | Gating rules, requirements, display metadata |
Two of these are more useful than they look.
disable-model-invocation: true makes a skill invocable only when you explicitly type its command. Use it for anything destructive or expensive. You want /purge-cache to happen because you asked for it, never because the agent decided your message resembled a cache problem.
command-dispatch: "tool" bypasses the model entirely and calls a tool directly. That’s faster, cheaper, and deterministic — ideal for a skill that’s really just a parameterised command with no judgement involved.
Gating with metadata
---name: image-labdescription: Generate or edit images via a provider-backed image workflowmetadata: { "openclaw": { "emoji": "🖼️", "requires": { "bins": ["uv"], "env": ["GEMINI_API_KEY"] }, "primaryEnv": "GEMINI_API_KEY" } }---
When the user asks to generate an image, use the `image_generate` tool...requires gates loading on the environment: required binaries on PATH, required environment variables. If they’re absent, the skill doesn’t load, and its instructions never clutter the agent’s context.
This is a genuinely nice piece of design. Skills are filtered at load time based on environment, config, and binary presence — so a machine without uv installed simply never sees the image skill, rather than the agent confidently trying and failing.
Writing a Skill the Agent Actually Uses
Here’s the part the format documentation won’t tell you. A skill has two jobs, and most first attempts only do one.
Job one: be found. The agent has to recognise that this request is the one this skill is for.
Job two: be followed. Once selected, the instructions have to be unambiguous enough to produce consistent behaviour.
Most people write a beautiful body and a lazy description, then wonder why the skill never fires.
The description is a matching key, not a label
This is the single highest-leverage line in the file. The agent decides whether to use a skill largely by comparing the request against the description.
Weak:
description: Deployment helperStrong:
description: Deploy the current branch to staging, run smoke tests, and report the result. Use when the user says deploy, ship, push to staging, or asks to release a branch.The second one names the trigger phrases people actually use. It reads slightly redundantly to a human. That’s fine — it isn’t for a human.
Write the body as a procedure, not an essay
Agents follow numbered steps far more reliably than prose. Compare:
Check the logs and see if anything looks wrong, then let the user know what you found.
against:
- Read the last 200 lines of
/var/log/app/current.log.- Extract lines containing
ERRORorFATAL.- Group by error message; count occurrences.
- Report the top 3 by count, with the most recent timestamp for each.
- If there are zero errors, reply exactly: “No errors in the last 200 lines.”
The second produces the same output every time. The first produces a different essay each run.
Specify the failure case
This is the most-skipped and most valuable habit. Without explicit failure handling, agents improvise — and improvisation is where confidently wrong answers come from.
If the log file does not exist, say so and stop. Do not search foralternative log files, and do not guess at the application's state.Two lines that prevent an entire category of nonsense.
Constrain the output shape
If you want notes under 120 words with three headings, say that. If you want no preamble, say that too — otherwise you’ll get “Certainly! Here are your standup notes:” forever.
Test it cold
Start a fresh session and phrase the request the way you’d naturally say it — not the way you wrote the description. If it doesn’t fire, the description is wrong. Add the phrasing you actually used.
This iteration loop is the whole game. A skill is not really written until it has survived three or four cold invocations.
Controlling Which Agents Get Which Skills
Skills can be scoped per agent, which pairs directly with the trust-tier pattern from Pairing and Allowlists:
{ agents: { defaults: { skills: ["standup-notes", "weather"] } }}An agent with an empty skill list gets none. An agent with its own list overrides the defaults entirely rather than adding to them — worth remembering, because it surprises people.
Per-skill configuration lives separately:
{ skills: { entries: { "image-lab": { enabled: true, apiKey: { source: "env", provider: "default", id: "GEMINI_API_KEY" }, config: { model: "nano-pro" } } } }}enabled toggles availability, apiKey injects a secret for skills declaring primaryEnv, and config is a free-form bag the skill can read. This is how you keep credentials out of the skill file itself — which matters if you ever intend to share it.
Skills Worth Writing First
From experience, the ones that earn their keep immediately:
A context-loader. “When I ask about the infrastructure, first read ~/notes/infra.md for current architecture before answering.” Stops the agent guessing about your specific setup.
A formatting enforcer. “When asked for a summary, always: 3 bullets max, no preamble, bold the decision.” Small, and it fixes the thing that annoys you most.
A safety wrapper. “Before any command that deletes or overwrites, state exactly what will be affected and wait for confirmation.” Belt and braces alongside exec.ask.
A recurring report. The thing you already ask for every Monday, written down once.
The pattern: the best first skill is the paragraph you’re tired of typing. Go find it in your message history — it’s genuinely there.
Troubleshooting
The skill never fires.
Confirm it’s loaded (openclaw skills list). If it’s absent, check the directory and any requires gating. If it’s present but not firing, the description doesn’t match how you phrase the request — add your actual phrasing.
It fires when it shouldn’t.
The description is too broad. Narrow it, and consider disable-model-invocation: true for anything you want to be deliberate.
It fires but the agent apologises and does nothing.
Tool policy. The skill is asking for a capability the agent doesn’t have. Check tools.allow / tools.deny.
Results vary run to run. The body is prose, not procedure. Convert to numbered steps and specify the output shape.
It worked, then stopped after an update.
Check openclaw skills list for gating changes, and re-run openclaw config validate. Fast-moving project; keys and behaviour do shift.
Where to Go Next
Skills are the knowledge layer. Tools and MCP covers the capability layer underneath them — what the agent can actually do, and the policy that constrains it. That’s the page to read if a skill of yours is failing on permissions rather than phrasing.
After that, Memory and Workspace covers the third piece: what your agent knows about you over time, and how to curate it.