---
title: "Bulk library sync"
method: GET
path: "/api/v1/library"
tags: ["Library"]
---

# Bulk library sync

`GET /api/v1/library`

## Request

- Base URL: `https://skillrepo.dev`
- URL: `https://skillrepo.dev/api/v1/library`
- Auth: HTTP bearer

Returns every skill the authenticated account can access (owned + library-added), with inline SKILL.md and supporting file contents.

**Version selection**: each skill is served at the account's approved version when the account's library holds one (an approved-version pin, set by a library lead), and at the publisher's current version otherwise. Accounts without pins — including every account on a plan without the approval workflow — always receive the current version; for them this endpoint behaves exactly as it did before pins existed. A recalled version is never served — whether recalled platform-wide by a SkillRepo admin or pulled back from this account's own fleet by its library lead (account-scoped; another account's recalls never affect this response): delivery falls back to the most recent earlier version that is not recalled, and a skill with no servable version left is absent from the response.

**Delta sync**: pass `?since=<ISO 8601>` to restrict `skills` to those modified after that timestamp — including skills whose approved version changed — AND populate `removals` with skills removed from the library since that timestamp.

**ETag / 304**: the route emits an HTTP-level `ETag` on complete responses. Clients should send it back as `If-None-Match` on subsequent syncs; a match short-circuits to a 304 with no body. Incomplete responses (any skill with `filesIncomplete: true`) do NOT emit an ETag — the CLI is expected to re-sync instead of caching.

**Skillset-scoped sync**: pass `?skillset=` (with `repo`) to serve the repo's declared skillset — a curated subset of the library — instead of the whole library. A skillset-scoped sync always returns the FULL resolved set: `since` is ignored and removals, pin rollbacks, and recalls are expressed by absence from `skills`, never by tombstones. The response carries a `skillset` object with the skipped-extras signal. The skillset-scoped `ETag` is a distinct opaque format from the whole-library one; `If-None-Match` / 304 revalidation works the same way.

Rate-limit bucket: `sync` (10/min per key — intentionally tight). Single-skill reads belong on `/api/v1/skills/{owner}/{name}`, which uses the looser `cli-crud` bucket.

## Query parameters

- `since` string, date-time: ISO 8601 timestamp. When present, switches to delta-sync mode: only skills updated after this time appear in `skills`, and `removals` is populated with tombstones newer than this time.
- `manifest` '1': When `1`, returns a metadata-only manifest: `files` is empty for every skill and NO delivery is recorded. Used by `skillrepo list` for a read-only drift check that must not affect sync state (#1832). A full (recording) sync omits this param.
- `skillset` string: Switches to skillset-scoped sync: resolves the named skillset (`owner/name` per the repo declaration's `use` pointer) and returns ONLY its curated set — members plus honored `extra` entries, with the authored-skill auto-include suppressed. Requires `repo`. Ignores `since` (a skillset-scoped sync always returns the full resolved set; removals are expressed by absence). Requires a skillset-capable plan and the skillset rollout flag; otherwise the request fails with 422 `skillset_unresolvable`.
- `repo` string: The declaring repo's self-declared name (declaration `name` field). Required when `skillset` is present.
- `extra` string[]: Repeatable; each entry an `owner/name` skill reference from the declaration's `extra` list. Honored only when the organization's extras toggle is on and the skill is in the caller's library (or authored by the caller's organization); unhonorable entries are skipped loudly via `skillset.skippedExtras` in the 200 response.

## Headers

- `If-None-Match` string: ETag from a previous sync. When it matches the current state, the route returns 304 with no body so clients can reuse their cached response.

## Response `200`

Full sync payload.

- LibrarySyncResponse: Canonical CLI library sync payload. Used by the `skillrepo` CLI to reconcile its local library cache on session start.
  - `skills` SyncSkill[], required
    - `owner` string, required
    - `ownerName` string, required
    - `name` string, required
    - `version` string, nullable, required
    - `description` string, required
    - `keywords` string[], required: Single-word keywords extracted from the skill's `triggers` (stop-words removed, lowercased) for client-side indexing.
    - `updatedAt` string, date-time, required
    - `etag` string, required: Per-skill ETag of the form `"owner/name@<timestamp>"`. Used by clients for conditional re-fetching; the bulk sync response also sets an HTTP-level `ETag` covering the whole response.
    - `contextSignals` ContextSignals, nullable, required: Context-signals object attached to a skill by the analysis pipeline. Open-shaped — clients should pass through to UI without strict validation. Null when analysis has not yet run.
    - `files` SyncFile[], required
      - `path` string, required: File path relative to the skill root.
      - `content` string, required: Inlined file contents. UTF-8 when `encoding: utf-8`; base64 of the raw bytes when `encoding: base64`.
      - `sha256` string, required: Hex-encoded SHA-256 of the raw file bytes. Empty string for the synthesized SKILL.md entry (clients use the version-level `etag` for freshness there).
      - `contentType` string, required: MIME type. Text content types are inlined as UTF-8; everything else as base64.
      - `size` integer, required: File size in bytes (pre-base64-encoding).
      - `encoding` 'utf-8' | 'base64', required: How `content` is encoded. `utf-8` for text types, `base64` for binary.
    - `filesIncomplete` boolean, required: True when one or more blob-backed files failed to inline and were dropped from `files`. When true, the route SUPPRESSES the response-level HTTP `ETag` header and sets `Cache-Control: private, no-store` so clients re-fetch on the next sync instead of caching an incomplete response. On the push (POST) response this field is almost always `false` — files were just uploaded successfully, so the inline-fetch rarely fails. A `true` value here indicates a transient blob store hiccup between upload and response build; the next GET will return the complete state.
    - `governance` SyncSkillGovernance: Per-skill delivery governance carried ONLY on the non-recording read paths — the `?manifest=1` whole-library and skillset-scoped reads (`skillrepo list`). Absent on the byte-identical whole-library sync wire (D2) and the skillset-scoped sync wire, and absent entirely when the recall feature is disabled.
      - `status` 'latest' | 'serving' | 'pinned', required: Delivery status in the shared version-status vocabulary: `latest` — the served version is the publisher's head (healthy); `serving` — a recall rolled the account back to an earlier version (the served version is below head and diverted); `pinned` — a deliberate hold behind head (not a recall).
      - `head` string, nullable, required: The publisher's current head version label, for context (e.g. "vX available"). Null when the skill has no published head.
      - `recalledVersion` string, nullable: Present only when `status` is `serving`: the version that WOULD serve absent the recall — the one recalled and rolled back FROM. The version actually served is this skill's own `version`.
  - `removals` LibraryRemoval[], required: Tombstones for skills removed from the caller's library — including skills whose every servable version has been recalled (computed at request time; restoring a recalled version or publishing a new one makes the skill servable again). Only populated when the request includes `?since=` (delta sync); an unconditional sync returns an empty array. Always empty on skillset-scoped syncs — there, removal (and recall) is expressed by absence from `skills`, never by tombstones.
    - `owner` string, required
    - `name` string, required
    - `removedAt` string, date-time, required
  - `syncedAt` string, date-time, required
  - `skillset` SkillsetSyncInfo: Present only on skillset-scoped syncs (the `skillset` query param). Carries the skipped-extras signal: declared `extra` entries that could not be honored, each with a machine reason and the canonical remediation message. The base skillset always delivers — extras never fail delivery (design E5).
    - `name` string, required: Resolved skillset name.
    - `updatedAt` string, date-time, required
    - `skippedExtras` SkillsetSkippedExtra[], required
      - `skill` string, required: The `owner/name` skill reference the declaration's `extra` list named.
      - `reason` 'extras_disabled' | 'not_in_library', required: Machine reason the entry was skipped: `extras_disabled` — the organization's extras toggle is off; `not_in_library` — the skill is not in the caller's library (and not authored by the caller's organization).
      - `message` string, required: Human-readable remediation — canonical server copy the CLI prints verbatim.

## Other responses

- `304`: ETag matched — no changes since the cached response. Empty body; clients should reuse their prior sync.
- `400`: Invalid request — malformed JSON, missing required fields, or failed schema validation. Body matches `ErrorEnvelope`.
- `401`: Missing or invalid authentication. For routes that require `bearerAccessKey` or `bearerCatalogKey`.
- `403`: Authenticated, but the key lacks the required scope or the account is suspended. Use `code` to distinguish: `insufficient_scope`, `account_suspended`, `plan_limit`.
- `422`: Emitted only for skillset-scoped requests (`?skillset=`). Single machine code `skillset_unresolvable` covering every fail-closed cause: skillsets not enabled for the caller's organization, a declaration pointing at another organization's skillset, an unknown skillset name, or missing/malformed `repo`/`skillset`/`extra` params. The response never falls back to a whole-library payload; the `error` message is actionable, written for the developer whose sync failed.
- `429`: Rate limit exceeded on the route's bucket. Includes `X-RateLimit-*` headers indicating the limit, remaining, and reset time.
- `503`: Emitted only for skillset-scoped requests: the entitlement check's flag evaluation failed at the infrastructure level (transient). Not a statement about the declaration or the organization's entitlement — clients should retry (see `Retry-After`) or serve last-verified local state. No machine `code`.

---

[API](https://skmtc.dev/skillrepo/apis/skillrepo-api.md) · [All operations](https://skmtc.dev/skillrepo/apis/skillrepo-api/llms.txt) · [OpenAPI document](https://skmtc.dev/skillrepo/apis/skillrepo-api/revisions/b62bac246918?raw)
