![]() |
The official skill-publish CLI and GitHub Action for validating, quoting, and publishing trustless, immutable, on-chain skill releases through the HOL Registry Broker. Built and maintained by Hashgraph Online. npm Package GitHub Marketplace HOL Registry DeepWiki Wiki |
|---|
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 starts with SKILL.md. skill.json is optional metadata; when it is absent, skill-publish synthesizes it during validate, quote, and publish flows.
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:
Start with a validate-only pull request workflow. This does not require RB_API_KEY, does not request id-token: write, and keeps the first rollout fork-safe by disabling preview upload until maintainers explicitly opt in.
name: Validate Skill
on:
pull_request:
paths:
- skills/my-skill/**
- .hol/skill-publish.yml
- .github/workflows/validate-skill.yml
jobs:
validate:
concurrency:
group: validate-skill-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- name: Validate skill package
uses: hashgraph-online/skill-publish@df6ae95e010d9792158a441eec9ac50d4d17139d
with:
mode: validate
skill-dir: skills/my-skill
annotate: "false"
preview-upload: "false"If you want preview uploads later, enable them only in a trusted repo-owned workflow such as workflow_dispatch or a protected-branch push, then add id-token: write and preview-upload: "true" there.
Publishing immutable releases still consumes HOL Registry Broker credits. Add RB_API_KEY only when you are ready to request an authenticated quote and then publish on-chain:
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@11bd71901bbe5b1630ceea73d27597364c9af683
- name: Publish skill package
uses: hashgraph-online/skill-publish@df6ae95e010d9792158a441eec9ac50d4d17139d
with:
mode: publish
api-key: ${{ secrets.RB_API_KEY }}
skill-dir: skills/my-skill
annotate: "true"
github-token: ${{ github.token }}npx skill-publish
npx skill-publish validate ./weather-skill
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 quote ./weather-skill
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 inspect-repo .
npx skill-publish setup-action . --skill-dir .
npx skill-publish setup --account-id 0.0.12345 --hedera-private-key <key>
git tag v1.0.0 && git push --tagsThat gives you validate-only CI first, then a live Registry page, pinned install URLs, and share-ready badge snippets once you have funded credits and publish a release.
- 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
npx skill-publish monitor ./skills/my-skill --quote-preview
npx skill-publish quote --skill-dir ./skills/my-skill
npx skill-publish publish --skill-dir ./skills/my-skillRepository automation flows:
# Inspect an existing repo before opening a workflow PR
npx skill-publish inspect-repo .
# 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
Outreach PRs only work when the target repository already contains a real HOL skill package. Use inspect-repo first:
npx skill-publish inspect-repo .
npx skill-publish inspect-repo . --jsonWhat inspect-repo checks:
- valid HOL packages with
SKILL.mdpresent - partial skill-like directories that are missing
SKILL.md - whether
setup-actioncan be added safely without guessing a skill directory
setup-action now refuses to generate workflows for repos that do not already contain a valid HOL skill package.
After setup, quote and publish automatically reuse the stored key, so you can run:
npx skill-publish doctor ./skills/my-skill
npx skill-publish validate ./skills/my-skill
npx skill-publish quote ./skills/my-skill
npx skill-publish publish ./skills/my-skillquote requires broker authentication, and publish requires both broker authentication and funded credits because the release is written on-chain.
publish 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 \
--mode validate \
--skill-dir ./skills/my-skillnpx 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-onlyGitHub Action modes:
with:
mode: validate # no RB_API_KEY required
annotate: "false"with:
mode: publish
api-key: ${{ secrets.RB_API_KEY }}Use 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.mdto your repo. Addskill.jsononly if you want to pin metadata explicitly instead of using synthesized defaults. - Add the validate workflow for pull requests, then add the publish workflow for releases.
Validate on pull requests without secrets:
name: Validate Skill
on:
pull_request:
paths:
- skills/my-skill/**
- .github/workflows/validate-skill.yml
jobs:
validate:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- name: Validate skill package
uses: hashgraph-online/skill-publish@v1
with:
mode: validate
skill-dir: skills/my-skill
annotate: "false"Publish immutable 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:
mode: publish
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 |
file discovery, MIME detection, size checks, synthesized metadata when skill.json is absent |
RB_API_KEY secret for quote and publish only |
authenticated broker calls that estimate or write on-chain state |
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 |
|---|---|---|---|
mode |
No | publish |
Execution mode: validate, monitor, quote, or publish. |
api-key |
Validate: No, Quote/Publish: Yes | - | Registry Broker API key. Publish still consumes credits and requires funded broker auth. |
skill-dir |
Yes | - | Path containing SKILL.md. skill.json is optional and will be synthesized when missing. |
repo-skill-dir |
No | - | Canonical repository path for status/domain lookups. Set this when skill-dir points to a staged package folder. |
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. |
preview-upload |
No | true |
When mode=validate or mode=monitor, upload preview state through GitHub OIDC when available. |
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. |
comment-mode |
No | state-changes |
Controls low-noise managed preview comment behavior for validate, monitor, and quote runs. |
comment-on-success |
No | true |
When false, skips managed preview comment updates after successful validate, monitor, or quote runs. |
quote-preview |
No | false |
Requests anonymous publish cost estimates during validate or monitor when available. |
conversion-hint-level |
No | soft |
Preview comment guidance verbosity: off, soft, or detailed. |
group-key |
No | skill directory | Optional grouping key for multi-skill monitor summaries. |
| Output | Description |
|---|---|
preview-json |
Validate/monitor preview artifact payload (skill-preview.v1). |
hcs28-json |
HCS-28 trust scoring payload generated in validate/monitor. |
hcs28-score-total |
HCS-28 total score from validate/monitor. |
preview-json-path |
Path to the generated preview JSON file. |
status-url |
Lifecycle status/preview page URL when available. |
trust-tier |
Lifecycle trust tier for the current state. |
publish-readiness |
Lifecycle readiness summary (ready, blocked, quoted, published). |
missing-requirements |
JSON array of requirements still blocking publish readiness. |
estimated-credits-range |
Estimated publish credit range from quote-preview. |
managed-comment-url |
Managed preview comment URL for PR runs. |
managed-comment-status |
Managed preview comment status (disabled, skipped, created, updated, unchanged, failed). |
managed-comment-reason |
Managed preview comment skip/failure reason when provided. |
publish-comment-url |
Sticky publish lifecycle PR comment URL when publish annotations run. |
publish-comment-status |
Publish comment status (disabled, skipped, created, updated, unchanged, failed). |
release-annotation-status |
Release body block status (disabled, skipped, created, updated, unchanged, failed). |
purchase-url |
HOL submit/purchase flow URL for credit setup. |
publish-url |
HOL publish flow URL for the resolved skill. |
verification-url |
HOL verification/domain-proof flow URL for trust upgrades. |
published |
true when publish executed, false when skipped. |
skip-reason |
Skip reason (for example version-exists). |
skill-name |
Skill name from resolved package metadata. |
skill-version |
Skill version from resolved package metadata. |
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 quoted/consumed. |
estimated-cost-hbar |
Estimated HBAR cost from quote. |
skill-page-url |
Canonical skill detail page URL for resolved name@version. |
entity-url |
Machine-readable entity.json URL for the skill page. |
docs-url |
Canonical HOL docs URL for Registry Broker. |
openapi-url |
Canonical OpenAPI URL for Registry Broker 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 resolved version. |
badge-html |
HTML badge snippet for resolved version. |
markdown-link |
Markdown link snippet for canonical skill page. |
html-link |
HTML link snippet for 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 metadata pointing to canonical HOL URLs. |
codemeta-json |
CodeMeta document for the resolved skill version. |
attested-kit-json |
Full attested distribution kit payload. |
next-actions |
Suggested post-run next actions summary. |
annotation-target |
Backward-compatible 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
}}"mode=validate
- Discovers and validates package files in
skill-dir. - Resolves broker limits from
/skills/config. - Emits
skill-preview.v1JSON plus lifecycle/share outputs. - Optionally uploads preview state through GitHub OIDC.
mode=quote
- 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. - Emits quote metadata without publishing.
mode=publish
- Discovers and validates package files in
skill-dir. - Resolves broker limits from
/skills/config. - Requests authenticated cost estimates via
POST /skills/quote. - Checks if
name@versionalready exists. - Publishes via
POST /skills/publish, then pollsGET /skills/jobs/{jobId}until completion. - Upserts sticky publish annotations (PR comment and/or release body block) when enabled.
- Emits outputs, step summary, and distribution snippets.
- 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. - Validate mode never quotes or publishes, and it does not require
RB_API_KEY.
- Validate workflows should grant only
contents: readby default when comments and preview uploads are disabled. - Preview uploads should be opt-in and limited to trusted repo-owned workflows. Do not grant
id-token: writeto fork-triggeredpull_requestjobs just to validate package structure. - Publish workflows that annotate releases or PRs typically also need
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@df6ae95e010d9792158a441eec9ac50d4d17139d- 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 package metadata or pass explicit name / version overrides if needed. |
| 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 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.
