Manage AI-tool plugins
An AI-tool plugin is a bundle of commands, agents, skills, hooks, and MCP or LSP server declarations that extends an AI coding tool. ToolHive builds these plugins into portable OCI artifacts, publishes them to any OCI registry, and installs them into the target client's plugins directory.
Plugins are for the AI tool itself, not for ToolHive. A plugin ships everything that lives inside the AI tool's own extension surface (commands, agents, skills, and so on); ToolHive is the delivery mechanism.
The thv ai-plugin commands install into two clients today:
- Claude Code:
~/.claude/plugins/<name>for user scope,<PROJECT_ROOT>/.claude/plugins/<name>for project scope - Codex:
~/.agents/plugins/toolhive/<name>for user scope,<PROJECT_ROOT>/.agents/plugins/toolhive/<name>for project scope
Other supported clients may install skills, MCP servers, or both; only these two currently accept plugins. See the client compatibility reference.
Prerequisites
-
The ToolHive API server must be running. Start it in a separate terminal window (the command blocks while running):
thv serveThe server must remain running while you use
thv ai-plugincommands.Using the ToolHive desktop app?If the ToolHive desktop app is already running, the API server is available automatically. You can skip the
thv servestep and usethv ai-plugincommands directly. -
Claude Code or Codex installed on your machine.
Install a plugin
You can install plugins by plain name (resolved through the configured registry), by OCI reference, by Git URL, or from a local build:
thv ai-plugin install my-plugin
thv ai-plugin install ghcr.io/my-org/plugins/my-plugin:v1.0.0
thv ai-plugin install git://github.com/my-org/plugins@main#packages/my-plugin
If the plain name matches an artifact you built locally with
thv ai-plugin build, ToolHive resolves it from the local OCI store; otherwise
it looks up the name in the configured Registry Server.
Target a specific client
If both Claude Code and Codex are installed, ToolHive installs the plugin for
the first supported client it detects. To pick explicitly, use the --clients
flag:
thv ai-plugin install my-plugin --clients claude-code
thv ai-plugin install my-plugin --clients claude-code,codex
thv ai-plugin install my-plugin --clients all
Valid values are claude-code, codex, or all.
Choose a scope
Plugins support two installation scopes, matching skills:
- User scope (default) - installs the plugin into your home directory, so it is available across all projects.
- Project scope - installs the plugin into the project directory. The project root must be a Git repository.
# User scope (default)
thv ai-plugin install my-plugin
# Project scope
thv ai-plugin install my-plugin --scope project \
--project-root .
Relative project roots are resolved from the current working directory. You can
also pass an absolute path. The same behavior applies to install, info,
list, and uninstall.
Overwrite or group
Pass --force to replace an existing installation of the same plugin, or
--group to add the plugin to a named group for later batch operations:
thv ai-plugin install my-plugin --force
thv ai-plugin install my-plugin --group development
Install a key-pair-signed plugin
When a plugin was signed with a cosign key pair rather than keyless, the first
project-scoped install must supply the matching cosign public key (cosign.pub)
with --public-key:
thv ai-plugin install my-plugin --scope project --project-root . \
--public-key ./cosign.pub
ToolHive verifies the signature against the key, then pins it in the project's
toolhive.lock.yaml so subsequent thv ai-plugin sync and
thv ai-plugin upgrade runs reuse it automatically. Distribute the public key
alongside the artifact so users installing the plugin can supply it.
Keyless-signed plugins need no such out-of-band step, since the signer identity
is verifiable from the transparency-log entry.
List installed plugins
thv ai-plugin list
Filter by client, scope, or group:
thv ai-plugin list --client claude-code
thv ai-plugin list --scope project --project-root .
thv ai-plugin list --group development
For JSON output:
thv ai-plugin list --format json
Inspect a plugin
To see metadata, version, source, and declared contents for an installed plugin:
thv ai-plugin info my-plugin
For project-scoped plugins, pass --scope project --project-root ..
Uninstall a plugin
thv ai-plugin uninstall my-plugin
For a project-scoped install:
thv ai-plugin uninstall my-plugin --scope project \
--project-root .
Author a plugin
A plugin is a directory with a manifest at .claude-plugin/plugin.json. At a
minimum, the manifest needs a name, which is used as the default OCI tag at
build time. A version is recommended so thv ai-plugin builds and
thv ai-plugin info can report it.
{
"name": "my-plugin",
"version": "1.0.0",
"description": "What this plugin does and when to use it.",
"author": {
"name": "Your Team",
"email": "team@example.com"
},
"license": "Apache-2.0",
"keywords": ["review", "python"],
"commands": ["./commands/review.md"],
"agents": ["./agents/reviewer.md"],
"skills": ["./skills/code-review"],
"hooks": ["./hooks/post-tool-use.js"]
}
Content-path fields (commands, agents, skills, hooks) must be relative
paths beginning with ./. Path traversal (..) is rejected, each group is
capped at 100 entries, and the manifest itself is capped at 64 KB. The
keywords field must be a JSON array of strings.
MCP and LSP server declarations (mcpServers, lspServers) are recorded in the
manifest for the AI tool to consume; ToolHive does not lifecycle-manage them
from the plugin. thv ai-plugin info reports declared servers as "Declared (not
managed by ToolHive)".
Naming conventions
Use kebab-case for the plugin name - lowercase letters, numbers, and hyphens. The name must match the directory the plugin ships in and appears in the default OCI tag.
Validate
Before building, check the manifest and directory structure:
thv ai-plugin validate ./my-plugin
For JSON output:
thv ai-plugin validate ./my-plugin --format json
Build an OCI artifact
Package the plugin into an OCI artifact stored in the local OCI store:
thv ai-plugin build ./my-plugin
The command prints the OCI reference of the built artifact to stdout. By
default, the built artifact is tagged with the plugin name from the manifest,
or the raw digest if the manifest has no name. Pass --tag to override:
thv ai-plugin build ./my-plugin --tag ghcr.io/my-org/plugins/my-plugin:v1.0.0
Push to a registry
After building, push to a remote OCI registry:
thv ai-plugin push ghcr.io/my-org/plugins/my-plugin:v1.0.0
thv ai-plugin push signs the pushed artifact by default using Sigstore keyless
signing. ToolHive acquires a short-lived OIDC identity token and records the
signature in the public transparency log. In GitHub Actions with
id-token: write permission, the ambient OIDC token is used automatically; on
an interactive terminal, ToolHive prompts for browser sign-in; in any other
environment the push fails with an actionable error before publishing anything.
To supply a pre-acquired identity token, pass --identity-token:
thv ai-plugin push ghcr.io/my-org/plugins/my-plugin:v1.0.0 \
--identity-token "$IDENTITY_TOKEN"
To publish without a signature, pass --no-sign:
thv ai-plugin push ghcr.io/my-org/plugins/my-plugin:v1.0.0 --no-sign
To install an unsigned plugin project-scoped, pass --allow-unsigned to
thv ai-plugin install.
Plugin push is keyless-only. If you need to sign with a cosign key pair, publish
a skill instead, which supports both keyless and
key-pair signing via --key.
Push uses your existing container registry credentials (for example, from
docker login or podman login). Authenticate before pushing.
Reproduce and upgrade project-scoped plugins
Project-scoped installs record their source, resolved digest, and signer
identity in a toolhive.lock.yaml file at the project root. This lets you
reinstall the same plugin content on another machine, detect drift in CI, and
upgrade to newer content when the catalog moves forward. User-scoped installs
don't participate in the lock file.
Restore plugins from the lock file
To reinstall the plugins recorded in the lock file (for example, after cloning
the project on a new machine), run thv ai-plugin sync from the project
directory:
thv ai-plugin sync --project-root .
Missing or drifted plugins are reinstalled at their pinned digest. Sync prompts
for confirmation before installing; pass --yes in non-interactive environments
such as CI.
By default, thv ai-plugin sync targets every plugin-supporting client
installed on the machine. Pass --clients to constrain sync to a specific set:
thv ai-plugin sync --project-root . --clients claude-code
Use --check to report drift without installing or writing anything. This is
useful as a CI gate:
thv ai-plugin sync --project-root . --check
If you have project-scoped plugins that were installed before the lock file
existed, --adopt records lock entries for them so subsequent syncs include
them:
thv ai-plugin sync --project-root . --adopt
Use --prune to remove installs that are no longer in the lock file.
See the
thv ai-plugin sync command reference
for all options.
Upgrade project-scoped plugins
Upgrade the project's plugins to newer pinned content:
thv ai-plugin upgrade --project-root .
A version or tag change within the same OCI repository proceeds without
--allow-ref-change, including a move to an older tag. ToolHive pins the
resolved digest and blocks signer changes. If the catalog moves the plugin to a
different repository, organization, or registry, the upgrade is blocked. Review
the new source, then repeat the command with --allow-ref-change if you intend
to permit that repository move. ToolHive prompts before installing the planned
changes; pass --yes in non-interactive environments.
Plugins pinned to an immutable reference (an OCI digest or a full Git commit hash) are reported as not upgradable, because there is nothing newer to resolve to.
Use --preview to see what would change without persisting anything, or
--fail-on-changes as a CI freshness gate that reports pending upgrades without
installing them.
See the
thv ai-plugin upgrade command reference
for all options.
Manage local builds
The builds subcommand exposes the local OCI store where thv ai-plugin build
writes artifacts.
List locally-built artifacts
thv ai-plugin builds
Output shows the tag, digest, name, and version for each artifact. Add
--format json for machine-readable output.
Remove a locally-built artifact
thv ai-plugin builds remove ghcr.io/my-org/plugins/my-plugin:v1.0.0
Blobs are retained on disk until every tag pointing to their digest is removed.
Next steps
- Configure your AI client to register clients with ToolHive so plugins install to the right location automatically
- Manage agent skills - the sibling workflow for distributing skill bundles across a wider set of clients
Related information
thv ai-plugincommand reference- Client compatibility
- ToolHive API reference - the
/api/v1beta/pluginsroutes expose the same operations for scripting and integration
Troubleshooting
thv ai-plugin operation times out
ToolHive allows API operations up to 10 minutes by default so large OCI pulls
can complete. To use a different client timeout, set TOOLHIVE_API_TIMEOUT to a
positive Go duration:
TOOLHIVE_API_TIMEOUT=30m thv ai-plugin install <PLUGIN_NAME>
Invalid, zero, or negative values are ignored. A timeout error means the API server was reachable but did not respond within the limit.
thv ai-plugin install reports "plugin not found in local store or registry"
ToolHive looks up plain names first in the local OCI store (populated by
thv ai-plugin build) and then in the configured Registry Server. If both miss,
install the plugin directly by OCI reference:
thv ai-plugin install ghcr.io/<namespace>/<name>:<version>
Confirm the Registry Server is configured (see Registry configuration) and that the plugin has been published to it.
Installed plugin isn't visible to the AI tool
-
Verify the install landed:
thv ai-plugin listthv ai-plugin info <PLUGIN_NAME> -
Confirm the plugin files exist in the expected directory:
- Claude Code:
~/.claude/plugins/<PLUGIN_NAME>/(user) or<PROJECT_ROOT>/.claude/plugins/<PLUGIN_NAME>/(project) - Codex:
~/.agents/plugins/toolhive/<PLUGIN_NAME>/(user) or<PROJECT_ROOT>/.agents/plugins/toolhive/<PLUGIN_NAME>/(project)
- Claude Code:
-
Restart the AI tool to trigger plugin discovery.
Manifest validation fails
Run thv ai-plugin validate ./my-plugin to see the specific error. Common
issues:
- Missing
.claude-plugin/plugin.jsonor missingnamefield keywordsis a string instead of a JSON array- A content-path entry (in
commands,agents,skills, orhooks) does not start with./or contains.. - More than 100 entries in one content-path group
- The manifest file exceeds 64 KB
Push to registry fails with authentication error
thv ai-plugin push uses your existing container registry credentials. Log in
first:
# For GitHub Container Registry
echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdin
# For Docker Hub
docker login
Then retry the push.