AgentSkills.site

How to Create an OpenClaw Skill

The parts that separate a working OpenClaw skill from a file that loads and never fires: a description short enough to survive the prompt budget, and gating metadata that keeps it out of sight when the machine can't run it.

Published

AgentSkills.site editorial

The minimum viable skill is a directory, a file, and two frontmatter fields:

mkdir -p ~/.openclaw/workspace/skills/hello-world
# ~/.openclaw/workspace/skills/hello-world/SKILL.md
---
name: hello-world
description: A simple skill that prints a greeting.
---

# Hello World

When the user asks for a greeting, use the `exec` tool to run:

```bash
echo "Hello from your custom skill!"
```
openclaw skills list

That works. The rest of this page is the difference between a skill that loads and a skill that actually gets used.

Let the bundled skill-creator do the first draft

OpenClaw ships skill-creator, whose own description reads: "Author or review AgentSkills: create, repair, validate, or restructure SKILL.md files and bundled resources."

It's worth using rather than hand-rolling frontmatter, because its workflow makes you answer the questions that decide whether the skill works — establish the contract, choose the invocation mode, then structure the body. Its second step in particular is the one people skip:

  • Model-discoverable: write a model-facing description, omit disable-model-invocation.
  • Manual-only: set disable-model-invocation: true, write a human-facing summary.
  • Direct tool command: add command-dispatch: tool, command-tool, and command-arg-mode only when the command bypasses the model.

Decide that before writing the body, because it changes who the description is written for.

Write the description for the budget, not for the reader

This is the single highest-leverage constraint in OpenClaw, and it comes from arithmetic rather than style.

Every eligible skill is compiled into a compact XML block in the system prompt at a cost of "~97 characters + your name, description, and location field lengths" — roughly 24 tokens per skill before your fields. That cost recurs in every session, for every eligible skill, whether or not it's used.

Hence OpenClaw's own authoring rule: keep description "one line and under 160 characters."

For comparison, the portable Agent Skills spec permits up to 1,024 characters. OpenClaw asks for roughly a sixth of that. If you're porting a skill from Claude Code or Codex, the description is the field most likely to need trimming.

What has to survive the trim is the trigger. The description is the only thing the model sees when deciding whether to load your skill, so it needs to say when to use this, not what this is:

# Weak — describes the artifact
description: A skill for working with our deployment system.

# Better — describes the trigger
description: Deploy or roll back a service to staging or production. Use when asked to ship, deploy, release, or revert.

If the block exceeds skills.limits.maxSkillsPromptChars, OpenClaw degrades in a documented order: keep skill identities first, then shortened descriptions, then drop descriptions entirely — and it tells you by pointing at openclaw skills check. A long description doesn't just cost tokens; past the ceiling it can be the thing that gets truncated.

Naming rules

  • name: lowercase letters, digits, and hyphens.
  • Keep the directory name and frontmatter name aligned.
  • The slash command comes from name, not the folder path — so you can group skills in subfolders for organisation without changing how they're invoked:
~/.openclaw/workspace/skills/personal/hello-world/SKILL.md   # still /hello-world

OpenClaw discovers SKILL.md up to six levels deep under any configured root.

Reference bundled files with {baseDir}

Don't hardcode absolute paths. {baseDir} resolves to the skill's own directory:

Run the helper script at `{baseDir}/scripts/run.sh`.

Conventional subdirectories are scripts/, references/, and assets/, matching the portable spec.

Gating: make the skill disappear when it can't run

This is OpenClaw's most useful authoring feature and the one most worth writing into a skill from the start. A metadata.openclaw block filters the skill out at load time when its requirements aren't met — so it costs nothing in the prompt and can't be selected on a machine where it would fail.

---
name: gemini-search
description: Search the web using the Gemini CLI. Use when asked to look something up online.
metadata: { "openclaw": { "requires": { "bins": ["gemini"] }, "primaryEnv": "GEMINI_API_KEY" } }
---
Key Behavior
requires.bins All listed binaries must exist on PATH
requires.anyBins At least one must exist on PATH
requires.env Each env var must exist in the process or config
requires.config Each openclaw.json path must be truthy
os Platform filter: ["darwin"], ["linux"], ["win32"]
always Include on a compatible OS even when requires.* checks fail

A skill with no metadata.openclaw block is always eligible. Note that always does not override os — the platform filter is hard.

Two things to know when writing these. Frontmatter is parsed as YAML first, and nested metadata blocks are flattened and re-parsed as JSON5 — which is why the JSON-style brace syntax above works inside YAML frontmatter. And requires.bins is checked on the host at load time; if your agent runs sandboxed, the binary needs to exist inside the container too.

Declaring how to install the dependency

If your skill gates on a binary, you can tell OpenClaw how to get it. The macOS Skills UI uses these specs to offer an install:

metadata:
  {
    "openclaw":
      {
        "emoji": "♊️",
        "requires": { "bins": ["gemini"] },
        "install":
          [
            {
              "id": "brew",
              "kind": "brew",
              "formula": "gemini-cli",
              "bins": ["gemini"],
              "label": "Install Gemini CLI (brew)",
            },
          ],
      },
  }

Supported kinds are brew, node, go, uv, and download. With several listed, the gateway picks one — brew when available, otherwise node — following an overall preference order of Homebrew → uv → configured node manager → go → download. Specs can carry their own os filter.

