# Manifest Every plugin package has an `idea-plugin.json` file at the archive root. For development installs, the same file must exist at the root of the plugin source directory selected in IdeA with `Paramètres > Plugins > Installer depuis un dossier…`. ## Minimal Plugin Directory A plugin directory must contain the manifest at its root and a built ESM entrypoint matching the manifest `main` field. ```text my-plugin/ ├── idea-plugin.json ├── package.json ├── tsconfig.json ├── src/ │ └── index.ts └── dist/ └── index.js ``` Create the directory: ```sh mkdir -p my-plugin/src cd my-plugin npm init -y npm install --save-dev typescript @idea/plugin-sdk ``` Use a package script that emits JavaScript into `dist/`: ```json { "type": "module", "scripts": { "build": "tsc -p tsconfig.json" }, "devDependencies": { "@idea/plugin-sdk": "^0.3.0", "typescript": "^5.0.0" } } ``` When developing against a local SDK checkout instead of a published package, replace the SDK dependency with a `file:` reference, for example: ```json { "devDependencies": { "@idea/plugin-sdk": "file:../IdeaSDK", "typescript": "^5.0.0" } } ``` Minimal `tsconfig.json`: ```json { "compilerOptions": { "target": "ES2022", "module": "NodeNext", "moduleResolution": "NodeNext", "outDir": "dist", "rootDir": "src", "strict": true }, "include": ["src"] } ``` Minimal `src/index.ts`: ```ts import type { IdeAPluginModule } from "@idea/plugin-sdk"; const plugin: IdeAPluginModule = { activate(ctx) { ctx.logger.info("plugin activated", { pluginId: ctx.pluginId }); } }; export default plugin; ``` Build before installing or reloading: ```sh npm run build ``` Then install the `my-plugin/` directory in IdeA. For hot reload, keep installing from the directory, rebuild after source changes, then run `idea_plugin_reload` for the installed plugin id. Do not install from a ZIP archive for a hot-reload development loop. ```json { "ideaPluginManifestVersion": 1, "id": "com.example.hello-plugin", "displayName": "Hello Plugin", "publisher": "Example", "version": "0.1.0", "description": "Example IdeA plugin.", "main": "dist/index.js", "engines": { "idea": ">=0.1.0" }, "trustLevel": "full", "capabilities": ["ui", "tooling"], "activationScope": "app", "contributes": { "menus": [], "menuItems": [], "layouts": [], "mcpServers": [] } } ``` ## Required Fields - `ideaPluginManifestVersion`: currently `1`. - `id`: stable lowercase id using letters, digits, dots and dashes. It must start and end with an alphanumeric character. - `displayName`: human-readable plugin name. - `version`: semver version. - `main`: package-relative ESM entrypoint loaded by IdeA. - `trustLevel`: currently `"full"`. ## Optional Fields - `description`, `publisher`. - `engines.idea`: host compatibility hint. - `activationScope`: `"app"` by default, or `"project"` when activation needs a focused project immediately. - `capabilities`: `"ui"`, `"tooling"` and/or `"mcp"`. ## Contributions `contributes.skills` declares read-only agent skills shipped inside the IdeA plugin package. These skills are IdeA-native: IdeA can expose them in project plugin settings, assign them to agents, inject them into the agent skill catalogue, and serve their Markdown body through `idea_skill_read` for every supported harness that receives IdeA capabilities, including Claude Code, Codex, OpenCode local and OpenCode cloud. ```json { "contributes": { "skills": [ { "id": "unity.build-debug", "name": "unity-build-debug", "description": "Diagnose Unity build failures.", "kind": "workflow", "path": "skills/unity-build-debug/SKILL.md" } ] } } ``` Skill contribution rules: - `id` is stable within the plugin and is used by project/agent assignments. - `name` is the agent-facing name shown in the injected skill catalogue and accepted by `idea_skill_read`. - `description` is the short affordance shown before the agent loads the skill. - `kind` defaults to `"workflow"`; `"reference"` is also supported. - `path` must be a package-relative Markdown file path ending in `.md`. - Installing a plugin globally is not enough: a project must enable the plugin, then assign the skill to the target agent. `contributes.layouts` is the only surface for plugin layouts. The same layout contribution can be mounted inside an IdeA layout cell or opened in a detached OS window. Do not add a separate manifest contribution type for windows. For a command that opens a visible plugin window, declare both the menu command and the layout type: ```json { "ideaPluginManifestVersion": 1, "id": "com.example.unity-plugin", "displayName": "Unity Developer Tools", "publisher": "Example", "version": "0.1.0", "description": "Unity integration for IdeA.", "main": "dist/index.js", "engines": { "idea": ">=0.1.0" }, "trustLevel": "full", "capabilities": ["ui", "tooling"], "activationScope": "app", "contributes": { "menus": [ { "id": "unity-plugin.menu", "label": "Unity Developer Tools", "topLevel": true, "order": 100 } ], "menuItems": [ { "id": "unity-plugin.health.item", "targetMenuId": "unity-plugin.menu", "label": "Health", "command": "unity-plugin.health", "order": 10, "when": "projectOpen" } ], "layouts": [ { "type": "unity-plugin.health", "label": "Unity Health", "component": "UnityHealth", "order": 10 } ] } } ``` `capabilities: ["ui"]` is required when a plugin relies on layouts or windows as human-facing UI. Add `"tooling"` when the same plugin uses workspace, task, tooling or terminal services. The `contributes.layouts[].type` value is the public id used by both `ctx.layouts.register({ type, component })` and `ctx.services.windows.open({ layoutType })`. Contribution ids are part of the runtime contract: - commands can only register ids declared by `contributes.menuItems[*].command`; - layouts can only register `type` values declared by `contributes.layouts`; - `services.windows.open({ layoutType })` only accepts a layout type declared by the calling plugin. ## Validation Use the SDK validator in tests or build tooling: ```ts import { assertPluginManifest } from "@idea/plugin-sdk"; assertPluginManifest(JSON.parse(manifestText)); ```