plugins

package
v0.33.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 1, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Overview

Package plugins provides types and interfaces for managing ToolHive plugins (Claude Plugin manifest format, .claude-plugin/plugin.json).

A plugin is an OCI artifact containing a .claude-plugin/plugin.json manifest and its component directories (commands, agents, skills, hooks). The package mirrors pkg/skills: the scoping model (user vs. project) and install-status lifecycle are identical, so Scope and InstallStatus are re-exported as type aliases from pkg/skills to avoid conversion churn at storage boundaries.

Index

Constants

View Source
const (
	// ScopeUser indicates a plugin installed user-wide.
	ScopeUser = skills.ScopeUser
	// ScopeProject indicates a plugin installed for a specific project.
	ScopeProject = skills.ScopeProject
)
View Source
const (
	InstallStatusInstalled = skills.InstallStatusInstalled
	InstallStatusPending   = skills.InstallStatusPending
	InstallStatusFailed    = skills.InstallStatusFailed
)

Install lifecycle statuses. Aliased from skills.InstallStatus because the lifecycle model is identical.

View Source
const ManifestPath = ".claude-plugin/plugin.json"

ManifestPath is the required manifest file path for a plugin directory, matching the Claude Plugin manifest format.

View Source
const MaxComponentsPerGroup = 100

MaxComponentsPerGroup caps the number of entries allowed in a single component array (commands, agents, skills, hooks). Mirrors the skills parser's MaxDependencies bound and bounds the cost of ValidatePluginDir, which walks each bundled skill path. A 64KB manifest can otherwise pack thousands of "./x" entries cheaply.

View Source
const MaxManifestSize = 64 * 1024

MaxManifestSize limits the plugin.json size to prevent JSON parsing attacks (e.g. billion laughs). Mirrors the packager's maxManifestSize.

Variables

View Source
var CheckFilesystem = skills.CheckFilesystem

CheckFilesystem walks a plugin directory checking for symlinks and path traversal. Re-exported from skills (the filesystem safety check is generic).

View Source
var ErrInvalidManifest = errors.New("invalid plugin manifest")

ErrInvalidManifest indicates that the plugin manifest is malformed, missing, or fails toolhive-side strictness checks.

View Source
var NormalizeScopeAndProjectRoot = skills.NormalizeScopeAndProjectRoot

NormalizeScopeAndProjectRoot validates scope and project_root and returns normalized values. Re-exported from skills (the scope/project_root normalization rule is identical for plugins).

View Source
var ValidateProjectRoot = skills.ValidateProjectRoot

ValidateProjectRoot validates a project root path and returns its cleaned form. Re-exported from skills: project-root validation (absolute, no traversal, no symlinks, must be a git repo) is identical for plugins.

View Source
var ValidateScope = skills.ValidateScope

ValidateScope validates a plugin scope. Re-exported from skills because the rule (empty | "user" | "project") is identical.

Functions

func ValidatePluginName

func ValidatePluginName(name string) error

ValidatePluginName checks that a plugin name conforms to the kebab-case rule shared with skills (2-64 lowercase alphanumeric/hyphens, no consecutive hyphens). Re-exported from skills because the rule is identical.

Types

type Author

type Author struct {
	Name  string `json:"name,omitempty"`
	Email string `json:"email,omitempty"`
	URL   string `json:"url,omitempty"`
}

Author represents the author field of a plugin manifest.

type BuildOptions

type BuildOptions = skills.BuildOptions

BuildOptions configures the behavior of the Build operation. Alias for skills.BuildOptions (Path, Tag).

type BuildResult

type BuildResult = skills.BuildResult

BuildResult contains the outcome of a Build operation. Alias for skills.BuildResult (Reference).

type ComponentInventory

type ComponentInventory = ociplugins.ComponentInventory

ComponentInventory summarizes the component types declared by a plugin (map of component-type name to count). Alias for the toolhive-core type.

type ContentOptions

type ContentOptions = skills.ContentOptions

ContentOptions configures the behavior of the GetContent operation. Alias for skills.ContentOptions.

type Dependency

type Dependency = skills.Dependency

Dependency is an external plugin dependency (OCI reference). Alias for skills.Dependency; the {Name, Reference, Digest} shape is identical.

type InfoOptions

type InfoOptions = skills.InfoOptions

InfoOptions configures the behavior of the Info operation. Alias for skills.InfoOptions.

type InstallOptions

type InstallOptions struct {
	// Name is the plugin name or OCI reference to install.
	Name string `json:"name"`
	// Version is the specific version to install. Empty means latest.
	Version string `json:"version,omitempty"`
	// Scope is the installation scope.
	Scope Scope `json:"scope,omitempty"`
	// Clients lists target clients (e.g., "claude-code").
	Clients []string `json:"clients,omitempty"`
	// Force allows overwriting unmanaged plugin directories.
	Force bool `json:"force,omitempty"`
	// ProjectRoot is the project root path for project-scoped installs.
	ProjectRoot string `json:"project_root,omitempty"`
	// Group is the group name to add the plugin to after installation.
	Group string `json:"group,omitempty"`
	// LayerData is the tar.gz content from an OCI layer. Internal use only — NOT exposed via HTTP API.
	LayerData []byte `json:"-"`
	// Reference is the full OCI reference (e.g. ghcr.io/org/plugin:v1).
	Reference string `json:"-"`
	// Digest is the OCI digest for upgrade detection.
	Digest string `json:"-"`
}

