Nexus-backed skill catalog, package publishing, search, and installation for SKILL.md packages.
skill-hub publishes a local SKILL.md package into Nexus, makes it searchable, and installs it into /skills/... through a clean API.
The bundled Docker stack in this repo is an integration harness for local/GCP validation.
The intended production boundary is: existing Nexus runtime + skill-hub app.
Phase 1 is now genuinely Nexus-backed.
- publish a local package into a Nexus-backed catalog
- persist package metadata and package files inside Nexus
- retrieve package metadata and package content through
skill-hub - search the published package catalog, using Nexus search when available
- install published packages into
system,zone,user, oragentscopes - run the full stack with Docker: Postgres + Nexus +
skill-hub
Recommended long-term deployment model:
- Nexus runs as its own runtime/infrastructure stack
skill-hubconnects to that Nexus overNEXUS_BASE_URL+NEXUS_API_KEY- the bundled compose files remain for smoke tests and demos
What is still out of scope:
- workflow execution
- MCP runtime materialization
- credential binding
- enforceable permission manifests
- rollback and snapshots
skill-hub is the control plane.
Nexus is the package store, search substrate, and install target.
Published package state lives in Nexus under:
- catalog metadata:
/skill-hub/packages/... - published artifacts:
/skill-hub/artifacts/... - search documents:
/skill-hub/search/... - installation records:
/skill-hub/installations/...
Installed package contents land under:
/skills/system/packages/.../skills/zones/<zone_id>/.../skills/users/<user_id>/.../skills/agents/<agent_id>/...
Current API:
GET /healthGET /v1/nexusGET /v1/nexus/healthGET /v1/packagesGET /v1/packages/searchPOST /v1/packages/registerPOST /v1/packages/register-localGET /v1/packages/{publisher}/{name}GET /v1/packages/{publisher}/{name}/{version}GET /v1/packages/{publisher}/{name}/{version}/artifactGET /v1/packages/{publisher}/{name}/{version}/content?path=...POST /v1/installations/previewPOST /v1/installationsGET /v1/installationsGET /v1/installations/{installation_id}
OpenAPI:
/docs/redoc
uv run skillhub nexus-info
uv run skillhub nexus-check
uv run skillhub register-local examples/hello-skill
uv run skillhub search-packages hello
uv run skillhub read-package-file nexi-lab hello-skill 0.1.0 SKILL.md
uv run skillhub preview-install examples/hello-skill --target user --scope-id demo-user
uv run skillhub install-local examples/hello-skill --target user --scope-id demo-user
uv run skillhub serveThis is the intended end-to-end path.
Start the default stack:
docker compose -f compose.yaml up --buildThis builds a thin wrapper around the official Nexus release image ghcr.io/nexi-lab/nexus:0.9.2.
The wrapper only patches the missing libgomp1 runtime dependency so txtai-backed search works correctly with the released image.
The wrapper also bakes in a minimal config.skillhub.yaml so the release image does not silently boot with the bundled config.demo.yaml, which is a demo profile and not the right runtime shape for skill-hub.
If you are developing in a workspace that also has the Nexus repo checked out as the parent directory, you can override the default service and build Nexus from local source:
docker compose -f compose.yaml -f compose.local.yaml up --buildThe local-source override uses the Nexus repo’s own root Dockerfile, so it includes the same Rust extensions and runtime wiring as the official Nexus image path.
The stack starts:
postgreson the internal Docker networkdragonflyon the internal Docker networknexusonhttp://localhost:2026skill-hubonhttp://localhost:8040
Compose enables Nexus search and uses:
NEXUS_API_KEY=sk-dev-skillhub-admin-1234567890abcdefNEXUS_IMAGE=ghcr.io/nexi-lab/nexus:0.9.2NEXUS_PLATFORM=linux/amd64NEXUS_CONFIG_FILE=/app/configs/config.skillhub.yamlNEXUS_CACHE_BACKEND=dragonflyNEXUS_DRAGONFLY_URL=redis://dragonfly:6379DRAGONFLY_MAXMEMORY=512mbDRAGONFLY_THREADS=2NEXUS_HEALTH_START_PERIOD=120sSKILLHUB_NEXUS_CATALOG_ROOT=/skill-hubSKILLHUB_NEXUS_INSTALL_ROOT=/skills
On the first boot, Postgres initializes the vector extension and Nexus may spend extra time downloading the txtai embedding model into the Docker volume cache under /app/data/.cache. After that, restarts are much faster.
If you already have an older local stack volume, reset it once so the init SQL runs:
docker compose -f compose.yaml down -v
docker compose -f compose.yaml up --buildcurl -sS http://localhost:8040/health
curl -sS http://localhost:8040/v1/nexus
curl -sS http://localhost:8040/v1/nexus/healthWhen using Docker, register-local must point at a path that exists inside the skill-hub container. The compose file mounts this repo’s examples/ directory at /workspace/examples.
curl -sS -X POST http://localhost:8040/v1/packages/register-local \
-H "content-type: application/json" \
-d '{"source_dir":"/workspace/examples/hello-skill"}'What this does:
- validates
skillhub.yaml - copies declared package files into Nexus under
/skill-hub/artifacts/... - writes package metadata under
/skill-hub/packages/... - writes a search document under
/skill-hub/search/...
curl -sS "http://localhost:8040/v1/packages/search?q=hello&limit=5"If Nexus search is healthy, this uses Nexus search. If not, skill-hub falls back to metadata search.
To confirm semantic search is actually active, inspect Nexus search stats:
curl -sS http://localhost:2026/api/v2/search/statsYou should see "backend": "txtai" once the search daemon is ready.
If you want to use a different official Nexus image tag:
NEXUS_IMAGE=ghcr.io/nexi-lab/nexus:0.9.2 docker compose -f compose.yaml up --buildOn Apple Silicon, the default release-image path intentionally runs the amd64 image under emulation because the current 0.9.2 arm64 release image still has a ggml runtime issue.
That path is valid for smoke checks, but a full readiness/search validation is more trustworthy on an amd64 host such as the GCP deployment.
To confirm the pgvector database extension is enabled:
docker exec skillhub-postgres psql -U skillhub -d nexus -c '\dx'You should see vector in the installed extensions list for a fresh stack.
Artifact metadata:
curl -sS http://localhost:8040/v1/packages/nexi-lab/hello-skill/0.1.0/artifactRead a published file:
curl -sS "http://localhost:8040/v1/packages/nexi-lab/hello-skill/0.1.0/content?path=SKILL.md"curl -sS -X POST http://localhost:8040/v1/installations/preview \
-H "content-type: application/json" \
-d '{
"publisher": "nexi-lab",
"name": "hello-skill",
"version": "0.1.0",
"target": "user",
"scope_id": "demo-user"
}'curl -sS -X POST http://localhost:8040/v1/installations \
-H "content-type: application/json" \
-d '{
"publisher": "nexi-lab",
"name": "hello-skill",
"version": "0.1.0",
"target": "user",
"scope_id": "demo-user"
}'bash scripts/e2e_smoke.shWithout Docker:
export NEXUS_BASE_URL=http://127.0.0.1:2026
export NEXUS_API_KEY=sk-dev-skillhub-admin-1234567890abcdef
export SKILLHUB_NEXUS_CATALOG_ROOT=/skill-hub
export SKILLHUB_NEXUS_INSTALL_ROOT=/skills
uv sync
uv run skillhub serveuv run pytest
uv run python -m compileall src tests
docker compose -f compose.yaml config
docker compose -f compose.yaml -f compose.local.yaml configskill-hub/
docs/
api/
architecture/
examples/
hello-skill/
scripts/
e2e_smoke.sh
docker/
nexus.Dockerfile
src/
skillhub/
compose.yaml
compose.local.yaml
docs/architecture/phase1.mddocs/api/phase1.md
Apache 2.0. See LICENSE.