skill-publish is the official CLI and GitHub Action for publishing trustless, immutable, on-chain skill releases through the HOL Registry Broker.
Instead of sharing mutable URLs or copy/paste blobs, each name@version release is recorded on Hedera (HCS) and exposed via hcs://... references. That immutability is the value: the published artifact is tamper-evident, reproducible, and audit-friendly.
Immutability gives you:
- Version pinning: consumers can depend on an exact
name@version. - Reproducible retrieval: the same canonical references resolve later (not “whatever is at this URL today”).
- Audit trail: topic IDs, job IDs, and optional repo+commit stamping connect releases back to source.
A skill package is SKILL.md + skill.json (plus optional files). The action validates, quotes, publishes, waits for completion, and emits outputs.
By default, skill-publish excludes hidden files and directories, env files, lockfiles, build output, local databases, and key/certificate material from package discovery before quote or publish.
Choose the path that matches how you work:
Add the official action to your repo and publish on GitHub releases:
name: Publish Skill
on:
release:
types: [published]
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
issues: write
steps:
- uses: actions/checkout@v4
- name: Publish skill package
uses: hashgraph-online/skill-publish@v1
with:
api-key: ${{ secrets.RB_API_KEY }}
skill-dir: skills/my-skill
annotate: "true"
github-token: ${{ github.token }}npx skill-publish
npx skill-publish setup --account-id 0.0.12345 --hedera-private-key <key>
npx skill-publish create ./weather-skill --name weather-skill --preset api
npx skill-publish publish ./weather-skillAfter publish, use the returned canonical skill page, badge snippet, and resolver URLs to share a version-pinned release.
If you already have a repo and wallet, this is the shortest path to a live page:
npx skill-publish setup --account-id 0.0.12345 --hedera-private-key <key>
npx skill-publish setup-action . --skill-dir .
git tag v1.0.0 && git push --tagsThat gives you a live Registry page, pinned install URLs, and share-ready badge snippets from the action outputs.
- CLI (npx)
- First Publish in Under 5 Minutes
- Golden Workflow Templates
- Trust and Security Defaults
- Troubleshooting Matrix
- Canonical References
The CLI now supports guided, Vercel-style command discovery:
npx skill-publish
npx skill-publish --helpCore flows:
npx skill-publish setup --account-id 0.0.12345 --hedera-private-key <key> --hbar 5
npx skill-publish create ./weather-skill --name weather-skill --preset api
npx skill-publish init ./skills/my-skill
npx skill-publish doctor ./skills/my-skill
npx skill-publish doctor ./skills/my-skill --fix --local-only
npx skill-publish validate ./skills/my-skill
RB_API_KEY=rbk_xxx npx skill-publish quote ./skills/my-skill
RB_API_KEY=rbk_xxx npx skill-publish publish ./skills/my-skillRepository automation flows:
# Add a publish workflow to an existing SKILL.md repository
npx skill-publish setup-action . --skill-dir skills/my-skill
# Scaffold a new repository with skill package + GitHub workflow preconfigured
npx skill-publish scaffold-repo ./weather-skill --name weather-skill
# Golden path: scaffold repo, repair package metadata, and prepare for publish
npx skill-publish create ./weather-skill --name weather-skill --preset apiDistribution helper flows:
npx skill-publish badge ./skills/my-skill
npx skill-publish install-url ./skills/my-skill --format summary
npx skill-publish install-url --name programmable-secrets --version 1.0.1 --format pinned-skill-md
npx skill-publish release-notes ./skills/my-skill
npx skill-publish readme-snippet ./skills/my-skill
npx skill-publish attested-kit ./skills/my-skill --format json
npx skill-publish apply-kit ./skills/my-skill --repo-dir . --docs-path docs/my-skill.md
npx skill-publish submit-indexnow ./skills/my-skillskill-publish can now generate an attested distribution kit for each resolved name@version.
The kit includes:
- canonical HOL page URL
- machine-readable
entity.json - badge markdown and HTML
- release notes, README, and docs snippets
- package metadata block
codemeta.json- IndexNow submission targets
Typical flow:
npx skill-publish attested-kit ./skills/my-skill --format json
npx skill-publish apply-kit ./skills/my-skill --repo-dir . --docs-path docs/my-skill.md
npx skill-publish submit-indexnow ./skills/my-skillWallet-first bootstrap:
# Create API key via ledger challenge/verify and top up credits in one command
npx skill-publish setup \
--account-id 0.0.12345 \
--network hedera:testnet \
--hedera-private-key <key> \
--hbar 5What setup does:
- requests a ledger challenge from the broker
- signs locally with your Hedera private key
- verifies the challenge and receives an API key
- stores the key in
~/.skill-publish/credentials.json(unless--no-save) - optionally purchases credits with
--hbar
After setup, quote and publish automatically reuse the stored key, so you can run:
npx skill-publish doctor ./skills/my-skill
npx skill-publish quote ./skills/my-skill
npx skill-publish publish ./skills/my-skillpublish remains the default command, so legacy flag-only usage still works:
RB_API_KEY=rbk_xxx npx skill-publish --skill-dir ./skills/my-skillOptional overrides:
npx skill-publish \
publish \
--api-key rbk_xxx \
--skill-dir ./skills/my-skill \
--version 1.2.3 \
--annotate falseDry run behavior:
npx skill-publish publish ./skills/my-skill --dry-run
# no key => validate-only
# with key => quote-onlyUse this path when you want the full CI/CD setup with GitHub releases and annotations.
- Generate an API key: https://hol.org/registry/docs?tab=api-keys
- Add credits: https://hol.org/registry/docs?tab=credits
- Add
RB_API_KEYas a GitHub secret. - Commit
SKILL.mdandskill.jsonto your repo. - Add this workflow and publish a release.
name: Publish Skill
on:
release:
types: [published]
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
issues: write
steps:
- uses: actions/checkout@v4
- name: Publish skill package
uses: hashgraph-online/skill-publish@v1
with:
api-key: ${{ secrets.RB_API_KEY }}
skill-dir: skills/my-skill
annotate: "true"
github-token: ${{ github.token }}Expected success signal:
- workflow output includes
published=true - output includes
skill-json-hrl(hcs://...) for your immutable release reference
skills/my-skill/
├── SKILL.md
└── skill.json
Example skill.json:
{
"name": "my-skill",
"version": "0.1.0",
"description": "Example skill package"
}These paths are never included in publish payloads:
- hidden paths such as
.env,.env.local,.gitignore,.github/,.vscode/ - lockfiles such as
pnpm-lock.yaml,package-lock.json,yarn.lock,bun.lockb - build and dependency output such as
node_modules/,dist/,build/,.next/,coverage/ - local state and sensitive material such as
*.db,*.sqlite,*.pem,*.key,*.p12,*.pfx
If you need to ship a supporting artifact, keep it in a normal visible path inside the skill directory.
Use these copy-ready templates:
- Release-driven publish:
examples/workflows/publish-on-release.yml - Manual publish (
workflow_dispatch):examples/workflows/publish-manual.yml - Monorepo path-filtered publish:
examples/workflows/publish-monorepo-paths.yml
Most “skills” get shared as copy/paste blobs or mutable links. That works until you need version pinning, audits, or reproducibility.
In this context, a “trustless skill release” means:
- you publish an exact
name@version - consumers can later re-fetch the same published artifact by its canonical reference
- you can compare versions over time without relying on a private server or a package registry
- the published payload can be traced back to a repo + commit (default behavior)
This action exists to make that publish step deterministic and automated in CI.
| You provide | Action handles |
|---|---|
skill-dir with SKILL.md and skill.json |
file discovery, MIME detection, size checks |
RB_API_KEY secret |
authenticated API calls |
optional overrides (name, version) |
payload shaping and metadata stamping |
| optional annotation settings | release/PR annotation behavior |
| workflow trigger | quote/publish/job polling orchestration |
| Input | Required | Default | Description |
|---|---|---|---|
api-key |
Yes | - | Registry Broker API key. |
skill-dir |
Yes | - | Path containing SKILL.md and skill.json. |
api-base-url |
No | https://hol.org/registry/api/v1 |
Broker base URL (.../registry or .../registry/api/v1). |
account-id |
No | - | Optional Hedera account ID for publish authorization edge cases. |
name |
No | - | Optional skill name override for skill.json. |
version |
No | - | Optional version override for skill.json. Non-stable overrides are blocked on production by default. |
allow-nonstable-production-version |
No | false |
Explicitly permits publishing a non-stable custom version to the production registry. |
stamp-repo-commit |
No | true |
Stamp repo and commit metadata into payload. |
poll-timeout-ms |
No | 720000 |
Max time to wait for publish job completion. |
poll-interval-ms |
No | 4000 |
Interval between publish job status polls. |
annotate |
No | true |
Post publish result to release notes or merged PR comments. |
submit-indexnow |
No | false |
Submit canonical HOL skill URLs to IndexNow after publish or skip-existing. |
github-token |
No | - | Token used only when annotate=true. |
| Output | Description |
|---|---|
published |
true when publish executed, false when skipped. |
skip-reason |
Skip reason (currently version-exists). |
skill-name |
Skill name from publish result. |
skill-version |
Skill version from publish result. |
quote-id |
Broker quote identifier. |
job-id |
Publish job identifier. |
directory-topic-id |
Skill directory topic ID. |
package-topic-id |
Skill package topic ID. |
skill-json-hrl |
Canonical hcs://... reference for skill.json. |
credits |
Credits consumed. |
estimated-cost-hbar |
Estimated HBAR cost from quote. |
skill-page-url |
Canonical skill detail page URL for the resolved name@version. |
entity-url |
Machine-readable entity.json URL for the canonical skill page. |
docs-url |
Canonical HOL docs URL for the registry. |
openapi-url |
Canonical OpenAPI URL for the registry API. |
install-url-pinned-skill-md |
Pinned SKILL.md resolver URL. |
install-url-latest-skill-md |
Latest SKILL.md resolver URL. |
install-url-pinned-manifest |
Pinned manifest resolver URL. |
install-url-latest-manifest |
Latest manifest resolver URL. |
install-metadata-pinned-url |
Pinned install metadata URL. |
install-metadata-latest-url |
Latest install metadata URL. |
badge-markdown |
Markdown badge snippet for the resolved version. |
badge-html |
HTML badge snippet for the resolved version. |
markdown-link |
Markdown link snippet for the canonical skill page. |
html-link |
HTML link snippet for the canonical skill page. |
readme-snippet |
README snippet with canonical install links. |
docs-snippet |
Docs snippet with canonical HOL links. |
citation-snippet |
Citation snippet pointing to canonical HOL metadata. |
release-notes |
Release notes snippet with install links and badge markdown. |
package-metadata-json |
JSON block for package metadata pointing at HOL canonical URLs. |
codemeta-json |
CodeMeta document for the resolved skill version. |
attested-kit-json |
Full attested distribution kit payload. |
next-actions |
Post-publish checklist with the best distribution next steps. |
annotation-target |
Annotation destination (release:<id>, pr:<id>, none, failed). |
indexnow-result |
IndexNow submission result when enabled. |
result-json |
Full result payload as JSON string. |
Useful references after publish:
directory-topic-id: where the skill record livespackage-topic-id: package/version topic referenceskill-json-hrl: canonical reference you can paste into docs, release notes, or toolingskill-page-url, install URL outputs, and snippets: ready-to-share distribution kit output for READMEs and release notes
An HRL looks like: hcs://1/0.0.12345
- name: Publish skill
id: publish_skill
uses: hashgraph-online/skill-publish@v1
with:
api-key: ${{ secrets.RB_API_KEY }}
skill-dir: skills/my-skill
- name: Notify only when new version published
if: steps.publish_skill.outputs.published == 'true'
run: |
echo "Published ${{
steps.publish_skill.outputs.skill-name
}}@${{
steps.publish_skill.outputs.skill-version
}}"- Discovers and validates package files in
skill-dir. - Resolves broker limits from
/skills/config. - Checks if
name@versionalready exists. - Requests quote via
POST /skills/quote. - Publishes via
POST /skills/publish. - Polls
GET /skills/jobs/{jobId}until completion. - Emits outputs, step summary, and optional GitHub annotations.
- If
name@versionalready exists, the action exits cleanly withpublished=falseandskip-reason=version-exists. - Publish failures return structured output in
result-jsonso CI can gate follow-up jobs. - Annotation failures do not hide publish status;
annotation-targetreports where comments were attempted.
- Recommended minimum permissions are
contents: write,pull-requests: write, andissues: write. - Store
RB_API_KEYin repository or organization secrets. - If you do not need GitHub annotations, set
annotate: "false"and omitgithub-token. - For strict supply-chain pinning, pin to a full commit SHA instead of
@v1:
uses: hashgraph-online/skill-publish@93aee116a8a4b8d90dcde8cfb64628bc255becde- When annotations are disabled, this tighter permission set is sufficient:
permissions:
contents: read| Symptom | Likely Cause | Fix |
|---|---|---|
skip-reason=version-exists |
Same name@version already published |
Bump version in skill.json and re-run. |
| Quote request fails | Missing credits or invalid package metadata | Top up credits, then validate skill.json fields and size limits. |
| Publish job times out | Broker load or long queue | Increase poll-timeout-ms (for example, 1200000) and re-run. |
published=true but no PR/release annotation |
Missing write scopes or missing github-token |
Add pull-requests: write, issues: write, contents: write, and pass github-token. |
| Missing file validation error | SKILL.md or skill.json not found under skill-dir |
Verify folder structure and skill-dir path in workflow. |
| API authentication error | Wrong or revoked API key | Regenerate key at /registry/docs?tab=api-keys and update RB_API_KEY secret. |
You do not need the full standard to use this action, but the storage and lookup rules follow HCS-26.
- the Registry Broker is the publish API surface
- the publish result includes topic IDs and
hcs://...HRLs that can be resolved independently
Full standard:
- npm package: https://www.npmjs.com/package/skill-publish
- Marketplace listing: https://github.com/marketplace/actions/skill-publish
- Registry landing page: https://hol.org/registry
- Skill index: https://hol.org/registry/skills
- Product docs: https://hol.org/docs/registry-broker/
- Interactive API docs: https://hol.org/registry/docs
- OpenAPI: https://hol.org/registry/api/v1/openapi.json
- Skill schema: https://raw.githubusercontent.com/hashgraph-online/skill-publish/main/schemas/skill.schema.json
If you reference this action in documentation or research, use CITATION.cff.