InstallOptions configures the behavior of the Install operation. Mirrors skills.InstallOptions with the plugin-specific addition of Reference/Digest passthrough fields used by install-from-OCI flows.

type InstallResult

type InstallResult struct {
	// Plugin is the installed plugin.
	Plugin InstalledPlugin `json:"plugin"`
}

InstallResult contains the outcome of an Install operation.

type InstallStatus

type InstallStatus = skills.InstallStatus

InstallStatus is the lifecycle status of an installed plugin. Alias for skills.InstallStatus (installed | pending | failed).

type InstalledPlugin

type InstalledPlugin struct {
	// Metadata contains the plugin's metadata.
	Metadata PluginMetadata `json:"metadata"`
	// Scope is the installation scope (user or project).
	Scope Scope `json:"scope"`
	// ProjectRoot is the project root path for project-scoped plugins. Empty for user-scoped.
	ProjectRoot string `json:"project_root,omitempty"`
	// Reference is the full OCI reference (e.g. ghcr.io/org/plugin:v1).
	Reference string `json:"reference,omitempty"`
	// Tag is the OCI tag (e.g. v1.0.0).
	Tag string `json:"tag,omitempty"`
	// Digest is the OCI digest (sha256:...) for upgrade detection.
	Digest string `json:"digest,omitempty"`
	// Status is the current installation status.
	Status InstallStatus `json:"status"`
	// InstalledAt is the timestamp when the plugin was installed.
	InstalledAt time.Time `json:"installed_at"`
	// Clients is the list of client identifiers the plugin is installed for.
	Clients []string `json:"clients,omitempty"`
	// Components is the inventory of component types declared by the plugin
	// (e.g. {"commands": 3, "skills": 2}). Extracted from the OCI artifact.
	Components ComponentInventory `json:"components,omitempty"`
	// Signature is the optional signing signature for the plugin artifact.
	Signature string `json:"signature,omitempty"`
	// Dependencies is the list of external plugin dependencies.
	Dependencies []Dependency `json:"dependencies,omitempty"`
}

InstalledPlugin represents a plugin that has been installed locally.

type ListOptions

type ListOptions = skills.ListOptions

ListOptions configures the behavior of the List operation. Alias for skills.ListOptions (identical shape: Scope, ClientApp, ProjectRoot, Group).

type LocalBuild

type LocalBuild = skills.LocalBuild

LocalBuild represents a locally-built OCI plugin artifact in the local store. Alias for skills.LocalBuild (identical shape: Tag, Digest, Name, Description, Version).

type PluginContent

type PluginContent struct {
	// Name is the plugin name from the OCI config labels.
	Name string `json:"name"`
	// Description is the plugin description from the OCI config labels.
	Description string `json:"description,omitempty"`
	// Version is the plugin version from the OCI config labels.
	Version string `json:"version,omitempty"`
	// License is the SPDX license identifier from the OCI config labels.
	License string `json:"license,omitempty"`
	// Manifest is the raw .claude-plugin/plugin.json body.
	Manifest string `json:"manifest"`
	// Files is the list of all files in the artifact with their sizes.
	Files []PluginFileEntry `json:"files"`
}

PluginContent contains the manifest body and file listing extracted from an OCI plugin artifact without installing it.

type PluginFileEntry

type PluginFileEntry = skills.SkillFileEntry

PluginFileEntry represents a single file within a plugin artifact. Alias for skills.SkillFileEntry (same {Path, Size} shape).

type PluginInfo

type PluginInfo struct {
	// Metadata contains the plugin's metadata.
	Metadata PluginMetadata `json:"metadata"`
	// InstalledPlugin contains the full installation record.
	InstalledPlugin *InstalledPlugin `json:"installed_plugin,omitempty"`
}

PluginInfo contains detailed information about an installed plugin.

type PluginManifest

type PluginManifest struct {
	Name        string `json:"name"`
	Version     string `json:"version,omitempty"`
	Description string `json:"description,omitempty"`
	Author      Author `json:"author,omitempty"`
	Homepage    string `json:"homepage,omitempty"`
	Repository  string `json:"repository,omitempty"`
	License     string `json:"license,omitempty"`
	// Keywords MUST be a JSON array (a string is a hard error — see strictStringSlice).
	Keywords strictStringSlice `json:"keywords"`
	// Component directories: each entry must be a relative path starting with "./".
	Commands   []string        `json:"commands,omitempty"`
	Agents     []string        `json:"agents,omitempty"`
	Skills     []string        `json:"skills,omitempty"`
	Hooks      []string        `json:"hooks,omitempty"`
	McpServers json.RawMessage `json:"mcpServers,omitempty"`
	LspServers json.RawMessage `json:"lspServers,omitempty"`
	// Raw is the full original document, preserved for round-tripping unknown fields.
	Raw json.RawMessage `json:"-"`
}

