Introduction
universal-plugin is a build tool for universal AI agent plugins. You write one canonical definition in root plugin.json, and universal-plugin build generates a spec-conformant vendor manifest for each runtime you target.
The problem
Section titled “The problem”Every major AI coding agent runtime — Claude Code, Cursor, Codex, GitHub Copilot CLI — uses its own plugin.json format at a vendor-specific path. Targeting multiple runtimes means maintaining multiple manifest files that share ~60% of their content, hand-writing vendor-specific transformations (hook event casing, env var names, component fields), and re-syncing on every change.
The solution
Section titled “The solution”A single source of truth in root plugin.json, following the closed Agent Plugins Specification v1.0.0 field set ($schema, name, version, description, author, homepage, repository, license, keywords, extensions). All universal-plugin build config — component paths, the vendor target list, and per-harness overrides — nests under extensions["org.cyberuni.universal-plugin"]. Running universal-plugin build produces each vendor’s manifest as a build artifact.
{ "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json", "name": "my-plugin", "extensions": { "org.cyberuni.universal-plugin": { "vendors": ["claude-code", "cursor", "codex", "copilot-cli"], "skills": "./skills/", "mcpServers": "./mcp.json", "hooks": "./hooks/hooks.json", "harnesses": { "claude-code": { "monitors": "./monitors/monitors.json" }, "cursor": { "publisher": "my-org", "logo": "./assets/logo.png" }, "codex": { "version": "1.0.0", "description": "My plugin." }, "copilot-cli": {} } } }}Running universal-plugin build from the plugin root generates:
| Vendor | Output |
|---|---|
claude-code | .claude-plugin/plugin.json |
cursor | .cursor-plugin/plugin.json |
codex | .codex-plugin/plugin.json |
copilot-cli | plugin.json |
What gets transformed
Section titled “What gets transformed”- Hook event names — canonical PascalCase (
SessionStart) is translated to each vendor’s casing (camelCase for Cursor, PascalCase for Claude Code and Codex). - Env vars — canonical
${PLUGIN_ROOT}is translated to vendor-native names in hook commands and MCP configs. - Vendor-specific fields — fields in
extensions["org.cyberuni.universal-plugin"].harnesses.<vendor>are merged into the generated manifest; fields the vendor doesn’t support are dropped with a warning. - Required field enforcement — Codex requires
versionanddescription; build fails with a clear error if they’re missing.
Generated files are build artifacts
Section titled “Generated files are build artifacts”The generated vendor manifests should be treated like compiled output — either gitignored (build on install) or committed (pre-built for distribution). The choice is yours; universal-plugin enforces neither.