| name | skill-hub-query |
| description | Query, install, update, and edit AI agent skills on any compatible Skill Hub (self-hosted, or any Hub implementing the documented API contract). Dual-channel: with a token it uses the authenticated API (full features including private skills); without a token it falls back to the unauthenticated channel (public skills only). Covers: list newly published skills, search by keyword / author / time / source, inspect version history, install or upgrade a specific version, and edit a skill's card metadata (display name, summary, tags, visibility, applicable position, etc.) via a safety-first GET -> diff -> backup -> PUT -> dual-channel verify -> auto-rollback flow. Trigger phrases include "what's new on the hub", "search for X skill", "install X", "update Y skill", "edit hub card info", "show skill version history", "skill-hub-query". |
skill-hub-query
Drive any compatible Skill Hub from the command line with a single,
predictable interface. Works with self-hosted Hubs that implement the
documented API contract.
Heads-up: this tool talks to Hubs that implement the API contract below.
It does NOT target clawhub.ai โ that Hub has its own
API surface and an official CLI named clawhub. Use this tool when you have
a private or compatible Hub to drive.
Agent workflow
Dual-channel auto-selection
When the user asks a Hub-related question ("what's on the hub", "install X",
"search for Y"), run sync.sh / query.sh / install.sh directly โ the
scripts pick the right channel:
| User state | Channel | Capability |
|---|
| Token set (env or credentials file) | OpenAPI (<HUB_API_PREFIX>/* with auth header) | Full features incl. private skills |
| No token | Legacy fallback (<HUB_LEGACY_API_PREFIX>/* without auth) | Search & install public skills |
When falling back the first time, the script emits a one-shot notice
suggesting the user request a token for long-term stability. After that it
stays silent.
When to actively suggest the user configure a token
Only when the user explicitly needs to:
- install a private skill (search finds it, but download requires auth)
- get contract-stable, long-term behavior (legacy fallback may be removed)
- when
doctor.sh explicitly recommends it
Setting up the token (after the user provides one)
export SKILL_HUB_URL="https://hub.your-company.com"
export SKILL_HUB_TOKEN="<your-token>"
mkdir -p "${XDG_CONFIG_HOME:-$HOME/.config}/skill-hub-query"
cat > "${XDG_CONFIG_HOME:-$HOME/.config}/skill-hub-query/credentials.json" <<EOF
{
"endpoint": "https://hub.your-company.com",
"token": "<your-token>",
"authHeader": "Authorization",
"authScheme": "Bearer "
}
EOF
chmod 600 "${XDG_CONFIG_HOME:-$HOME/.config}/skill-hub-query/credentials.json"
Then verify with bash scripts/doctor.sh.
Never echo a full token back to the user, write it outside the credentials
directory, or commit it to git.
"What's on the hub for X?"
- Silently
bash sync.sh (incremental; zero HTTP if nothing changed)
bash query.sh keyword X
- Reply with a user-readable table (name / author / version / updated / summary), not raw IDs
- If โค5 hits include the summary; if many, list top 10 + total count
"Install X"
bash sync.sh then bash query.sh slug X to get the latest version and summary
- Confirm first: "Will install {displayName} v{latest} (author X). Proceed?"
- After user approves, run:
bash install.sh X --yes
- Without
--yes, install.sh blocks on stdin for already-installed skills; in non-interactive mode it refuses outright โ preventing silent overwrite
- Show: "installed; will be loaded on the next agent session"
"Install a batch"
- Query each slug for version + permission info
- Show one combined manifest + estimated download size, wait for approval
- After approval, install serially with
install.sh <slug> --yes (avoid rate limiting); report failures separately
Configuration
โ ๏ธ You MUST configure SKILL_HUB_URL (or .endpoint in the credentials
file) before any network call. There is no baked-in default, because no
single public Hub is guaranteed to implement this contract. Run
bash scripts/doctor.sh first โ it will tell you exactly what's missing.
| Env variable | Default | Purpose |
|---|
SKILL_HUB_PROVIDER | (unset) | Select a built-in adapter for a known public Hub instead of the generic contract. Currently supports skillhub_cn (see Built-in provider: skillhub.cn). When unset, the generic-contract behavior below applies. |
SKILL_HUB_URL | (must be set) | Hub base URL, e.g. https://hub.your-company.com (ignored when SKILL_HUB_PROVIDER is set) |
SKILL_HUB_API_PREFIX | /api/v1/skill | Primary API path |
SKILL_HUB_LEGACY_API_PREFIX | /api/skill | Fallback API path |
SKILL_HUB_AUTH_HEADER | Authorization | HTTP header name for auth |
SKILL_HUB_AUTH_SCHEME | Bearer | Header value prefix (note trailing space; set to "" for API-key auth) |
SKILL_HUB_TOKEN | (unset) | API token (takes precedence over credentials file) |
SKILL_HUB_TOKEN_FILE | ${XDG_CONFIG_HOME:-~/.config}/skill-hub-query/credentials.json | Credentials file |
SKILL_HUB_SKILLS_DIR | (auto-detect) | Where installed skills land |
SKILL_HUB_CACHE_DIR | ${XDG_CACHE_HOME:-~/.cache}/skill-hub-query | Where the local cache lives |
SKILL_HUB_EDIT_PREFIX | same as SKILL_HUB_LEGACY_API_PREFIX | Path prefix for /edit and /detail (edit.sh only) |
SKILL_HUB_DISABLE_EDIT | 0 | Set to 1 to disable edit.sh when your Hub does not implement /edit |
SKILL_HUB_BACKUP_RETENTION | 20 | How many recent edit.sh backups to keep per slug (older are pruned) |
SKILL_HUB_DOWNLOAD_TIMEOUT | 120 | curl --max-time (seconds) for skill ZIP download in install.sh |
SKILL_HUB_OWNER_EMAIL | (auto: git config user.email) | Email used by edit.sh owner pre-check; override if your git identity differs from your Hub identity |
Skills install directory
Resolved in order: SKILL_HUB_SKILLS_DIR -> ~/.claude/skills/ ->
~/.openclaw/workspace/skills/ -> ~/.config/skills/ (first existing wins).
Setting up Hub URL + token (one-time)
echo 'export SKILL_HUB_URL="https://hub.your-company.com"' >> ~/.bashrc
echo 'export SKILL_HUB_TOKEN="<your-token>"' >> ~/.bashrc
source ~/.bashrc
Or โ for richer per-Hub profiles โ use the credentials file:
mkdir -p "${XDG_CONFIG_HOME:-$HOME/.config}/skill-hub-query"
cat > "${XDG_CONFIG_HOME:-$HOME/.config}/skill-hub-query/credentials.json" <<EOF
{
"endpoint": "https://hub.your-company.com",
"token": "<your-token>",
"authHeader": "Authorization",
"authScheme": "Bearer "
}
EOF
chmod 600 "${XDG_CONFIG_HOME:-$HOME/.config}/skill-hub-query/credentials.json"
Never commit tokens to git, never hardcode them in scripts, and never
echo the full token to the user.
Built-in provider: skillhub.cn
skillhub.cn is a China-optimized public skills hub.
Because its API shape differs from the generic contract above, this skill ships
a built-in adapter for it. Activate it with:
export SKILL_HUB_PROVIDER=skillhub_cn
echo 'export SKILL_HUB_PROVIDER=skillhub_cn' >> ~/.bashrc
When the provider is active, SKILL_HUB_URL / token / API-prefix env vars are
ignored โ the adapter targets https://api.skillhub.cn directly. No token
is needed (all supported operations are public, read-only).
Capability matrix (skillhub.cn)
| Operation | Command | Supported? |
|---|
| Search / browse | query.sh keyword <kw> ยท query.sh today ยท query.sh combo --keyword= --category= --source= | โ
live (no local cache) |
| Skill detail | query.sh slug <slug> | โ
|
| Version history | query.sh versions <slug> | โ
|
| Install | install.sh <slug> [--yes] | โ
|
sync.sh | โ | โช no-op (live search needs no cache; informational, exit 0) |
query.sh author <handle> | โ | โ no author-filter param on skillhub.cn (use keyword) |
edit.sh (edit card metadata) | โ | โ not available โ see below |
Why edit is not supported on skillhub.cn
skillhub.cn card metadata (displayName / summary / tags / category) is a
one-way mirror synced from the upstream source (clawhub / GitHub). The only
write endpoints the platform exposes are publish / unlist / relist / delete /
claim โ none of which edit card fields. To change a card, update the
upstream source and re-publish/let it re-sync. (This differs from a
generic Hub that implements a PUT /edit contract, which edit.sh drives.)
Examples (skillhub.cn)
export SKILL_HUB_PROVIDER=skillhub_cn
bash scripts/query.sh keyword code
bash scripts/query.sh today
bash scripts/query.sh slug skill-creator
bash scripts/query.sh versions skill-creator
bash scripts/install.sh skill-creator --yes
bash scripts/doctor.sh
Self-check / diagnosis
bash scripts/doctor.sh
doctor.sh probes both channels (OpenAPI with token, legacy without) plus
optionally the /edit endpoint. If at least one channel works, the skill is
usable.
Cache & performance
All list queries hit a local JSON cache (${SKILL_HUB_CACHE_DIR}/skill-cache.json),
parsed with jq (sub-ms).
| Trigger | Sync action |
|---|
| Cache missing or corrupt | Full sync |
| User asks "refresh cache" | Forced full sync |
| Routine query | Incremental (records with updatedAt newer than cursor) |
| Incremental page 1 entirely new (= 100 records) | Upgrade to full sync |
Incremental sync does NOT prune removed/withdrawn skills (it only unions
new records). If you hit a "found in cache but install 404s" case, run
bash sync.sh --full. The full sync log will report "pruned N removed".
Multi-user / shared-host caveat
The legacy channel (no token) identifies callers by source IP. On shared
hosts (containers, CI runners), all agents/users share one identity.
scope=mine returns the list for that shared identity.
For per-user isolation on shared hosts, configure a per-user SKILL_HUB_TOKEN.
Quick reference: scenarios
Scenario 1: search
| User request | Action |
|---|
| "Search for calendar-related skills" | bash sync.sh && bash query.sh keyword calendar |
| "What was published this week?" | bash sync.sh && bash query.sh time this_week |
| "Anything on 2026-05-20?" | bash query.sh time 2026-05-20 (single day: 00:00 - 23:59) |
| "Between 5/18 and 5/22?" | bash query.sh time 2026-05-18:2026-05-22 |
| "Last week by user X?" | bash sync.sh && bash query.sh combo --since=last_week --author=X |
| "Only this account (avoid prefix collisions)" | bash query.sh author alice@example.com --exact |
| "Official skills today?" | bash sync.sh && bash query.sh combo --since=today --source=official |
| "Show details of skill XX" | bash query.sh slug XX |
Scenario 2: install / update
| User request | Action |
|---|
| "Install calendar" | 1) Check cached version 2) Confirm with user 3) After approval: bash install.sh calendar --yes |
| "Update html-go-live to latest" | First query.sh slug html-go-live for new version + confirm with user -> after approval bash install.sh html-go-live --yes (--yes must be user-authorized) |
| "Install html-go-live 2.4.0" | Same confirmation flow -> after approval bash install.sh html-go-live 2.4.0 --yes |
| "Search skillhub.cn for X" | SKILL_HUB_PROVIDER=skillhub_cn bash query.sh keyword X (no token; see Built-in provider: skillhub.cn) |
| "Install X from skillhub.cn" | SKILL_HUB_PROVIDER=skillhub_cn bash install.sh X --yes |
--yes is a user-authorization flag; an LLM/agent caller must not add it on its own.
The user must explicitly say "yes" / "go ahead" / "install" first; SKILL.md examples in
automated paths intentionally omit --yes.
Scenario 3: version history
| User request | Action |
|---|
| "Version history of html-go-live" | source scripts/_lib.sh && api_get "${HUB_API_PREFIX}/versions/html-go-live?limit=20" | jq |
| "What changed in 2.4.0?" | api_get "${HUB_API_PREFIX}/versions/html-go-live/2.4.0" | jq .data.version.changelog |
Scenario 4: diagnose / refresh
| User request | Action |
|---|
| "skill-hub-query is broken / I can't find anything" | bash doctor.sh (probes all channels and reports the precise issue) |
| "Refresh cache / rebuild cache / prune removed skills" | bash sync.sh --full |
Scenario 5: edit a skill's card metadata
Use edit.sh to modify the Hub card for a skill you own. You can only edit
skills you own; non-owners get 403 from the Hub.
Hub compatibility: This requires your Hub to implement
PUT /edit/<slug> and GET /detail/<slug>. If your Hub does not implement
them, run: export SKILL_HUB_DISABLE_EDIT=1 and edit.sh will refuse to run
with an informative message instead of producing confusing errors.
| User request | Action |
|---|
| "Show current card info for my-skill" | bash edit.sh <slug> --show |
| "Change summary of my-skill to xxx" | First --show or --dry-run to confirm -> after approval: bash edit.sh <slug> --summary "xxx" --yes |
| "Add tags Demo / Test to my-skill" | First --show to grab current tags, build the merged list -> after approval bash edit.sh <slug> --tags "old1,old2,Demo,Test" --yes |
| "Change visibility of my-skill to public" | High-risk: surface the prompt to the user explicitly (including any Hub-side policy that may silently downgrade) -> after explicit approval add --yes |
Agent caller rule (same as install.sh): --yes is a user-authorization
flag. An agent must NOT add it on its own; the human user must explicitly
approve. Without --yes, edit.sh blocks on stdin in a TTY and refuses to
proceed in non-interactive mode.
Array fields (tags / scene / business / ...) are full overwrites, not
additive. To append, first --show to read the current list, then submit
the merged list.
Supported fields: see bash edit.sh --help for the full list of CLI flags.
Safety guarantees (five-stage flow):
- GET the authoritative current value
- Owner pre-check (server-side 403 is the ultimate safety net)
- Build patch + show diff (skip PUT if no actual diff)
- Backup to disk + user confirm (backups in
${SKILL_HUB_CACHE_DIR}/edit-backups/, latest 20 per slug)
- PUT + dual-channel verify with retry + auto-rollback on mismatch
(visibility silent-downgrade is a documented partial-success edge case)
Self-hosted Hub: API contract
Your Hub must implement these endpoints (response envelope
{code: 200, message: "", data: {...}}):
GET <endpoint><SKILL_HUB_API_PREFIX>/search?page=N&size=N&orderBy=updatedAt&order=desc
-> data: {records: [<skill>...], total: <number>}
GET <endpoint><SKILL_HUB_API_PREFIX>/versions/<slug>?limit=N
-> data: {items: [{version, changelog, ...}, ...]}
GET <endpoint><SKILL_HUB_API_PREFIX>/versions/<slug>/<version>
-> data: {version: {...}}
GET <endpoint><SKILL_HUB_LEGACY_API_PREFIX>/download/<slug>?version=<v>&track=true
-> body: zip bytes (Content-Type may be application/octet-stream)
Each <skill> record minimally contains:
{
"slug": "string",
"displayName": "string",
"summary": "string",
"owner": {"displayName": "...", "handle": "...", "email": "..."},
"source": "official|personal|external",
"updatedAt": <epoch_ms>,
"latestVersion": {"version": "x.y.z"}
}
For edit.sh (optional), additionally:
PUT <endpoint><SKILL_HUB_EDIT_PREFIX>/edit/<slug>
body = JSON patch (any subset of editable fields)
empty body returns the current snapshot
-> data: <full skill metadata>
GET <endpoint><SKILL_HUB_EDIT_PREFIX>/detail/<slug>
-> data: {skill: <full metadata>}
If your Hub uses a different auth scheme, override SKILL_HUB_AUTH_HEADER and
SKILL_HUB_AUTH_SCHEME (e.g. SKILL_HUB_AUTH_HEADER=X-API-Key
SKILL_HUB_AUTH_SCHEME="").
๐ Need the full request/response field reference? When implementing or
debugging a self-hosted Hub, read references/api.md โ
it documents every endpoint's exact parameters, response envelope, and field
semantics in detail.
File layout
skill-hub-query/
โโโ SKILL.md # this file
โโโ credentials.example.json # template for the credentials file
โโโ references/
โ โโโ api.md # detailed API contract reference
โโโ scripts/
โโโ _lib.sh # path discovery + token + curl wrapper (sourced)
โโโ _edit_lib.sh # edit.sh internals (sourced)
โโโ doctor.sh # one-shot self-check
โโโ sync.sh # full / incremental cache sync
โโโ query.sh # query the local cache
โโโ install.sh # download + safe extract + atomic dir replace
โโโ edit.sh # five-stage safe metadata editor (optional Hub features)
Cache & credentials (NOT in skill directory, NOT git-tracked):
${SKILL_HUB_CACHE_DIR:-~/.cache/skill-hub-query}/
โโโ skill-cache.json # full skill index (key = slug)
โโโ skill-cache-meta.json # sync cursor + metadata
โโโ skill-versions.json # locally installed skill versions
โโโ edit-backups/ # snapshots before each edit (latest 20 per slug)
${XDG_CONFIG_HOME:-~/.config}/skill-hub-query/credentials.json (chmod 600)
Direct API call pattern (advanced)
source ./scripts/_lib.sh
api_get "${HUB_API_PREFIX}/search?keyword=calendar&size=20"
api_get "${HUB_API_PREFIX}/versions/html-go-live?limit=10"
api_get "${HUB_API_PREFIX}/versions/html-go-live/2.4.0"
api_download "html-go-live" "2.4.0" "/tmp/x.zip"
For direct curl calls, pass the auth header when you have a token:
-H "$(load_auth_header): $(load_auth_scheme)$SKILL_HUB_TOKEN".
Error reference
| Error | What to do |
|---|
[info] No SKILL_HUB_TOKEN configured, falling back to legacy channel | Normal; consider setting a token for long-term stability |
[error] No SKILL_HUB_TOKEN found, and the legacy fallback channel is unavailable | Both channels are down; run doctor.sh to pinpoint |
HTTP 401 / token invalid | Token expired or revoked; refresh it or remove it to fall back to legacy |
[error] Skill 'X' access denied (HTTP 403, private skill) | Private skill; configure a token with permission, or ask the owner |
[error] Skill 'X' is private (response code=403) | Same as above (some Hubs return 200 + JSON error) |
[error] Skill 'X' not found (HTTP 404) | Wrong slug / removed; try query.sh slug X and possibly sync.sh --full |
[error] Download failed: X (network error) | curl-layer failure (network/DNS); check connectivity |
zip contains unsafe paths | Defense against directory traversal; report to Hub maintainer |
Extracted content is missing SKILL.md | Malformed zip; aborted without touching existing install |
install failed; rolling back | Atomic dir replace failed (rare; usually disk full) |
X exists and --yes not given | Agent didn't get user authorization; have the user say "yes" first |
| Cache corruption (jq parse failure) | sync.sh rebuilds automatically |
edit.sh is disabled because SKILL_HUB_DISABLE_EDIT=1 | Your Hub does not expose /edit; unset the var only if it does |
Known limitations
- The ZIP download endpoint is not part of the formal OpenAPI spec on all Hubs;
install.sh uses the legacy /download/<slug> path (public skills: no auth needed; private: token required).
- Some legacy fields (
starredAt, starred, litToday, etc.) are deprecated and may be missing depending on Hub version.
- Incremental sync does not prune removed skills (see "Cache" section).
- The legacy channel is a transition path; for production / long-term use, configure a token.
edit.sh requires optional /edit and /detail endpoints; not all Hubs expose them.
็ๆฌ
ๅฝๅ v1.1.4ใๅฎๆด็ๆฌๅๅฒ่ง CHANGELOG.mdใ