PluginManifest represents the toolhive-readable fields of .claude-plugin/plugin.json. Unknown fields are preserved in Raw so the manifest can be round-tripped without loss.

func ParsePluginManifest

func ParsePluginManifest(pluginDir string) (*PluginManifest, error)

ParsePluginManifest reads and parses .claude-plugin/plugin.json from pluginDir. It performs toolhive-specific pre-build strictness checks only; the packager re-walks the directory and re-validates at build time.

Strictness (exit gate):

  • keywords MUST be a JSON array; a string is a hard error.
  • component paths (commands/agents/skills/hooks) must be relative, start with "./", and contain no ".." traversal segments.

The full document is preserved in .Raw (unknown fields preserved).

type PluginMetadata

type PluginMetadata struct {
	// Name is the unique name of the plugin (kebab-case).
	Name string `json:"name"`
	// Version is the semantic version of the plugin.
	Version string `json:"version,omitempty"`
	// Description is a human-readable description of the plugin.
	Description string `json:"description,omitempty"`
	// Author is the plugin author or maintainer.
	Author string `json:"author,omitempty"`
	// License is the SPDX license identifier for the plugin.
	License string `json:"license,omitempty"`
	// Keywords is a list of keywords for categorization/search.
	Keywords []string `json:"keywords,omitempty"`
}

PluginMetadata contains metadata about a plugin, drawn from the .claude-plugin/plugin.json manifest.

type PluginService

type PluginService interface {
	// Validate checks whether a plugin definition is valid.
	Validate(ctx context.Context, path string) (*ValidationResult, error)
	// Build builds a plugin from a local directory into an OCI artifact.
	Build(ctx context.Context, opts BuildOptions) (*BuildResult, error)
	// Push pushes a built plugin artifact to a remote registry.
	Push(ctx context.Context, opts PushOptions) error
	// ListBuilds returns all locally-built OCI plugin artifacts in the local store.
	ListBuilds(ctx context.Context) ([]LocalBuild, error)
	// DeleteBuild removes a locally-built OCI plugin artifact from the local store.
	DeleteBuild(ctx context.Context, tag string) error
	// GetContent retrieves the plugin.json body and file listing from an OCI
	// artifact without installing it. Works for both remote registry references
	// and local build tags.
	GetContent(ctx context.Context, opts ContentOptions) (*PluginContent, error)
}

PluginService declares the plugin lifecycle surface (mirrors skills.SkillService).

Phase 2 implements ONLY: Validate, Build, Push, ListBuilds, DeleteBuild, and GetContent — the build/validate/push/content surface. The install/uninstall/ list/info methods are NOT declared on the interface yet: they land in Phase 3 (#5527), which will widen this interface (the only change is the addition; existing method signatures stay stable). The Phase-3 option/result types they will use (InstallOptions, InstallResult, UninstallOptions, InfoOptions, PluginInfo, ListOptions) are already declared in options.go as forward declarations of the Phase-3 contract.

type PushOptions

type PushOptions = skills.PushOptions

PushOptions configures the behavior of the Push operation. Alias for skills.PushOptions (Reference).

type Scope

type Scope = skills.Scope

Scope is the installation scope for a plugin. It is an alias for skills.Scope because the scoping model is identical: a plugin is installed either user-wide or project-local, and the storage layer keys both on the same (scope, project_root) pair.

type UninstallOptions

type UninstallOptions = skills.UninstallOptions

UninstallOptions configures the behavior of the Uninstall operation. Alias for skills.UninstallOptions (identical shape).

type ValidationResult

type ValidationResult = skills.ValidationResult

ValidationResult contains the outcome of a Validate operation. Alias for skills.ValidationResult.

func ValidatePluginDir

func ValidatePluginDir(path string) (*ValidationResult, error)

ValidatePluginDir validates a plugin directory at the given path. It is the plugin analogue of skills.ValidateSkillDir. Steps:

  1. Clean + absolute path check.
  2. CheckFilesystem (symlink + traversal walk).
  3. ParsePluginManifest (strict keywords + component-path checks).
  4. Validate name (ValidatePluginName) and assert it matches the dir basename.
  5. For each manifest.Skills entry, reuse skills.ValidateSkillDir on the bundled skill at <pluginDir>/<path-without-leading-./> — this reuses the pkg/skills validator for bundled skills rather than duplicating it.

I/O errors are returned as error; validation issues are returned in ValidationResult.

Directories

Path Synopsis
Package mocks is a generated GoMock package.
Package mocks is a generated GoMock package.
Package pluginsvc provides the default implementation of plugins.PluginService.
Package pluginsvc provides the default implementation of plugins.PluginService.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL