feat(sdk): contributes.skills — skills IdeA-native déclarables par plugin — #282 (types IdeAPluginSkillContribution/IdeAPluginSkillKind: id/name/description/kind workflow|reference/path .md package-relative, validation manifeste, export public; docs manifest + codex-skills-and-idea-plugins recentrés skills IdeA-native vs .codex-plugin Codex, README; QA verte: npm run build)

This commit is contained in:
2026-09-08 15:48:47 +02:00
parent 1239104b0f
commit 6eb8db3791
5 changed files with 101 additions and 26 deletions

View File

@ -16,7 +16,7 @@ exports `activate(ctx)`.
- [Windows](docs/windows.md): opening plugin layouts in detached OS windows. - [Windows](docs/windows.md): opening plugin layouts in detached OS windows.
- [Services](docs/services.md): workspace, tasks, tooling, events, config, terminal and windows facades. - [Services](docs/services.md): workspace, tasks, tooling, events, config, terminal and windows facades.
- [Packaging And Distribution](docs/packaging-distribution.md): build output, archive layout, hot reload and dependency rules. - [Packaging And Distribution](docs/packaging-distribution.md): build output, archive layout, hot reload and dependency rules.
- [Codex Skills And IdeA Plugins](docs/codex-skills-and-idea-plugins.md): separate runtime install from Codex skill discovery. - [Codex Skills And IdeA Plugins](docs/codex-skills-and-idea-plugins.md): separate IdeA-native plugin skills from Codex plugin discovery.
The installable example lives in [`examples/hello-plugin`](examples/hello-plugin). The installable example lives in [`examples/hello-plugin`](examples/hello-plugin).
It demonstrates a menu command, storage, background-task feedback, a React layout It demonstrates a menu command, storage, background-task feedback, a React layout

View File

@ -1,12 +1,20 @@
# Codex Skills And IdeA Plugins # Codex Skills And IdeA Plugins
IdeA runtime plugins and Codex plugins are separate installation and discovery IdeA runtime plugins, IdeA-native plugin skills and Codex plugins are distinct
systems. installation and discovery systems.
An IdeA runtime plugin is described by `idea-plugin.json`. Installing it through An IdeA runtime plugin is described by `idea-plugin.json`. Installing it through
IdeA makes its IdeA runtime contributions available: menus, menu items, slash IdeA makes its global runtime package available. Project settings then decide
commands, layouts, MCP servers and runtime services declared by the IdeA plugin which installed plugins are enabled for a project, and agent settings decide
manifest. which plugin skills and plugin MCP tools are assigned to each agent.
An IdeA-native plugin skill is declared in `idea-plugin.json` under
`contributes.skills`. Its body is a package-relative Markdown file such as
`skills/<name>/SKILL.md`. When the plugin is enabled for a project and the skill
is assigned to an agent, IdeA injects the skill affordance into that agent's
skill catalogue and serves the body through `idea_skill_read`. This is not
Codex-specific; it is projected by IdeA for every harness that supports IdeA
capabilities, including Claude Code, Codex, OpenCode local and OpenCode cloud.
A Codex plugin is described by `.codex-plugin/plugin.json`. Its `skills` entry A Codex plugin is described by `.codex-plugin/plugin.json`. Its `skills` entry
points Codex at skill directories such as `skills/*/SKILL.md`. This metadata is points Codex at skill directories such as `skills/*/SKILL.md`. This metadata is
@ -15,27 +23,29 @@ loading.
## Normative Behavior ## Normative Behavior
- Installing or reloading an IdeA plugin makes the package available globally,
but does not automatically enable it in every project.
- Enabling a plugin for a project does not automatically assign every skill or
MCP tool to every agent.
- A plugin skill becomes visible to an agent only when the plugin is enabled for
the project and that skill is assigned to that agent.
- Installing or reloading an IdeA plugin does not automatically install a bundled - Installing or reloading an IdeA plugin does not automatically install a bundled
Codex plugin. Codex plugin, and `.codex-plugin/plugin.json` remains inert for IdeA-native
- Installing or reloading an IdeA plugin does not automatically make bundled plugin loading unless a separate bridge explicitly consumes it.
Codex skills available to agents in the current project. - Bundling `.codex-plugin/plugin.json` is still allowed as distribution content
- Installing or reloading an IdeA plugin does not automatically make bundled for Codex-specific workflows, but it is not the multi-harness IdeA contract.
Codex skills available to agents in other projects.
- No `idea-plugin.json` manifest field currently declares Codex skills for IdeA
agent assignment.
- Bundling `.codex-plugin/plugin.json` and `skills/*/SKILL.md` inside an IdeA
plugin package is allowed as distribution content, but it is inert for IdeA
runtime plugin loading unless a separate bridge explicitly consumes it.
## Required Mechanism ## Required Mechanisms
If a plugin needs Codex skills to be available to agents, install the Codex For multi-harness IdeA agent skills, declare `contributes.skills` in
plugin through the Codex plugin mechanism for the intended scope, then assign or `idea-plugin.json`, ship the referenced Markdown files inside the package,
enable those skills for the relevant agents according to Codex/IdeA agent install the plugin in IdeA, enable it in the target project, and assign the
configuration. skills to the target agents.
Do not rely on IdeA plugin installation as a cross-project skill propagation For Codex-specific plugin skills, install the Codex plugin through the Codex
mechanism. Cross-project skill availability needs an explicit product contract plugin mechanism for the intended scope, then assign or enable those skills
covering scope, provenance, permissions, uninstall behavior, hot reload, according to Codex/IdeA agent configuration.
collisions and security. Until that bridge exists, document and perform Codex
skill installation separately from IdeA runtime plugin installation. Do not rely on `.codex-plugin/plugin.json` as a cross-harness skill propagation
mechanism. Cross-harness plugin skill availability is driven by
`idea-plugin.json` and IdeA project/agent assignments.

