api/schemas.py) — not reconstructed from the design doc — so they match what actually comes back on the wire. Example values (ids, digests, tenant ids) are from a real local run, not placeholders.
Endpoint index
Search
GET /api/v1/skills
Query params: query, runtime, versionConstraint, tags (csv), category, page, pageSize — all optional. No query returns everything the caller can see.
Matches on indexed tokens (id segments, name words, tags, category, description words), not arbitrary substrings — see the ranking model below. Searching an id’s own hyphenated suffix (personal-notes) won’t match if that exact string isn’t itself a tag or name token; searching a real tag (notes) will.
items[] and page above is exhaustive — that’s the complete SearchResultItem / PageMeta shape, nothing trimmed.
Ranking model
Skill metadata
GET /api/v1/skills/{id}/versions/{version}
guardrailCertifiedLevel/guardrailLevelStatuses are a point-in-time attestation computed once at publish — null/[] means “not available for this version” (published before certification existed, or the guardrails service was unreachable at publish time), never “failed,” and it is never recomputed later even if the tenant’s guardrail policy changes afterward.
Create, validate, and publish a draft
POST /api/v1/drafts → DraftResponse
POST /api/v1/drafts/{draftId}/validate → ValidationResultResponse — no body required.
certification is a projection — what this draft would be certified as if published right now. It’s null whenever nothing was actually scanned (invalid/blocked) or the guardrails service wasn’t reachable.
POST /api/v1/drafts/{draftId}/publish → DraftPublishResponse
visibility defaults to "private" when omitted — a caller has to opt in to "public" explicitly; nothing is ever published world-visible by accident.
Share a skill
POST /api/v1/skills/{id}/shares → ShareGrantResponse. Requires the skills:share scope and being either the skill’s owner or an admin of its owning tenant.
permission defaults to "read" when omitted. Revoking (DELETE /api/v1/skills/{id}/shares/{grantId}) takes effect on the very next request — grants are checked per-request, never cached.
Artifact download
POST /api/v1/skills/{id}/versions/{version}/artifact-token → ArtifactTokenResponse, then GET /api/v1/artifacts/{token} redeems it.
Response — artifact-token
expiresAt, not single-use — the same posture as a presigned S3/OCI URL, which is exactly what this stands in for on the local filesystem backend (see Architecture).
Tenant guardrail policy
GET /api/v1/tenants/{tenantId}/guardrail-policy / PUT (same shape) → TenantGuardrailPolicyResponse. Readable by any tenant member, writable only by a tenant admin.
Response
Auth
POST /api/v1/auth/login (dev-login path) → AuthResponse
POST /api/v1/auth/google takes { "idToken": "...", "tenantId": null } and returns the same AuthResponse shape. POST /api/v1/auth/refresh takes { "refreshToken": "...", "tenantId": null } and returns an access token + tenant list without a new refresh token.
Guardrails service endpoints
Separate service, separate base URL (:8028 locally) — see Architecture.
GET /healthz — real response