API reference
Tenant-scoped REST. Bearer auth on every /v1/* except /v1/healthz.
Tenant resolution by subdomain or X-Skill-Pool-Tenant header.
Mutations write an audit_events row in the same transaction.
Common
Auth. Authorization: Bearer <token> issued for the resolved tenant.
Tenant resolution. Either subdomain (acme.skill-pool.example.com) or X-Skill-Pool-Tenant: acme header.
Error shape.
{
"error": "tenant_resolution_failed",
"message": "missing Host header"
}
Codes: not_found · unauthorized · forbidden · bad_request · tenant_resolution_failed · not_implemented · internal_error.
Health
GET /v1/healthz — no auth, no tenant. Always returns 200 so the load balancer doesn't pull a node on a transient blip. Page on deps.db.status == "down" from your monitoring.
{
"status": "ok", // "ok" | "degraded"
"version": "0.1.0",
"deps": {
"db": { "status": "up", "latency_ms": 3 },
"storage": { "status": "up", "latency_ms": 12 },
"embedder": { "status": "off", "note": "fastembed feature not compiled" }
}
}
Skills · Agents · Commands
One catalog table holds all three, discriminated by ?kind=skill|agent|command (default skill). Schema, validation, dependency graph, embedding column, decay model — all shared.
| Method | Path | Notes |
|---|---|---|
| GET | /v1/skills | List · supports query · tags · limit · kind · semantic · min_similarity |
| POST | /v1/skills | Publish · multipart · tar+gz body + JSON metadata · secret scan on server |
| GET | /v1/skills/{slug} | Metadata |
| GET | /v1/skills/{slug}/bundle.tar.gz | 302 → signed S3 URL (or stream from fs/MinIO) |
| GET | /v1/skills/{slug}/skill-md | The raw SKILL.md text |
| GET | /v1/skills/{slug}/detail | Portal-shaped detail (version history, usage) |
| DELETE | /v1/skills/{slug}/versions/{version} | Archive (soft-delete; partial unique index allows republish) |
Semantic search (Phase 5+). ?semantic=axum middleware ranks by cosine similarity of the description embedding. Returns 400 if no embedder is compiled in.
GET /v1/skills?semantic=axum+middleware&min_similarity=0.7
[
{
"slug": "axum-handler",
"version": "1.0.0",
"description": "Pattern for axum tenant-scoped extractors",
"tags": ["rust"],
"status": "published",
"created_at": "2026-05-18T12:00:00Z",
"similarity": 0.94
}
]
Plugins (Layer 3)
| Method | Path | Notes |
|---|---|---|
| GET | /v1/plugins | List tenant's plugins |
| POST | /v1/plugins | Publish · resolves nested {slug,version} entries · 409 on duplicate version |
| GET | /v1/plugins/{slug} | Detail · sourcing mode · refresh state |
| POST | /v1/plugins/{slug}/refresh | Mirror-mode only · trigger immediate pull |
| DELETE | /v1/plugins/{slug}/versions/{version} | Archive |
Projects · Plans (Layer 2)
A project binds a repo (git remote URL) to a curated set of skills. A plan is a curator-authored, versioned bundle that a project can follow.
| Method | Path | Notes |
|---|---|---|
| GET | /v1/projects | List · auto-discover by git remote |
| POST | /v1/projects | Create |
| GET | /v1/projects/{slug}/plan | Current plan resolved for the project |
| POST | /v1/plans | Publish a plan version |
| GET | /v1/plans/{slug}/history | Immutable version log |
Drafts (retrospective capture)
| Method | Path | Notes |
|---|---|---|
| POST | /v1/drafts | Capturer daemon posts a Sonnet-drafted SKILL.md + frontmatter |
| GET | /v1/drafts | Curator inbox (paginated) |
| POST | /v1/drafts/{id}/approve | Promote draft to a new skill version |
| POST | /v1/drafts/{id}/reject | Discard with reason |
Decay (lifecycle)
GET /v1/tenant/skills/decay — admin-only. Lists candidates matching last_used > 6mo ∧ uses < 3. The web portal's "graveyard" view uses this.
Tenants · Tokens
| Method | Path | Notes |
|---|---|---|
| POST | /v1/tenant/tokens | Mint a scoped token · read · publish · admin |
| GET | /v1/tenant/members | List · paged · filterable by role |
| POST | /v1/tenant/sso | Configure OIDC / SAML 2.0 · per-tenant |
| GET | /v1/tenant/theme | Logo · palette · font · favicon · custom domain |
| POST | /scim/v2/Users · /Groups | SCIM v2 user provisioning |
Audit
GET /v1/tenant/audit — paginated, filterable by actor, action, resource, time range.
GET /v1/tenant/audit/export.jsonl — signed JSONL export for SIEM ingestion. Every mutation in the system is in here.
Public read surfaces (no auth)
These are the only routes Claude Code's installer touches. Tenant routing is by Host header / subdomain / custom domain.
| Path | Consumer | Notes |
|---|---|---|
/.claude-plugin/marketplace.json | /plugin marketplace add <url> | Generated server-side from the tenant's plugin rows |
/git/plugins/<slug>.git/* | /plugin install <name> | Smart-HTTP git endpoint backed by stored bytes |
MCP transport
Claude can call search_skills and install_skill inline over JSON-RPC at /mcp. Authenticates with the same Bearer token. Useful when you want Claude to manage its own toolbox without shelling out to the CLI.