This document specifies the unified manifest format for extensions in this
monorepo. A single extension.json per extension serves as the source of
truth, from which install scripts generate tool-native packages:
- Gemini CLI: a Gemini extension (directory with
gemini-extension.json) - Claude Code: a Claude Code plugin (directory with
.claude-plugin/plugin.json)
extension.json files are standard JSON (not JSONC). Comments appear
only in this specification document for clarity. Actual files must be
valid JSON compatible with jq.
| Field | Type | Description |
|---|---|---|
name |
string | Extension ID (kebab-case). Plugin namespace for Claude Code. |
version |
string | Semantic version (X.Y.Z) |
description |
string | Human-readable summary |
| Field | Type | Description |
|---|---|---|
mcpServers |
object | MCP server definitions (shared across tools) |
mcpServers[name].command |
string | Executable name |
mcpServers[name].args |
string[] | Arguments. Supports ${extensionPath} |
mcpServers[name].env |
object | Env vars. Supports ${VAR} interpolation |
| Field | Type | Default | Description |
|---|---|---|---|
components.commands.enabled |
boolean | false |
Commands provided? |
components.commands.location |
string | commands/ |
Directory path |
components.commands.convertToSkills |
boolean | false |
Auto-convert .toml to SKILL.md for Claude |
components.skills.enabled |
boolean | false |
Skills provided? |
components.skills.location |
string | skills/ |
Directory path |
components.agents.enabled |
boolean | false |
Agents provided? |
components.agents.location |
string | agents/ |
Directory path |
components.hooks.enabled |
boolean | false |
Hooks provided? |
components.hooks.location |
string | hooks/ |
Directory path |
| Field | Type | Description |
|---|---|---|
gemini.contextFileName |
string | Context file loaded when extension is active |
gemini.themes |
array | UI theme definitions |
gemini.themes[].name |
string | Theme identifier |
gemini.themes[].colors |
object | Color palette |
gemini.hooks |
array | Inline hook definitions |
| Field | Type | Description |
|---|---|---|
claude.author |
object | Plugin author → plugin.json |
claude.contextFileName |
string | Context file for the plugin |
claude.skills |
string[] | Glob patterns for skill directories |
claude.agents |
string[] | Glob patterns for agent directories |
claude.rules |
string[] | Rule files for the plugin |
claude.hooks |
object | Claude Code hook definitions → hooks/hooks.json |
claude.defaultAllowedTools |
string[] | Default tool permissions for skills |
claude.settings |
object | Plugin settings → settings.json |
claude.lsp |
object | LSP server config → .lsp.json |
claude.bin |
string | Executables directory → bin/ |
extension.json ──build──> Gemini extension directory
├── gemini-extension.json # Generated
├── GEMINI.md # Context file
├── dist/ # MCP server (shared)
├── commands/ # .toml files
├── skills/ # SKILL.md files
├── agents/ # PROMPT.md files
└── hooks/hooks.json # Gemini hook config
Generated gemini-extension.json contains: name, version, description,
contextFileName (from gemini.contextFileName), mcpServers, themes
(from gemini.themes).
extension.json ──build──> Claude Code plugin directory
├── .claude-plugin/
│ └── plugin.json # Generated
├── .mcp.json # Generated
├── CLAUDE.md # Context file
├── skills/ # SKILL.md files
├── agents/ # AGENT.md files
├── hooks/hooks.json # Claude hook config
├── settings.json # Plugin settings
├── .lsp.json # LSP config
└── bin/ # Executables
Generated .claude-plugin/plugin.json contains: name, version,
description, author (from claude.author).
Generated .mcp.json contains: mcpServers with ${extensionPath}
resolved to absolute path.
Gemini CLI and Claude Code have fundamentally different hook architectures. See the migration plan (issue #30, section 5.4) for the complete comparison.
Key rule: extension.json does NOT provide a unified hook format.
Shell scripts in hooks/ are reusable across tools, but hook registration
(event binding, matchers) is tool-specific:
gemini.hooks: Gemini CLI formatclaude.hooks: Claude Code format → written tohooks/hooks.jsonin plugin
Install scripts support both formats:
- If
extension.jsonexists → use it (new unified format) - Else if
gemini-extension.jsonexists → use it (legacy Gemini-only) create-extension.shgeneratesextension.jsonfor new extensions
The scaffolding system (create-extension.sh) merges JSON fragments into
extension.json during extension creation:
mcp-server.json.fragment→mcpServersfieldtheme.json.fragment→gemini.themesfield- Merge tool:
jq -s '.[0] * .[1]' - Fragments are deleted after merge.
{ // ============================================================ // UNIVERSAL METADATA (required) // Used by all tools. These fields are mandatory. // ============================================================ // Unique identifier for the extension. Must be kebab-case. // Used in file paths, npm package name, and tool registrations. // For Claude Code: also the plugin namespace (skills become /name:skill). "name": "hello-world", // Semantic version (X.Y.Z). Drives monorepo releases via Gitmoji. "version": "0.1.0", // Human-readable summary. Displayed in extension listings and help. "description": "Demonstration extension showcasing MCP tools, commands, skills, and context.", // ============================================================ // MCP SERVERS (optional) // Shared MCP server definitions. Both tools use the same MCP SDK // and stdio transport, so this section is 100% universal. // // Each key is a server name (convention: "default" for single-server // extensions). Values define how to launch the server process. // // Variable substitution: // ${extensionPath} — resolved at install time to the absolute path // of the installed extension/plugin directory. // ============================================================ "mcpServers": { "default": { // Executable to run. Typically "node" for TypeScript MCP servers, // "python3" for Python-based servers. "command": "node", // Arguments passed to the command. The first argument is usually // the compiled entry point. "args": ["${extensionPath}/dist/index.js"], // Environment variables injected when spawning the server process. // Supports ${VAR} interpolation from the user's shell environment. // Optional — omit if the server needs no extra env. "env": { "NODE_ENV": "production" } } }, // ============================================================ // COMPONENTS (optional) // Declares which component types this extension provides. // Install scripts use these to know what to deploy. // // If a section is omitted or "enabled" is false, that component // type is ignored during installation. // ============================================================ "components": { // Slash commands. // Gemini: .toml files deployed with the extension. // Claude Code: if convertToSkills is true, .toml commands are // converted to SKILL.md files in the generated plugin. "commands": { "enabled": true, "location": "commands/", "convertToSkills": true }, // Agent skills. SKILL.md files with YAML frontmatter. // Gemini: deployed as-is in the extension. // Claude Code: deployed in the plugin's skills/ directory. // Namespaced as /plugin-name:skill-name. "skills": { "enabled": true, "location": "skills/" }, // Sub-agent definitions. Markdown prompt files. // Gemini: PROMPT.md files (no frontmatter). // Claude Code: AGENT.md files (with frontmatter) in the plugin. "agents": { "enabled": false, "location": "agents/" }, // Lifecycle hooks. Shell scripts triggered by tool events. // Gemini: hooks.json defining events (BeforeTool, AfterTool, etc.) // Claude Code: hooks.json with Claude events (PreToolUse, PostToolUse, etc.) // Hook systems are fundamentally different — see section below. "hooks": { "enabled": false, "location": "hooks/" } }, // ============================================================ // GEMINI CLI (optional) // Configuration specific to Gemini CLI. Ignored by Claude Code. // These fields map to the generated gemini-extension.json. // ============================================================ "gemini": { // Context file loaded by Gemini CLI when this extension is active. // Must be a file at the extension root. "contextFileName": "GEMINI.md", // UI themes for Gemini CLI. Claude Code does not support themes. "themes": [ { // Theme identifier. Convention: <extension-name>-<variant>. "name": "hello-world-dark", // Color palette. Minimum: primary, secondary, background, foreground. "colors": { "primary": "#00adb5", "secondary": "#ff2e63", "background": "#222831", "foreground": "#eeeeee" } } ], // Inline Gemini hook definitions. // Format: array of { event, matcher, name, type, command, timeout }. // If components.hooks is enabled, hooks/ directory takes precedence. "hooks": [] }, // ============================================================ // CLAUDE CODE (optional) // Configuration specific to Claude Code. Ignored by Gemini CLI. // These fields shape the generated Claude Code plugin. // ============================================================ "claude": { // Author metadata for the generated plugin manifest. "author": { "name": "Your Name" }, // Context file loaded when plugin is active. // Deployed at the plugin root alongside skills/ and agents/. "contextFileName": "CLAUDE.md", // Glob patterns for skill directories to include in the plugin. // Each matched directory must contain a SKILL.md file. "skills": ["skills/*/SKILL.md"], // Glob patterns for agent definitions to include. "agents": [], // Additional rule files to include with the plugin. "rules": [], // Plugin-level hooks in Claude Code format. // Written to hooks/hooks.json in the generated plugin. // Format: { "EventName": [{ "matcher": "...", "hooks": [...] }] } "hooks": {}, // Default allowed-tools applied to skills from this extension // when they don't define their own. "defaultAllowedTools": ["Read", "Write", "Edit", "Bash"], // Plugin-level settings applied when plugin is enabled. // Currently only "agent" key is supported by Claude Code. "settings": {}, // LSP server configurations for code intelligence. // Written to .lsp.json in the plugin root. "lsp": {}, // Directory of executables to add to the Bash tool's PATH. "bin": null } // ============================================================ // FUTURE TOOLS (extensible) // Additional tool sections follow the same pattern: // "codex": { ... }, "cursor": { ... } // Install scripts for each tool read only their own section + // the universal fields, ignoring everything else. // ============================================================ }