ClawHub Skill Publish
Publish and maintain the ClawHub skill registry. All skills are published to a single ClawHub account (j3ffyang) through GitHub Actions; skills are never published manually.
Scope
Skills come from three repos under the negtivSpace superproject. Each repo has its own .github/workflows/clawhub-skill-sync.yml that publishes its skills to ClawHub:
history/— publishes only.opencode/skills/chinese-history-literature-culture(via askill_pathentry). The other skills inhistory/.opencode/skills/(character-name-literary-origins,simplified-to-traditional) are local-only: they stay in the repo for opencode to load but are not published to ClawHub. (simplified-to-traditionalis published from its canonicalai-thoughtscopy.)ai-thoughts/.opencode/skills/— publishes every.opencode/skills/<slug>/SKILL.mdfolder via a glob, so any new skill is published automatically andpublish-skillsself-publishes like any other. Untracked/uncommitted folders are not on ClawHub until they are committed and pushed.ai-custom-skills/— rootsopenclaw/,hermes/,claude-code/(each publishes its*/SKILL.mdsubfolders), plus the double-nestedclaude-code/perplexity-downloader/perplexity-downloaderhandled via a matrixskill_pathentry. Folders without aSKILL.md(e.g.openclaw/twitter-bookmarks-exporter) are skipped automatically.
Single-source rule — read before anything else
- Only the
j3ffyang/*copies of these repos publish. Thenegtivspace/*copies keep the same workflow file (mirrors stay in sync) but are a no-op: every job is guarded withgithub.repository_owner == 'j3ffyang'. - Every skill update ships. Whenever a
SKILL.mdis created or changed in anynegtivSpacerepo, commit it and push to both remotes (j3ffyang+negtivspace) in the same change — an unpushed skill is an unpublished one. Thej3ffyangpush runsclawhub-skill-sync.yml; afterwards, verify the new version is live via the skills API (latestVersion). Don't leave a skill edit uncommitted or only on one remote. - Both copies are pushed on every change, so both repos run the workflow on push. Without the owner guard they would both publish to the same ClawHub account and race, producing
Version X already existscollisions. - Never create or run a manual publish path that could double-publish to ClawHub. If a skill edit is needed, edit it in the working repo, push to both remotes, and let the workflow publish once.
clawhub_token(thej3ffyangClawHub token) is set as a repo secret in all six repo copies; only thej3ffyangones ever use it.
Pipeline
- Workflow per repo:
clawhub-skill-sync.ymlwith adry-runjob (pull requests only) and apublishjob (pushes /workflow_dispatch). history/andai-custom-skills/call the reusable workflowopenclaw/clawhub/.github/workflows/skill-publish.ymlpinned to tagv0.23.3(no@v1tag exists). Both their jobs needpermissions: {contents: read, id-token: write}; callers fail withstartup_failure(id-token: none) if the job-level permission is missing.ai-thoughts/instead runs the in-reposcripts/clawhub_publish.py, which invokes the pinned ClawHub CLI (clawhub-source, v0.23.3) directly withbunand a config file written fromsecrets.clawhub_token; its jobs need onlypermissions: {contents: read}.- Publishing uses the caller repo's checkout; a new or changed skill is detected by fingerprint. Unchanged skills are skipped (
alreadySynced/unchanged).
Status & version semantics
unchanged/alreadySynced— fingerprint matches ClawHub; nothing to do.- New skill — first publish is version
1.0.0. - Changed skill — next patch version of the latest published version.
Error: Version X.Y.Z already exists. Increment the version number...— the skill is already on ClawHub at that version (usually from a prior publish or a dual-remote race). Do not re-publish; the workflow will report italreadySyncedon the next run.Invalid publish output: 'pending-publication'— a false alarm. The publish actually succeeded; the upstream workflow's status map (v0.23.3) does not recognize thepending-publicationstatus string and reports it as failed. Verify with the skills API before assuming a problem.
Procedure
- Add or edit a skill: create/update the
SKILL.md(and sibling files) in the correct root of the correct repo. Respect that repo's conventions (e.g.history/AGENTS.mdfilename rules). Do not rename or convert skills; publish them as-is. - Push to both remotes of the submodule (
j3ffyangandnegtivspace). The push toj3ffyang/*triggers the publish; thenegtivspace/*run is a no-op by design. - Wait for the
j3ffyang/*workflow run to finish; check the publish summary for the affected slug. - Manually trigger a publish (e.g. after a failed run) via
workflow_dispatchon thej3ffyang/*repo. - Verify on ClawHub (read-only, API):
curl -s -H "Authorization: Bearer $CLH_TOKEN" https://clawhub.ai/api/v1/skills/<slug>— thelatestVersionandowner.handlefields confirm what is live.
Error Handling
Version X.Y.Z already exists— confirm the skill already exists (skills API) and let the next run mark italreadySynced; if the local content is genuinely newer, the workflow's next-patch bump handles it on its own.pending-publicationreported as failure — treat as success; the wrapper script (v0.23.3) does not map this CLI status, so the run shows a redXeven though the upload went through. Verification has propagation lag: the skills API may keep serving the previouslatestVersion(and olddescription) for a few minutes, so a first check looks like a real miss. Re-poll.../skills/<slug>and.../skills/<slug>/versionsfor a few minutes; confirmlatestVersionbumped and the new text is indescriptionbefore concluding failure.startup_failure/id-token: none— the caller job is missingpermissions: {contents: read, id-token: write}; add it.- Nested skill not found — the matrix
skill_pathmust point at the folder containing theSKILL.md(double-nested folders need the full path). - Slug collision —
simplified-to-traditionalexists in bothhistoryandai-thoughts.ai-thoughtspublishes the canonical copy;history's copy is local-only, kept out of ClawHub viaskill_path. Never publish the same slug from two repos to the same owner. - Protected slug namespace — ClawHub rejects any slug starting with
clawhub-or ending with-clawhub(Error: "... uses the protected "clawhub" slug namespace"). This skill wentskill-publish→clawhub-publish(rejected) →publish-skills. The originalskill-publishslug is ambiguous across owners (other users have their own), sopublish-skillsis the canonical, unique slug; the legacy@j3ffyang/skill-publishstays on ClawHub (no delete-via-push). - Token missing — publish fails without
clawhub_token; it must be set as a secret on thej3ffyang/*repo.
Verification
- All three workflow files carry
github.repository_owner == 'j3ffyang'guards on both jobs. actionlintpasses on everyclawhub-skill-sync.yml.- Every expected slug appears in the
j3ffyang/*run's publish summary asalreadySyncedorpublished. - Skills API returns
owner.handle == 'j3ffyang'and the expectedlatestVersionfor every published skill.
