Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ task license-fix # Add missing license headers
| `recovery` | HTTP panic recovery middleware (Beta) |
| `validation/http` | RFC 7230/8707 compliant HTTP header and URI validation |
| `validation/group` | Group name validation (lowercase alphanumeric, underscore, dash, space) |
| `registry/types` | Skill/Server/Plugin catalog types + JSON-schema validation (Alpha) |

### Mock Generation

Expand Down
174 changes: 174 additions & 0 deletions registry/types/data/plugin.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://raw.githubusercontent.com/stacklok/toolhive-core/main/registry/types/data/plugin.schema.json",
"title": "ToolHive Plugin Schema",
"description": "Schema for a ToolHive plugin entry in the registry",
"type": "object",
"required": [
"namespace",
"name",
"description",
"version"
],
"properties": {
"namespace": {
"type": "string",
"description": "Ownership scope using reverse-DNS pattern (e.g. io.github.stacklok)",
"minLength": 3,
"maxLength": 128
},
"name": {
"type": "string",
"description": "Plugin identifier in lowercase alphanumeric with hyphens",
"minLength": 1,
"maxLength": 64,
"pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$"
},
"description": {
"type": "string",
"description": "Human-readable explanation of the plugin",
"minLength": 1,
"maxLength": 1024
},
"version": {
"type": "string",
"description": "Version identifier (semantic version or commit hash)",
"minLength": 1
},
"status": {
"type": "string",
"description": "Current status of the plugin",
"enum": [
"active",
"deprecated",
"archived"
],
"default": "active"
},
"title": {
"type": "string",
"description": "Human-readable display title",
"maxLength": 100
},
"license": {
"type": "string",
"description": "SPDX license identifier",
"maxLength": 256
},
"repository": {
"$ref": "#/$defs/plugin_repository"
},
"icons": {
"type": "array",
"description": "Display icons for the plugin",
"items": {
"$ref": "#/$defs/plugin_icon"
}
},
"packages": {
"type": "array",
"description": "Distribution packages (OCI or Git)",
"items": {
"$ref": "#/$defs/plugin_package"
}
},
"metadata": {
"type": "object",
"description": "Official metadata from the plugin manifest file",
"additionalProperties": true
},
"_meta": {
"type": "object",
"description": "Extended metadata with reverse-DNS namespaced keys",
"additionalProperties": true
}
},
"$defs": {
"plugin_package": {
"type": "object",
"description": "Distribution package reference (OCI or Git)",
"required": [
"registryType"
],
"properties": {
"registryType": {
"type": "string",
"description": "Package registry type",
"enum": [
"oci",
"git"
]
},
"identifier": {
"type": "string",
"description": "OCI image reference"
},
"digest": {
"type": "string",
"description": "Content digest (sha256 format)"
},
"mediaType": {
"type": "string",
"description": "Media type of the package"
},
"url": {
"type": "string",
"description": "Git repository URL",
"format": "uri"
},
"ref": {
"type": "string",
"description": "Git branch or tag reference"
},
"commit": {
"type": "string",
"description": "Git commit SHA"
},
"subfolder": {
"type": "string",
"description": "Path within the repository"
}
}
},
"plugin_icon": {
"type": "object",
"description": "Display icon for the plugin",
"required": [
"src"
],
"properties": {
"src": {
"type": "string",
"description": "Icon source URL or path"
},
"size": {
"type": "string",
"description": "Icon dimensions"
},
"type": {
"type": "string",
"description": "Icon media type"
},
"label": {
"type": "string",
"description": "Accessibility label for the icon"
}
}
},
"plugin_repository": {
"type": "object",
"description": "Source repository metadata",
"properties": {
"url": {
"type": "string",
"description": "Repository URL",
"format": "uri"
},
"type": {
"type": "string",
"description": "Repository type (e.g. git)"
}
}
}
}
}
7 changes: 7 additions & 0 deletions registry/types/data/upstream-registry.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@
"items": {
"$ref": "https://raw.githubusercontent.com/stacklok/toolhive-core/main/registry/types/data/skill.schema.json"
}
},
"plugins": {
"type": "array",
"description": "Array of plugins in the registry",
"items": {
"$ref": "https://raw.githubusercontent.com/stacklok/toolhive-core/main/registry/types/data/plugin.schema.json"
}
}
}
}
Expand Down
39 changes: 39 additions & 0 deletions registry/types/plugins_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc.
// SPDX-License-Identifier: Apache-2.0

package registry

// Plugin is a single plugin in list and get responses or publish requests.
type Plugin struct {
// Namespace is the namespace of the plugin.
// The format is reverse-DNS, e.g. "io.github.user".
Namespace string `json:"namespace"`
// Name is the name of the plugin.
// The format is that of identifiers, e.g. "my-plugin".
Name string `json:"name"`
// Description is the description of the plugin.
Description string `json:"description"`
// Version is the version of the plugin.
// Any non-empty string is valid, but ideally it should be either a
// semantic version or a commit hash.
Version string `json:"version"`
// Status is the status of the plugin.
// Can be one of "active", "deprecated", or "archived".
Status string `json:"status,omitempty"` // active, deprecated, archived
// Title is the title of the plugin.
// This is for human consumption, not an identifier.
Title string `json:"title,omitempty"`
// License is the SPDX license identifier of the plugin.
License string `json:"license,omitempty"`
// Repository is the source repository of the plugin.
Repository *SkillRepository `json:"repository,omitempty"`
// Icons is the list of icons for the plugin.
Icons []SkillIcon `json:"icons,omitempty"`
// Packages is the list of packages for the plugin.
Packages []SkillPackage `json:"packages,omitempty"`
// Metadata is the official metadata of the plugin as reported in the
// plugin manifest file.
Metadata map[string]any `json:"metadata,omitempty"`
// Meta is an opaque payload with extended meta data details of the plugin.
Meta map[string]any `json:"_meta,omitempty"`
}
Loading
Loading