Install
openclaw skills install clawhub-skill-forgeCreate ClawhHub-ready OpenClaw skills with correct structure, scanner criteria, security rules & publish checklist. No credentials or binaries required.
openclaw skills install clawhub-skill-forgeScaffold and publish ClawhHub-ready OpenClaw skills. Follow every rule below. Do not skip sections. Do not invent conventions not listed here.
Ask the user for the skill name and purpose if not already provided, then generate the files.
Generate two files only — no README.md, no CHANGELOG.md, no auxiliary docs:
[skill-name]/
├── SKILL.md (required)
└── _meta.json (required)
The scanner is the gatekeeper between publishing and availability. Know how it works before writing a single line:
1. The description summary is the ONLY thing the scanner trusts at the registry level.
_meta.json fields (requiredConfigPaths, primaryCredential, requires) are stored but NOT surfaced in the registry API. The scanner cannot read them. Everything the scanner needs to verify must be in the description — and in the FIRST ~160 characters, because that is where the registry truncates the summary.
2. The scanner is iterative — it reveals one layer at a time. Each fix exposes the next issue. It will not give you all problems at once. Expect multiple publish cycles. This is by design — it is a progressive trust gate.
3. The scanner cannot verify nested content. A worker script embedded inside a here-string inside a code block will be marked as truncated and unverifiable. All content the scanner needs to read must be flat and standalone.
4. The scanner is semantic, not keyword-based. It understands the difference between what is logged vs transmitted, always:true vs always:false, handle vs userId, and required vs optional credentials. It catches logical inconsistencies, not just missing keywords.
5. The scanner is conservative by default. It blocks and warns rather than approves. Every publish triggers a new scan. Do not publish until the checklist passes — each rejected version counts against the skill's history.
These will silently break skill detection — no error, skill just disappears from openclaw skills list:
Missing closing --- in frontmatter: If the frontmatter block is not closed with ---, OpenClaw silently fails to parse the skill entirely. Always verify the closing delimiter exists.
openclaw in metadata.openclaw.requires.bins: OpenClaw does not recognize itself as a bin to check and silently hides the skill. Never put openclaw in bins. Use anyBins: ["powershell","pwsh"] for OS gating — the openclaw runtime is implied.
Skills in ~/.openclaw/skills/ not auto-detected: OpenClaw scans <workspace>/skills/ by default. For skills in ~/.openclaw/skills/, add skills.load.extraDirs: ["~/.openclaw/skills"] to openclaw.json. Also add skills.entries.<name>.enabled: true for each skill.
clawhub install path: By default installs into ./skills (cwd) or <workspace>/skills. Always pass --workdir explicitly or install directly to ~/.openclaw/skills/ and add extraDirs.
Encoding: Always write SKILL.md with [System.Text.UTF8Encoding]::new($false) (no BOM). BOM or encoding artifacts in frontmatter break the YAML parser silently.
Address all five explicitly — in the description first, then in the body.
metadata.openclaw.requires.anyBins in SKILL.md frontmatter (OpenClaw load-time gating)_meta.json requires.anyBinaries (registry metadata)always:true is forbidden in community skills — high blast radius, scanner flags it---
name: [skill-name]
description: "[What it does in plain English — action-focused, no 'AI' prefix]. Requires: [binaries]. Reads [credentials file] ([FIELDS]). [Setup-only secrets: delete afterward.] [Long-lived tokens: rotate periodically; rotate immediately if host compromised.] Grant token minimal permissions only. No data forwarded to third parties; all calls go to [domain] only."
metadata: {"openclaw":{"emoji":"[icon]","requires":{"anyBins":["powershell","pwsh"]}}}
---
Rules:
Requires: [binaries]. Reads [credentials file] ([FIELDS]).openclaw in bins or anyBins — it silently hides the skillalways:true — scanner flags it as high blast radius--- line — verify it exists before publishingGood description example:
"Facebook Page manager: post, schedule, reply & get insights. Requires: powershell/pwsh. Reads ~/.config/fb-page/credentials.json (FB_PAGE_TOKEN, FB_PAGE_ID). FB_APP_SECRET for one-time setup only — delete afterward. Long-lived token; rotate periodically and immediately if host is compromised. Grant minimal permissions only. No data forwarded to third parties; all calls go to graph.facebook.com only."
Bad description example (do not do this):
"Requires: powershell/pwsh. Reads ~/.config/fb-page/credentials.json (FB_PAGE_TOKEN, FB_PAGE_ID). Interact with any Facebook Page feature via the Meta Graph API..."
The bad example leads with dry technical info — users scanning ClawhHub skip it.
CRITICAL: ownerId must be your ClawhHub internal userId — NOT your handle. Get it:
clawhub inspect <one-of-your-skills> --jsonLook forowner.userId(e.g. "kn7824yf4srh3akes6axhmqf5n81q7dh") — NOT "seph1709" Using the handle causes registry owner verification mismatch — scanner flags it.
{
"ownerId": "[registry-userId-not-handle]",
"slug": "[skill-name]",
"version": "1.0.0",
"publishedAt": "YYYY-MM-DDTHH:MM:SSZ",
"requiredEnvVars": [],
"requiredConfigPaths": ["~/.config/[skill]/credentials.json"],
"primaryCredential": {
"type": "file",
"path": "~/.config/[skill]/credentials.json",
"fields": ["FIELD_ONE", "FIELD_TWO"],
"required": ["FIELD_ONE"],
"optional": ["FIELD_TWO"],
"sensitive": true,
"notes": "Which fields are required vs optional. Credentials read fresh from disk at runtime — never embedded as literals. Setup-only fields (e.g. APP_SECRET): delete after one-time exchange. Rotation guidance for long-lived tokens."
},
"persistence": {
"type": "background-process",
"code": "inline",
"optional": true,
"description": "What is READ, TRANSMITTED (to where, via what), and LOGGED. Worker stored in ~/.config/[skill]/worker.ps1 with restricted permissions. Listener never starts autonomously."
},
"credentialSetup": {
"type": "manual",
"description": "One-time setup instructions summary."
},
"requires": {
"anyBinaries": ["powershell", "pwsh"],
"os": ["windows", "macos", "linux"]
}
}
Remove persistence if no background process.
Remove primaryCredential / requiredConfigPaths if no secrets.
Do NOT include openclaw in requires.binaries — it silently gates the skill against itself.
Follow this exact order:
$cfg = Get-Content "$HOME/.config/[skill]/credentials.json" -Raw | ConvertFrom-Json
If missing, show full setup flow:
openclaw channels list)$dir = "$HOME/.config/[skill-name]"
if ($env:OS -eq "Windows_NT") {
"credentials.json","worker.ps1","listener.log","listener.pid","listener-state.json" | ForEach-Object {
$f = "$dir/$_"
if (Test-Path $f) { icacls $f /inheritance:r /grant:r "$($env:USERNAME):(R,W)" | Out-Null }
}
} else {
Get-ChildItem $dir | ForEach-Object { & chmod 600 $_.FullName }
}
Include note: never commit any file in ~/.config/[skill]/ to version control.
For setup-only secrets (e.g. APP_SECRET): include explicit instruction to delete the field from credentials.json after the one-time token exchange is complete.
This section is MANDATORY if the skill has a background process. The worker script MUST be in its own dedicated section as a plain readable code block. Do NOT embed it in a here-string inside another code block — the scanner marks nested content as truncated and unverifiable.
Start the section with explicit disclosure:
External contacts: [list every domain — no others]
Outbound data: [exactly what is sent, to where, via what method]
Logs: [exactly what is written — metadata only, no message content, no tokens]
No other endpoints. No token literals.
Then the full worker as a plain code block with line-by-line comments on every sensitive operation.
The Start procedure must write the worker by extracting it from SKILL.md — not constructing it from string literals:
$workerContent = Get-Content "$HOME/.openclaw/skills/[skill]/SKILL.md" -Raw
$workerContent = ($workerContent -split "## WORKER SCRIPT")[1]
$workerContent = [regex]::Match($workerContent, '(?s)```powershell\r?\n(.*?)```').Groups[1].Value
Set-Content "$HOME/.config/[skill]/worker.ps1" -Value $workerContent -Encoding UTF8
> OPTIONAL - never start without explicit user request.
>
> WHAT IS READ: [credential fields] from [file path].
> WHAT IS TRANSMITTED: [exact fields] via openclaw message send to NOTIFY_CHANNEL/NOTIFY_TARGET.
> [Field X] goes to channel destination only — never written to disk.
> WHAT IS LOGGED: [fields only] — no [sensitive content], no tokens.
> WORKER SCRIPT: exact content shown in WORKER SCRIPT section above.
> AUTONOMOUS START: never. Only starts when the user explicitly requests it.
Always include these:
# Set GitHub repo About description and homepage URL (run after every push)
gh repo edit seph1709/[skill-name] `
--description "OpenClaw skill: [one-line purpose]" `
--homepage "https://clawhub.ai/seph1709/[skill-name]"
This resolves the "no homepage / opaque owner" scanner flag — the GitHub repo is the audit trail, and the ClawhHub URL links back to the published registry record.
Note: clawhub edit --homepage does not exist as a CLI command. GitHub repo About is the only place to surface a homepage URL for the skill.
--- exists after the metadata lineanyBins — NOT bins: ["openclaw"]openclaw anywhere in bins or anyBinsclawhub inspect --jsongh repo edit --description "...")gh repo edit --homepage "https://clawhub.ai/...")openclaw skills list confirms skill is ✓ ready (not missing, not absent)clawhub inspect [slug] summary starts with value hook and shows credentials path