---
title: "Sync project plugins from the lock file"
method: POST
path: "/api/v1beta/plugins/sync"
tags: ["plugins"]
---

# Sync project plugins from the lock file

`POST /api/v1beta/plugins/sync`

Restore a project's installed plugins to match toolhive.lock.yaml

## Request body

- union
  - object
  - PkgApiV1SyncPluginsRequest — Request to restore a project's installed plugins to match its lock file
    - `adopt` boolean — Adopt writes lock entries for existing unmanaged project-scope installs
    - `allow_unsigned` boolean — AllowUnsigned permits adopting plugins whose signature state cannot be established, recording them as unsigned
    - `check` boolean — Check verifies on-disk content against the lock file without installing or writing anything
    - `clients` string[] — Clients lists target client identifiers. Empty means every plugin-supporting client detected on this host.
    - `project_root` string — ProjectRoot is the project root path whose lock file should be synced
    - `prune` boolean — Prune removes project-scoped plugins installed but not present in the lock file

## Response `200`

OK

- GithubComStacklokToolhivePkgPluginsSyncResult
  - `already_current` string[] — AlreadyCurrent lists skills that already matched the lock file.
  - `drifted` string[] — Drifted lists skills whose on-disk contentDigest differed from the lock file. Normally these are reinstalled to match it; when Check is set, nothing is written and this field reports the drift only.
  - `failed` GithubComStacklokToolhivePkgSkillsSyncFailure[] — Failed lists skills that could not be synced, with the reason for each. Drift alone is never reported here — see Drifted.
    - `error` string — Error is a human-readable description of the failure.
    - `name` string — Name is the skill name that failed.
    - `reason` 'registry-unreachable' | 'digest-missing' | 'validation-rejected' | 'lock-write-failed' | 'signature-invalid' | 'signer-mismatch' | 'provenance-field-mismatch' | 'unsigned-rejected' | 'unknown' — Reason is a typed failure reason when Status is UpgradeStatusFailed.
  - `installed` string[] — Installed lists skills that were installed or reinstalled to match the lock file.
  - `missing` string[] — Missing lists lock entries with no corresponding install record at all — the fresh-clone state. Normally these are installed at their pinned reference; when Check is set, nothing is written and this field reports the gap only.
  - `never_managed` string[] — NeverManaged lists project-scoped skills never recorded as lock-managed.
  - `pruned` string[] — Pruned lists removed-from-lock skills that were uninstalled because Prune was set.
  - `removed_from_lock` string[] — RemovedFromLock lists previously managed skills absent from the lock file.

## Other responses

- `400` — Bad Request
- `403` — Forbidden (feature not enabled)
- `500` — Internal Server Error
- `501` — Not Implemented

---

[API](https://skmtc.dev/stacklok/apis/toolhive-api.md) · [All operations](https://skmtc.dev/stacklok/apis/toolhive-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/stacklok/toolhive-api/revisions/e9f942effcda/schema)