Worth knowing if you target Linux: brew-only installers are hidden in containers without brew, so add a second spec if Linux users matter to you.

Wiring an API key

For a skill that needs a credential, declare primaryEnv and let the user wire it in config rather than putting it in the file:

{
  skills: {
    entries: {
      "gemini-search": {
        enabled: true,
        apiKey: { source: "env", provider: "default", id: "GEMINI_API_KEY" },
      },
    },
  },
}

The key is injected into the host process for that agent turn only, and does not reach the sandbox.

Choosing how the skill is invoked

Three frontmatter fields shape this, and picking the wrong one is a common cause of "my skill never fires" or, worse, "my skill fired when I didn't want it to."

user-invocable: true              # default — exposed as a slash command
disable-model-invocation: false   # default — model may select it
command-dispatch: tool            # slash command bypasses the model entirely
command-tool: <tool-name>
command-arg-mode: raw             # forwards the raw args string

For anything with side effects — deploys, publishes, anything that spends money or changes production — set disable-model-invocation: true. The skill stays reachable as a slash command and via an explicit $skill-name reference, but the model can't decide to run it on its own.

command-dispatch: tool is the unusual one: the slash command dispatches straight to a registered tool without the model in the loop at all. Reach for it only when you genuinely want an alias rather than a skill.

Testing it

openclaw skills list
openclaw agent --message "give me a greeting"

Or invoke it explicitly in chat with /skill hello-world.

If it doesn't appear, work through these in order:

  1. Session snapshot. OpenClaw snapshots eligible skills when a session starts. Start a new one with /new, or openclaw gateway restart. The watcher does pick up SKILL.md changes by default, but a new session removes the doubt.
  2. Directory. It must be under one of the six documented roots.
  3. Gating. A requires or os clause you can't satisfy will filter the skill out silently. That's the feature working.
  4. Frontmatter. A missing closing --- is the usual culprit.

OpenClaw's own advice is worth keeping: be concise, instruct the model on what to do rather than how to be an AI, and "if your skill uses exec, ensure prompts do not allow arbitrary command injection from untrusted input."

Skill Workshop: proposals instead of direct writes

If you want the agent to help build skills but not to write to your skill files directly, Skill Workshop is a proposal queue: "When the agent spots reusable work, it drafts a proposal instead of writing directly to SKILL.md. You review and approve before anything changes."

openclaw skills workshop propose-create \
  --name "hello-world" \
  --description "A simple skill that prints a greeting." \
  --proposal ./PROPOSAL.md

openclaw skills workshop propose-update hello-world \
  --proposal ./PROPOSAL.md \
  --description "Updated greeting skill"

openclaw skills workshop list
openclaw skills workshop inspect <proposal-id>
openclaw skills workshop evaluate <proposal-id>
openclaw skills workshop apply <proposal-id>

Use --proposal-dir ./my-proposal/ when the proposal ships support files; the directory must contain PROPOSAL.md at its root, with extras under assets/, examples/, references/, scripts/, or templates/.

The closest equivalent elsewhere is Hermes Agent's staged-write approval queue. Both exist for the same reason: an agent that can edit its own skills is useful, and an agent that can edit its own skills unsupervised is a different proposition.

Publishing to ClawHub

npm i -g clawhub
clawhub login
clawhub skill publish ./path/to/hello-world

Publish options: --slug (the published URL name), --name (display name), --version (semver), --changelog, and --tags (comma-separated, defaulting to latest). --owner publishes under a specific owner.

Before publishing, two things are worth doing for the people who'll install it:

Fill in the metadata properly. name, description, any metadata.openclaw gating, and a homepage if you have one. Gating in particular is a courtesy — it's what stops your macOS-only skill from appearing broken on someone's Linux gateway.

Expect to be audited. ClawHub runs automated checks on every published skill, and the result is public on your listing before anyone installs. Its risk analysis looks for coherence — "do the name, summary, metadata, requested authority, and actual content line up with what users would reasonably expect?" A skill that requests credentials it doesn't visibly need will read badly, even with honest intent. If something is flagged wrongly, clawhub skill rescan @owner/<slug> requests a re-scan. See the security page for what the audit checks.

Publishing requires a GitHub account old enough to pass ClawHub's upload gate.

Making it portable

If you'd like the skill to work in other agents, keep the portable core clean:

  • name and description are the portable spec; scripts/, references/, and assets/ are the conventional directories everywhere.
  • OpenClaw-specific fields — metadata.openclaw, user-invocable, command-dispatch, command-tool, command-arg-mode, {baseDir} — do not travel.
  • The description length rule cuts both ways: a description written for OpenClaw's budget is comfortably inside every other agent's limit.

A skill kept in ~/.agents/skills is read natively by OpenClaw, Codex, and Cursor, so cross-agent sharing needs no export step at all.

Caveats

  • We have not installed or run OpenClaw, created a skill in it, or published to ClawHub. Every command, field, and constraint here is taken from the official documentation, and quoted where the wording matters.
  • The skills.limits.maxSkillsPromptChars default is not stated in the skills documentation; the degradation behavior is documented, the number isn't, and none is invented here.
  • The per-skill cost figure (~97 characters, ≈24 tokens) is OpenClaw's own published estimate.
  • Documented as of August 2026. OpenClaw is under very active development.

Sources