Skills & Plugins#
The skill and plugin system covers the capabilities of claude-code, opencode, and hermes, substituting equivalents wherever the stack differs, and adds capabilities that follow from OpenProgram's own host surfaces.
Reference implementations:
references/claude-code-leaked/src/{skills,plugins,commands/{skills,plugin}}references/opencode/packages/opencode/src/{skill,plugin},packages/plugin,.opencode/{skills,plugins}references/hermes-agent/{skills,plugins,optional-skills},web/src/plugins
1. Concepts and file conventions#
Skill#
Unit: a directory containing SKILL.md + optional references/, templates/, and other resources.
SKILL.md frontmatter (claude-code standard + opencode/hermes additions):
---
name: my-skill
description: One-line trigger description (LLM reads this to decide invocation)
category: devops # hermes-style grouping
optional: false # hermes optional-skills replaces directory-based distinction
allowed-tools: [Read, Edit] # claude-code: restrict the usable tools
triggers: # explicit trigger conditions (our extension; none of the three actually use it)
keywords: ["deploy", "ci"]
file_patterns: ["*.yml"]
slash: "/deploy"
version: 1.0.0
author: ...
---
Sources, lowest precedence first (merged for display; on conflict the latter overrides the former, so what the user wrote beats what was installed for them, and both beat what ships with the package):
- Bundled —
openprogram/skills_bundled/<name>/(shipped with the package, matching claude-codesrc/skills/bundled) - Remote-pulled —
~/.openprogram/cache/skills/<name>/(matching opencode discovery, pulled from a remote index) - Plugin-provided — contributed by enabled plugins
- User —
~/.openprogram/skills/<name>/ - Project —
<project>/skills/<name>/
A skill's name is its directory path relative to the source root, so nesting gives hierarchical names (anthropic-skills/docx) and a name collision means the same skill from two sources, not two different skills.
Resource layout (hermes convention): SKILL.md + references/ + templates/.
Plugin#
Unit: a package containing a manifest + entrypoint. All three manifest forms are supported, parsed uniformly:
plugin.json(claude-code / hermes style)[tool.openprogram.plugin]insidepyproject.toml(Python-native)- the
"openprogram"field insidepackage.json(Node-native, opencode style)
Manifest fields:
{
"name": "...",
"version": "...",
"description": "...",
"deprecated": false, // opencode style
"compatibility": ">=0.1.0", // opencode-style minVersion check
"trust": "community", // community | verified
"entrypoints": {
"commands": "...",
"skills": "./skills",
"agents": "...",
"hooks": "...",
"mcpServers": "...",
"providers": "...", // opencode style: LLM provider injection
"web": "./web/dist" // hermes-style dashboard; can register a frontend
},
"sidebar": [ // our extension: plugin registers sidebar items, same as built-in navigation
{ "label": "My Tool", "icon": "...", "route": "/plugin/my-plugin/tool" }
],
"options": { /* JSON Schema, see PluginOptionsDialog.tsx */ }
}
Sources:
- Installed via pip — Python package, scan the entry_points group
openprogram.plugins - Installed via npm — Node package,
~/.openprogram/plugins/node_modules/<name>/(opencode-style PluginLoader) - Local path —
~/.openprogram/plugins/<name>/(hermes style, placed manually) - Project-pinned —
<project>/.openprogram/plugins.json(declares enablement, version, source)
2. Backend#
Directory#
openprogram/
skills/
loader.py # five-source merged loading
discovery.py # pull on demand from a remote index (matching opencode discovery.ts)
watcher.py # watchdog file watching, hot reload + WS broadcast
skills_bundled/ # built-in skills
...
plugins/
loader.py # multi-manifest parsing, install, uninstall
sandbox.py # layered sandbox: subprocess / in-process
marketplace.py # multiple marketplaces, claude-code schema adapter
trust.py # trust policy + persistence
bundled/
webui/routes/
skills.py
plugins.py
Skills API (routes/skills.py)#
| Method | Path | Description |
|---|---|---|
| GET | /api/skills |
Five-source merged list, including source / enabled / category / optional |
| GET | /api/skills/{name} |
Full SKILL.md text + frontmatter + resource file tree |
| POST | /api/skills |
Create in project / user |
| DELETE | /api/skills/{name} |
Delete from project / user / remote-cache only |
| POST | /api/skills/{name}/toggle |
enable/disable |
| POST | /api/skills/{name}/invoke-trace |
Return the injection record from the LLM's last invocation of this skill (unique) |
| GET | /api/skills/discovery/sources |
List registered remote indexes |
| POST | /api/skills/discovery/sources |
Add a remote index |
| POST | /api/skills/discovery/pull |
Pull a single skill from an index into the cache |
| WS | skills:changed |
Triggered by the watcher |
Plugins API (routes/plugins.py)#
| Method | Path | Description |
|---|---|---|
| GET | /api/plugins |
Installed list + status + errors |
| GET | /api/plugins/{name} |
Details + manifest + entrypoint load status |
| POST | /api/plugins/install |
`{source: pip |
| POST | /api/plugins/{name}/uninstall |
|
| POST | /api/plugins/{name}/toggle |
|
| POST | /api/plugins/{name}/reload |
Matching claude-code /reload-plugins |
| POST | /api/plugins/{name}/validate |
Matching ValidatePlugin.tsx, dry-run check |
| GET / POST | /api/plugins/{name}/options |
Read/write the options JSON Schema |
| POST | /api/plugins/{name}/trust |
Set the trust level, affecting the sandbox policy |
| GET | /api/plugins/marketplaces |
List marketplaces |
| POST | /api/plugins/marketplaces |
Add (compatible with the claude-code marketplace schema) |
| GET | /api/plugins/marketplace/{id}/index |
Browse, with search / category / pagination |
| WS | plugins:changed |
|
| WS | plugins:error |
Push load failures in real time |
Junction points for plugin contribution entrypoints#
| Entrypoint type | Injected into |
|---|---|
| skills | The skill registry (merged with filesystem skills) |
| commands | availableFunctions, tagged with source=plugin:<name> |
| mcpServers | The existing openprogram/mcp/ registry; no changes to the /mcp page |
| providers | The provider registry (corresponding to the openprogram provider system, opencode style) |
| agents | The subagent registry |
| hooks | The event bus (PreToolUse / PostToolUse / SessionStart / Stop, etc.) |
| web | Static assets mounted at /plugin/<name>/static/, rendered by the Next.js dynamic route /plugin/[name]/[...slug] |
| sidebar | Pushed to the plugin section of the sidebar store (unique) |
Sandbox (layered)#
| trust | Loading method | Failure behavior |
|---|---|---|
verified |
in-process import | A load failure disables only that plugin |
community |
subprocess + RPC (stdin/stdout JSON-RPC), with CPU / memory / FS limits | A process crash does not affect the main process |
untrusted |
Refuse to load; the UI pops a trust confirmation | — |
Hook execution always goes through a subprocess (even when verified), consistent with claude-code.
3. Frontend#
Sidebar additions (web/components/sidebar/sidebar.tsx)#
New chat
Functions
Skills <- new
Plugins <- new
MCP Servers
Memory
Chats
─────────── (plugin-registered sidebar items are inserted dynamically below this divider)
<Plugin A nav>
<Plugin B nav>
Routes#
/skills— list (grouped by category, optional collapsed), details, create, remote index management/plugins— three tabs: Installed / Marketplace / Errors- Installed:
UnifiedInstalledCell-style rows - Marketplace: marketplace selector + card browsing + install (porting
BrowseMarketplace / AddMarketplace / DiscoverPlugins) - Errors: porting
PluginErrors
- Installed:
/plugin/[name]/[...slug]— dynamically render the plugin's own frontend (fromweb/dist)/skills/[name]/trace— Skill invocation record visualization (unique)
Components#
web/components/skills/
skills-list.tsx, skill-detail.tsx, new-skill-dialog.tsx,
discovery-sources.tsx, invoke-trace.tsx
web/components/plugins/
installed-list.tsx, marketplace-browser.tsx, add-marketplace-dialog.tsx,
plugin-options-dialog.tsx, plugin-trust-warning.tsx, plugin-errors.tsx,
validate-plugin.tsx, plugin-detail.tsx, plugin-host.tsx (iframe / dynamic mount)
Store#
lib/skills-store.ts, lib/plugins-store.ts, subscribing over WS to skills:changed / plugins:changed / plugins:error.
4. Capabilities beyond the three reference implementations#
- First-class plugin sidebar items: manifest
sidebar: [...]→ automatically injected into the sidebar, on par with built-in navigation - Skill invocation trace: each SkillTool call records
{ skill, injected_md_hash, accessed_refs, ts }, visualized in the right panel //skills/[name]/trace - Skill hot reload: watchdog watches any of the five sources for changes → re-parse → WS broadcast, no
/reloadneeded - Unified across the three manifests: any of
plugin.json/pyproject.toml/package.jsonis recognized, zero migration cost - Cross-ecosystem marketplace interop: a claude-code marketplace schema adapter layer, able to directly add its official / third-party marketplaces
- Dual-track package management: pip + npm dual track; both opencode's Node plugins and hermes's Python plugins can be installed
- Explicit triggers:
triggers.{keywords, file_patterns, slash}; a hit on any of conversation/file/command surfaces an activation prompt - Provider as a contribution type: introduced from opencode, letting LLM providers also be distributed in plugin form
- Layered sandbox: the trust level maps to a loading policy, not one-size-fits-all
- Validate dry-run: before install,
POST /validatechecks manifest / entrypoints / dependencies / compatibility, matchingValidatePlugin.tsx
5. Coverage of the three reference implementations#
claude-code: bundled skills ✓, SKILL.md frontmatter ✓, SkillTool tool invocation ✓, Marketplace / AddMarketplace / BrowseMarketplace / ManageMarketplaces ✓, ManagePlugins / DiscoverPlugins / ValidatePlugin / PluginErrors / PluginOptionsDialog / PluginTrustWarning / UnifiedInstalledCell ✓, ReloadPlugins ✓, the five entrypoints commands/skills/agents/hooks/mcpServers ✓
opencode: remote skill discovery (IndexSkill schema) ✓, npm-package-form plugins ✓, Provider plugin ✓, PluginPackage / resolvePluginTarget / compatibility / deprecated fields ✓, Effect-style concurrency and retry (swapped for httpx+tenacity) ✓
hermes: domain-grouped skills ✓ (category), optional distinction ✓ (optional field), the SKILL.md + references/ + templates/ resource layout ✓, plugin_api.py entrypoint ✓, dashboard/dist/ frontend contribution ✓ (upgraded to web entrypoint + sidebar registration)
Appendix: Implementation Status#
The design is complete; delivery is ordered in four blocks, each usable on its own:
- Skills — five-source loader, watchdog and WS broadcast, SKILL.md parsing (triggers / category / optional), the
/skillspage and bundled default set, the SkillTool built-in tool with invoke trace, and remote discovery. - Plugins, local — unified parsing of the three manifests; installation from pip / npm / git / path; layered sandbox and trust; injection of the commands / skills / mcpServers / providers / hooks / agents entrypoints; the Installed and Errors pages with Validate / Options / Reload.
- Plugins, frontend and sidebar —
webentrypoint asset mounting,/plugin/[name]/[...slug]dynamic rendering, sidebar registration items. - Marketplace — multiple marketplaces with the claude-code schema adapter, plus the BrowseMarketplace / AddMarketplace / DiscoverPlugins surfaces.
Three points are left open and do not block the blocks above:
- Whether skills and plugins live under
~/.openprogram/or reuse an existing global directory. - How the Provider plugin entrypoint aligns with the existing abstraction in
openprogram/providers/. - Whether hook event names match claude-code's (PreToolUse and the rest).