Files
IdeaSDK/docs/manifest.md

330 lines
9.6 KiB
Markdown

# 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": {
"skills": [],
"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.
See [Project Plugin Assignments](project-plugin-assignments.md) for the
`.ideai/project-plugins.json` schema, validation rules, assignment order, and
agent relaunch requirements.
`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.
## MCP Servers And Agent Tools
`contributes.mcpServers` is the IdeA-native contract for plugin-provided
agent tools. A plugin does not register individual MCP tools from `activate(ctx)`.
Instead, the plugin ships or references a stdio MCP server process, declares it
in the manifest, and that server advertises its own tools through the MCP
`tools/list` protocol.
```json
{
"capabilities": ["mcp"],
"contributes": {
"mcpServers": [
{
"id": "unity-editor",
"displayName": "Unity Editor Tools",
"command": "scripts/unity-mcp-server.mjs",
"args": [],
"cwd": "${pluginRoot}",
"transport": "stdio",
"autoStart": true
}
]
}
}
```
MCP server contribution rules:
- `id` is stable within the plugin and is used by project/agent assignments.
- `displayName` is the human-readable server name shown in plugin settings.
- `transport` must currently be `"stdio"`.
- `autoStart: true` is required for IdeA to start the server during plugin MCP
reconciliation. Non-auto-start servers are manifest metadata only today.
- A relative `command` is resolved under the installed plugin package root.
- An absolute `command` is rejected unless `allowAbsoluteCommand: true` is set.
Use this only for an intentional dependency on a host binary.
- `cwd` defaults to `${pluginRoot}` when omitted.
The tools an agent can call are assigned with the triplet
`pluginId`/`serverId`/`toolName` in project plugin settings. `toolName` must
match a tool name advertised by the MCP server. IdeA does not currently provide
a runtime API such as `ctx.mcp.registerTool()` or `ctx.mcp.registerServer()`.
For multi-harness workflows, keep `contributes.skills` as instructions and
expose executable behavior through assigned MCP tools. Do not make skill
Markdown depend on filesystem paths relative to the Markdown returned by
`idea_skill_read`; that body is served as read-only content, not mounted as a
working directory. If a skill needs packaged scripts, put the script behind a
manifest-declared MCP server and tell the agent to call the assigned tool.
## MCP Server Paths
`contributes.mcpServers` entries are resolved by the host before starting a
declared MCP server. In `command`, `args`, `env` and `cwd`, the host expands:
- `${pluginRoot}` to the installed plugin package root.
- `${appDataDir}` to the host-owned application data directory.
This string substitution is limited to manifest-declared MCP server startup.
Runtime handlers receive the same installed package location separately as
`ctx.pluginRoot`; `ctx.services.tasks.runCommand()` does not perform placeholder
substitution, and workspace APIs remain project-confined.
Prefer a packaged executable script for plugin-owned MCP servers, for example
`command: "scripts/unity-mcp-server.mjs"` with an appropriate shebang and file
mode. If the server must be launched through a host executable such as Node,
use an absolute command with `allowAbsoluteCommand: true` and keep plugin-owned
paths in `args`, for example `${pluginRoot}/scripts/unity-mcp-server.mjs`.
## Validation
Use the SDK validator in tests or build tooling:
```ts
import { assertPluginManifest } from "@idea/plugin-sdk";
assertPluginManifest(JSON.parse(manifestText));
```