Using ClawHub
Publishing
Publishing
Publishing sends a skill folder or plugin package to ClawHub under the owner you choose. ClawHub checks that your token can publish for that owner, validates the metadata, name, version, files, and source information, then stores the release and starts automated security checks.
If validation fails, nothing is published. New releases may also stay out of normal install and download surfaces until review finishes.
Skills
The simplest publishing path is the CLI. Sign in, preview the sync plan, then publish the new or changed skills:
clawhub loginclawhub sync --dry-run --owner <owner>clawhub sync --all --owner <owner>sync scans for folders containing SKILL.md and compares them with ClawHub.
When you run it without --dry-run, it publishes anything new or changed.
Use --dry-run first to see the plan without uploading.
Use --owner <handle> when publishing to an org owner. Omit it to publish as
the authenticated user.
GitHub Actions for Skills
If you want to run skill publishing from CI, call ClawHub's reusable
skill-publish.yml workflow
from a small workflow in your repo.
The example below is shaped for a catalog repo: operators choose whether to preview the full catalog, publish one skill folder, or publish the whole catalog.
name: Publish Skills to ClawHub on: workflow_dispatch: inputs: mode: description: What to run. type: choice required: true default: dry-run options: - dry-run - publish-single - publish-catalog skill_path: description: Skill folder for publish-single, for example skills/<slug>. type: string required: false default: "" permissions: contents: read id-token: write jobs: validate-single: if: github.event_name == 'workflow_dispatch' && inputs.mode == 'publish-single' runs-on: ubuntu-latest steps: - name: Validate single-skill input env: SKILL_PATH: ${{ inputs.skill_path }} run: | set -euo pipefail if [[ -z "${SKILL_PATH}" ]]; then echo "::error::skill_path is required when mode is publish-single." exit 1 fi case "${SKILL_PATH}" in skills/*) ;; *) echo "::error::skill_path must point under skills/, for example skills/<slug>." exit 1 ;; esac dry-run: if: github.event_name == 'workflow_dispatch' && inputs.mode == 'dry-run' uses: openclaw/clawhub/.github/workflows/skill-publish.yml@main with: owner: <owner> dry_run: true secrets: clawhub_token: ${{ secrets.CLAWHUB_TOKEN }} publish-single: if: github.event_name == 'workflow_dispatch' && inputs.mode == 'publish-single' needs: validate-single uses: openclaw/clawhub/.github/workflows/skill-publish.yml@main with: owner: <owner> skill_path: ${{ inputs.skill_path }} dry_run: false secrets: clawhub_token: ${{ secrets.CLAWHUB_TOKEN }} publish-catalog: if: github.event_name == 'workflow_dispatch' && inputs.mode == 'publish-catalog' uses: openclaw/clawhub/.github/workflows/skill-publish.yml@main with: owner: <owner> dry_run: false secrets: clawhub_token: ${{ secrets.CLAWHUB_TOKEN }}Replace <owner> with your ClawHub owner handle. The called workflow defaults to
scanning skills/; pass skill_path only when you want to process one folder.
Before running a real publish, sign in as a ClawHub user that can publish to the
selected owner, then store the current CLI token as a CLAWHUB_TOKEN repository
secret:
clawhub login --label "Skills GitHub Actions"gh secret set CLAWHUB_TOKEN \ --repo OWNER/REPO \ --body "$(clawhub token)"Start with dry-run, then publish one skill with publish-single, and only then
use publish-catalog for the full catalog.
Plugins
Plugins use npm-style package names. Scoped package names include the owner in the first part of the name:
@owner/package-nameThe scope must match the selected publish owner. If your package is named
@openclaw/dronzer, it can only be published as @openclaw. If you publish as
@vintageayu, rename the package to @vintageayu/dronzer.
This prevents a package from claiming an org namespace that the publisher does not control.
Before Publishing a Plugin
- Pick an owner that matches the package scope.
- Include
openclaw.plugin.json. Code plugins also needpackage.jsonwithopenclaw.compat.pluginApiandopenclaw.build.openclawVersion. - Include source repository and exact commit metadata, or use the CLI from a GitHub-backed checkout so it can detect them.
- Run
clawhub package publish <source> --dry-runbefore creating a release. - Expect new releases to stay out of public install surfaces until automated security checks and verification finish.
FAQ
Package scope must match selected owner
If the package scope and selected owner do not match, ClawHub rejects the publish:
Package scope "@openclaw" must match selected owner "@vintageayu".Publish as "@openclaw" or rename this package to "@vintageayu/dronzer".To fix it, either choose the owner named by the package scope, or rename the package so the scope matches the owner you can publish as.
If the package name already has the right scope but the package is owned by the wrong publisher, transfer ownership instead:
clawhub package transfer @opik/opik-openclaw --to opikUse package or skill transfer only when you have admin access to both the current owner and the destination publisher. Package transfer does not let you publish into a scope you cannot manage.
This protects org namespaces. A package named @openclaw/dronzer claims the
@openclaw namespace, so only publishers with access to the @openclaw owner
can publish it.