class CommandDefinition
Bases:BaseModel
Command definition loaded from markdown file.
Commands are slash commands that users can invoke directly.
They define instructions for the agent to follow.
Properties
allowed_tools: list[str]argument_hint: str | Nonecontent: strdescription: strmetadata: dict[str, Any]name: strsource: str | None
Methods
classmethod load()
Load a command definition from a markdown file. Command markdown files have YAML frontmatter with:- description: Command description
- argument-hint: Hint for command arguments (string or list)
- allowed-tools: List of allowed tools
- Parameters:
command_path– Path to the command markdown file. - Returns: Loaded CommandDefinition instance.
model_config = (configuration object)
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].to_skill()
Convert this command to a keyword-triggered Skill. Creates a Skill with a KeywordTrigger using the Claude Code namespacing format: /<plugin-name>:<command-name>
- Parameters:
plugin_name– The name of the plugin this command belongs to. - Returns: A Skill object with the command content and a KeywordTrigger.
class GitHubURLComponents
Bases:NamedTuple
Parsed components of a GitHub blob/tree URL.
Properties
branch: str Alias for field number 2owner: str Alias for field number 0path: str Alias for field number 3repo: str Alias for field number 1
class InstalledPluginInfo
Bases:BaseModel
Information about an installed plugin.
This model tracks metadata about a plugin installation, including
where it was installed from and when.
Properties
description: strenabled: boolinstall_path: strinstalled_at: strname: strrepo_path: str | Noneresolved_ref: str | Nonesource: strversion: str
Methods
classmethod from_plugin()
Create InstalledPluginInfo from a loaded Plugin.model_config = (configuration object)
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].class InstalledPluginsMetadata
Bases:BaseModel
Metadata file for tracking all installed plugins.
Properties
plugins: dict[str, InstalledPluginInfo]
Methods
classmethod get_path()
Get the metadata file path for the given installed plugins directory.classmethod load_from_dir()
Load metadata from the installed plugins directory.model_config = (configuration object)
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].save_to_dir()
Save metadata to the installed plugins directory.class Marketplace
Bases:BaseModel
A plugin marketplace that lists available plugins and skills.
Follows the Claude Code marketplace structure for compatibility,
with an additional skills field for standalone skill references.
The marketplace.json file is located in .plugin/ or .claude-plugin/
directory at the root of the marketplace repository.
Properties
description: str | Nonemetadata: MarketplaceMetadata | Nonemodel_config: = (configuration object) Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].name: strowner: MarketplaceOwnerpath: str | Noneplugins: list[MarketplacePluginEntry]skills: list[MarketplaceEntry]
Methods
get_plugin()
Get a plugin entry by name.- Parameters:
name– Plugin name to look up. - Returns: MarketplacePluginEntry if found, None otherwise.
classmethod load()
Load a marketplace from a directory. Looks for marketplace.json in .plugin/ or .claude-plugin/ directories.- Parameters:
marketplace_path– Path to the marketplace directory. - Returns: Loaded Marketplace instance.
- Raises:
FileNotFoundError– If the marketplace directory or manifest doesn’t exist.ValueError– If the marketplace manifest is invalid.
resolve_plugin_source()
Resolve a plugin’s source to a full path or URL.- Returns:
- source: Resolved source string (path or URL)
- ref: Branch, tag, or commit reference (None for local paths)
- subpath: Subdirectory path within the repo (None if not specified)
- Return type: Tuple of (source, ref, subpath) where
class MarketplaceEntry
Bases:BaseModel
Base class for marketplace entries (plugins and skills).
Both plugins and skills are pointers to directories:
- Plugin directories contain: plugin.json, skills/, commands/, agents/, etc.
- Skill directories contain: SKILL.md and optionally scripts/, references/, assets/
Properties
author: PluginAuthor | Nonecategory: str | Nonedescription: str | Nonehomepage: str | Nonemodel_config: = (configuration object) Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].name: strsource: strversion: str | None
class MarketplaceMetadata
Bases:BaseModel
Optional metadata for a marketplace.
Properties
description: str | Nonemodel_config: = (configuration object) Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].version: str | None
class MarketplaceOwner
Bases:BaseModel
Owner information for a marketplace.
The owner represents the maintainer or team responsible for the marketplace.
Properties
email: str | Nonename: str
Methods
model_config = (configuration object)
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].class MarketplacePluginEntry
Bases:MarketplaceEntry
Plugin entry in a marketplace.
Extends MarketplaceEntry with Claude Code compatibility fields for
inline plugin definitions (when strict=False).
Plugins support both string sources and complex source objects
(MarketplacePluginSource) for GitHub/git URLs with ref and path.
Properties
agents: str | list[str] | Nonecommands: str | list[str] | Nonehooks: str | HooksConfigDict | Nonekeywords: list[str]license: str | Nonelsp_servers: LspServersDict | Nonemcp_servers: McpServersDict | Nonemodel_config: = (configuration object) Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].repository: str | Nonesource: str | MarketplacePluginSourcestrict: booltags: list[str]
Methods
to_plugin_manifest()
Convert to PluginManifest (for strict=False entries).class MarketplacePluginSource
Bases:BaseModel
Plugin source specification for non-local sources.
Supports GitHub repositories and generic git URLs.
Properties
model_config: = (configuration object) Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].path: str | Noneref: str | Nonerepo: str | Nonesource: strurl: str | None
Methods
validate_source_fields()
Validate that required fields are present based on source type.class Plugin
Bases:BaseModel
A plugin that bundles skills, hooks, MCP config, agents, and commands.
Plugins follow the Claude Code plugin structure for compatibility:
plugin-name/
├── .claude-plugin/ # or .plugin/
│ └── plugin.json # Plugin metadata
├── commands/ # Slash commands (optional)
├── agents/ # Specialized agents (optional)
├── skills/ # Agent Skills (optional)
├── hooks/ # Event handlers (optional)
│ └── hooks.json
├── .mcp.json # External tool configuration (optional)
└── README.md # Plugin documentation
Properties
agents: list[AgentDefinition]commands: list[CommandDefinition]description: str Get the plugin description.hooks: HookConfig | Nonemanifest: PluginManifestmcp_config: dict[str, Any] | Nonename: str Get the plugin name.path: strskills: list[Skill]version: str Get the plugin version.
Methods
add_mcp_config_to()
Add this plugin’s MCP servers to an MCP config. Plugin MCP servers override existing servers with the same name. Merge semantics (Claude Code compatible):- mcpServers: deep-merge by server name (last plugin wins for same server)
- Other top-level keys: shallow override (plugin wins)
- Parameters:
mcp_config– Existing MCP config (or None to create new) - Returns: New MCP config dict with this plugin’s servers added
add_skills_to()
Add this plugin’s skills to an agent context. Plugin skills override existing skills with the same name. Includes both explicit skills and command-derived skills.- Parameters:
agent_context– Existing agent context (or None to create new)max_skills– Optional max total skills (raises ValueError if exceeded)
- Returns: New AgentContext with this plugin’s skills added
- Raises:
ValueError– If max_skills limit would be exceeded
classmethod fetch()
Fetch a plugin from a remote source and return the local cached path. This method fetches plugins from remote sources (GitHub repositories, git URLs) and caches them locally. Use the returned path with Plugin.load() to load the plugin.- Parameters:
-
source– Plugin source - can be:- Any git URL (GitHub, GitLab, Bitbucket, Codeberg, self-hosted, etc.) e.g., “https://gitlab.com/org/repo”, “git@bitbucket.org:team/repo.git”
- ”github:owner/repo” - GitHub shorthand (convenience syntax)
- ”/local/path” - Local path (returned as-is)
-
cache_dir– Directory for caching. Defaults to ~/.openhands/cache/plugins/ -
ref– Optional branch, tag, or commit to checkout. -
update– If True and cache exists, update it. If False, use cached as-is. -
repo_path– Subdirectory path within the git repository (e.g., ‘plugins/my-plugin’ for monorepos). Only relevant for git sources, not local paths. If specified, the returned path will point to this subdirectory instead of the repository root.
-
- Returns: Path to the local plugin directory (ready for Plugin.load()). If repo_path is specified, returns the path to that subdirectory.
- Raises: PluginFetchError – If fetching fails or repo_path doesn’t exist.
get_all_skills()
Get all skills including those converted from commands. Returns skills from both the skills/ directory and commands/ directory. Commands are converted to keyword-triggered skills using the format /<plugin-name>:<command-name>.
- Returns: Combined list of skills (original + command-derived skills).
classmethod load()
Load a plugin from a directory.- Parameters:
plugin_path– Path to the plugin directory. - Returns: Loaded Plugin instance.
- Raises:
FileNotFoundError– If the plugin directory doesn’t exist.ValueError– If the plugin manifest is invalid.
classmethod load_all()
Load all plugins from a directory.- Parameters:
plugins_dir– Path to directory containing plugin subdirectories. - Returns: List of loaded Plugin instances.
model_config = (configuration object)
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].class PluginAuthor
Bases:BaseModel
Author information for a plugin.
Properties
email: str | Nonename: str
Methods
classmethod from_string()
Parse author from string format ‘Name<email>’.
model_config = (configuration object)
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].class PluginManifest
Bases:BaseModel
Plugin manifest from plugin.json.
Properties
author: PluginAuthor | Nonedescription: strmodel_config: = (configuration object) Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].name: strversion: str
class PluginSource
Bases:BaseModel
Specification for a plugin to load.
This model describes where to find a plugin and is used by load_plugins()
to fetch and load plugins from various sources.
Examples
Properties
ref: str | Nonerepo_path: str | Nonesource: str
Methods
model_config = (configuration object)
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].classmethod validate_repo_path()
Validate repo_path is a safe relative path within the repository.class ResolvedPluginSource
Bases:BaseModel
A plugin source with resolved ref (pinned to commit SHA).
Used for persistence to ensure deterministic behavior across pause/resume.
When a conversation is resumed, the resolved ref ensures we get exactly
the same plugin version that was used when the conversation started.
The resolved_ref is the actual commit SHA that was fetched, even if the
original ref was a branch name like ‘main’. This prevents drift when
branches are updated between pause and resume.
Properties
original_ref: str | Nonerepo_path: str | Noneresolved_ref: str | Nonesource: str