View File

@ -143,6 +143,40 @@ development loop.
## Contributions ## 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 `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 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. window. Do not add a separate manifest contribution type for windows.

View File

@ -6,6 +6,8 @@ export type {
IdeAPluginLayoutContribution, IdeAPluginLayoutContribution,
IdeAPluginMcpServerContribution, IdeAPluginMcpServerContribution,
IdeAPluginMenuItemContribution, IdeAPluginMenuItemContribution,
IdeAPluginSkillContribution,
IdeAPluginSkillKind,
IdeAPluginTopLevelMenuContribution IdeAPluginTopLevelMenuContribution
} from "./manifest.js"; } from "./manifest.js";
export { export {

View File

@ -14,6 +14,7 @@ export interface IdeAPluginManifest {
*/ */
activationScope?: IdeAPluginActivationScope; activationScope?: IdeAPluginActivationScope;
contributes?: { contributes?: {
skills?: IdeAPluginSkillContribution[];
menus?: IdeAPluginTopLevelMenuContribution[]; menus?: IdeAPluginTopLevelMenuContribution[];
menuItems?: IdeAPluginMenuItemContribution[]; menuItems?: IdeAPluginMenuItemContribution[];
slashCommands?: IdeAPluginSlashCommandContribution[]; slashCommands?: IdeAPluginSlashCommandContribution[];
@ -26,10 +27,24 @@ export type IdeAPluginCapability = "ui" | "mcp" | "tooling";
export type IdeAPluginActivationScope = "app" | "project"; export type IdeAPluginActivationScope = "app" | "project";
export type IdeAPluginSkillKind = "workflow" | "reference";
export interface IdeAPluginEngineConstraints { export interface IdeAPluginEngineConstraints {
idea?: string; idea?: string;
} }
export interface IdeAPluginSkillContribution {
id: string;
/** Agent-facing name shown in the injected skill catalogue and accepted by idea_skill_read. */
name: string;
/** Short affordance shown to agents before they load the skill body. */
description: string;
/** Defaults to "workflow". */
kind?: IdeAPluginSkillKind;
/** Package-relative Markdown file, usually skills/<name>/SKILL.md. */
path: string;
}
export interface IdeAPluginTopLevelMenuContribution { export interface IdeAPluginTopLevelMenuContribution {
id: string; id: string;
label: string; label: string;
@ -192,6 +207,20 @@ function validateContributes(value: unknown, errors: string[]): void {
return; return;
} }
validateArray(value, "skills", errors, (skill, index) => {
requireString(skill, "id", errors, `contributes.skills[${index}].id`);
requireString(skill, "name", errors, `contributes.skills[${index}].name`);
requireString(skill, "description", errors, `contributes.skills[${index}].description`);
requireString(skill, "path", errors, `contributes.skills[${index}].path`);
if (typeof skill.kind === "string" && skill.kind !== "workflow" && skill.kind !== "reference") {
errors.push(`contributes.skills[${index}].kind must be "workflow" or "reference" when provided`);
} else if (skill.kind !== undefined && typeof skill.kind !== "string") {
errors.push(`contributes.skills[${index}].kind must be a string when provided`);
}
if (typeof skill.path === "string" && !skill.path.endsWith(".md")) {
errors.push(`contributes.skills[${index}].path must point to a .md file`);
}
});
validateArray(value, "menus", errors, (menu, index) => { validateArray(value, "menus", errors, (menu, index) => {
requireString(menu, "id", errors, `contributes.menus[${index}].id`); requireString(menu, "id", errors, `contributes.menus[${index}].id`);
requireString(menu, "label", errors, `contributes.menus[${index}].label`); requireString(menu, "label", errors, `contributes.menus[${index}].label`);