Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 19 additions & 16 deletions docs/diagnostics.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ entry names) holds a hand-authored `SKILL.md` or a rendered source module
(`SKILL.tsx`/`SKILL.ts`; `docs/framework-mode.md`). Parsing runs at discovery
and reports `AB3000`–`AB3005` on the document; the Skill IR is then read from
the frontmatter (`AB3006`) during source validation, and the IR is lowered once
per selected skill host — `claude`, `codex`, `cursor`, `portable`, plus the
unified `plugin` target's shared document — with `AB3008`–`AB3010` judged on
per selected skill host — `amp`, `claude`, `codex`, `cursor`, `portable`
with `AB3008`–`AB3010` judged on
the normalized model and carrying `target`. A skill whose frontmatter declares
no host extension and whose body carries no token passes through byte for byte
and is never lowered. `AB3007` is not assigned.
Expand All @@ -85,10 +85,10 @@ and is never lowered. `AB3007` is not assigned.
| `AB3003` | error | The rendered skill module failed to load: `Rendered Skill module failed to load: <error>` — a syntax error, an unresolved import, or a throw at module evaluation (the published `agent-bundle/meta` reached without a project identity raises `AB4760` here). | Fix the module so it imports and evaluates; `agent-bundle validate` prints the message. |
| `AB3004` | error | The rendered skill module does not default-export a component function, does not export a `frontmatter` plain object, or its `frontmatter` cannot be serialized as YAML. | Export both a default component and `export const frontmatter = { name, description, … }`. |
| `AB3005` | error | Rendering the component to Markdown failed: an element outside the supported subset (`h1`–`h6`, `p`, `ul`/`ol`/`li`, `strong`/`b`, `em`/`i`, `code`, `pre`, `blockquote`, `a`, `hr`, `br`, fragments, text), a structural rule of that subset (`<a>` without a nonempty string `href`, `<pre>` holding anything but text or one `<code>`, a list child that is not `<li>`, an empty list), a component that threw or resolved past the depth limit, a value that is neither text nor a supported element, or content that produced no Markdown; the message names the construct. | Write the content within the supported elements, or hand-author `SKILL.md`. |
| `AB3006` | error | Skill frontmatter declares a field that is not a portable Agent Skills field (`name`, `description`, `license`, `compatibility`, `allowed-tools`, `metadata`), not a typed host extension (Claude: `agent`, `argument-hint`, `arguments`, `background`, `context`, `disallowed-tools`, `effort`, `hooks`, `model`, `shell`, `user-invocable`, `when_to_use`; Cursor: `color`, `globs`, `icon`; shared: `disable-model-invocation`, `paths`), and not the authoring key `targets`; or `targets` is not an object, carries a key other than `claude`, `codex`, `cursor`, or holds an unknown key inside `targets.<host>` (including `targets.codex.interface`, `.policy`, `.dependencies`, and `.dependencies.tools[<n>]`). The message names the field path. | Move host-only fields into `targets.<host>` or a documented host key, or remove the unknown field. |
| `AB3008` | error | The Skill Markdown body uses a canonical token (`agent-bundle:token:arguments`, `agent-bundle:path:plugin-root`, `agent-bundle:path:plugin-data`, `agent-bundle:path:workspace-root`, `agent-bundle:token:session-identity`, `agent-bundle:token:skill-root`) or a host alias of one (`$ARGUMENTS`, `${CLAUDE_PLUGIN_ROOT}`, `${PLUGIN_ROOT}`, `${workspaceFolder}`, …), and the skill lowers to a host whose pinned Skill Markdown contract documents no interpolation placeholder: Codex, Cursor, portable, and the unified `plugin` target's shared portable document. Claude documents all six. One diagnostic per token per host: `Skill token "<token>" has no <host> Skill Markdown equivalent.` | Remove the token, restrict the skill to a host that documents it, or move the reference to a document that host interpolates. |
| `AB3009` | error | After token lowering, the `<host>` Skill Markdown body still contains a placeholder spelling another host's contract owns — for Codex, Cursor, and portable documents, one of Claude's `$ARGUMENTS`, `${CLAUDE_PLUGIN_DATA}`, `${CLAUDE_PLUGIN_ROOT}`, `${CLAUDE_PROJECT_DIR}`, `${CLAUDE_SESSION_ID}`, `${CLAUDE_SKILL_DIR}`; the message names the syntax. | Use canonical agent-bundle tokens so lowering emits only this host's documented placeholders. |
| `AB3010` | error | The lowered `<host>` skill frontmatter fails that host's pinned schema — `schemas/skill-hosts/claude-skill-frontmatter.schema.json` and `cursor-skill-frontmatter.schema.json` for Claude and Cursor, the Agent Skills frontmatter schema for Codex and portable: `Lowered <host> Skill document <field> <message>.` | Remove the unsupported field or restrict the skill to a host that documents it. |
| `AB3006` | error | Skill frontmatter declares a field that is not a portable Agent Skills field (`name`, `description`, `license`, `compatibility`, `allowed-tools`, `metadata`), not a typed host extension (Claude: `agent`, `argument-hint`, `arguments`, `background`, `context`, `disallowed-tools`, `effort`, `hooks`, `model`, `shell`, `user-invocable`, `when_to_use`; Cursor: `color`, `globs`, `icon`; Amp: `builtin-tools`, `mcpServers`; shared: `disable-model-invocation`, `paths`), and not the authoring key `targets`; or `targets` is not an object, carries a key other than `amp`, `claude`, `codex`, `cursor`, or holds an unknown key inside `targets.<host>` (including `targets.amp`, `targets.codex.interface`, `.policy`, `.dependencies`, and `.dependencies.tools[<n>]`). The message names the field path. | Move host-only fields into `targets.<host>` or a documented host key, or remove the unknown field. |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Remove valid targets.amp from the invalid examples

For a Skill using the newly supported targets: { amp: ... } extension, this row now simultaneously lists amp as an accepted target key and names targets.amp as an example of an unknown field. skills/parse-ir.ts explicitly accepts amp and reports only unknown keys nested beneath it, so the generated diagnostics reference incorrectly implies that valid Amp configuration triggers AB3006; remove this example or replace it with a genuinely invalid nested key.

AGENTS.md reference: AGENTS.md:L139-L142

Useful? React with 👍 / 👎.

| `AB3008` | error | The Skill Markdown body uses a canonical token (`agent-bundle:token:arguments`, `agent-bundle:path:plugin-root`, `agent-bundle:path:plugin-data`, `agent-bundle:path:workspace-root`, `agent-bundle:token:session-identity`, `agent-bundle:token:skill-root`) or a host alias of one (`$ARGUMENTS`, `${CLAUDE_PLUGIN_ROOT}`, `${PLUGIN_ROOT}`, `${workspaceFolder}`, …), and the skill lowers to a host whose pinned Skill Markdown contract documents no interpolation placeholder: Amp, Codex, Cursor, and portable. Claude documents all six. One diagnostic per token per host: `Skill token "<token>" has no <host> Skill Markdown equivalent.` | Remove the token, restrict the skill to a host that documents it, or move the reference to a document that host interpolates. |
| `AB3009` | error | After token lowering, the `<host>` Skill Markdown body still contains a placeholder spelling another host's contract owns — for Amp, Codex, Cursor, and portable documents, one of Claude's `$ARGUMENTS`, `${CLAUDE_PLUGIN_DATA}`, `${CLAUDE_PLUGIN_ROOT}`, `${CLAUDE_PROJECT_DIR}`, `${CLAUDE_SESSION_ID}`, `${CLAUDE_SKILL_DIR}`; the message names the syntax. | Use canonical agent-bundle tokens so lowering emits only this host's documented placeholders. |
| `AB3010` | error | The lowered `<host>` skill frontmatter fails that host's pinned schema — `schemas/skill-hosts/claude-skill-frontmatter.schema.json` and `cursor-skill-frontmatter.schema.json` for Claude and Cursor, the Agent Skills frontmatter schema for Amp, Codex, and portable, and Amp's pinned skill MCP rules for an Amp skill's `mcpServers`: `Lowered <host> Skill document <field> <message>.` | Remove the unsupported field or restrict the skill to a host that documents it. |

## Plugin metadata and Skill source validation (`AB4000`–`AB4007`, `AB4012`)

Expand Down Expand Up @@ -123,7 +123,7 @@ backstop.

| Code | Severity | Trigger | Recovery |
| --- | --- | --- | --- |
| `AB4100` | error | A selected target — `targets` in config, or the CLI's `--target` selection — is not a registered adapter: `Unknown target "<name>".` The built-in registry publishes `claude`, `codex`, `cursor`, and `portable`; `plugin` is one of the unknown names — it used to name a merged multi-host output and now selects nothing, because every build already emits the composite root (see the composite plugin root section below). Reported with `target`. | Select host projections (`claude`, `codex`, `cursor`, `portable`); omit `targets` for the default `portable` projection. |
| `AB4100` | error | A selected target — `targets` in config, or the CLI's `--target` selection — is not a registered adapter: `Unknown target "<name>".` The built-in registry publishes `amp`, `claude`, `codex`, `cursor`, and `portable`; `plugin` is one of the unknown names — it used to name a merged multi-host output and now selects nothing, because every build already emits the composite root (see the composite plugin root section below). Reported with `target`. | Select host projections (`amp`, `claude`, `codex`, `cursor`, `portable`); omit `targets` for the default `portable` projection. |
| `AB4101` | error | Two normalized components share one `id` (for example two skills normalizing to `skill:<name>`): `Normalized component ID "<id>" is duplicated.` | Rename or remove one of the two components. |
| `AB4102` | error | Two inputs of one target produce the same artifact path — a skill's `SKILL.md`, sidecar, or resource under `skills/<name>/`, an `assets/` file, `commands/<name>.md`, `rules/<name>.mdc`, a payload file, or a Claude `bin/`, `output-styles/`, or `workflows/` file: `Multiple inputs produce "<path>"; first source is <source>.` Reported with `generatedPath`, `sourcePath`, and `target`. | Rename or remove one of the inputs. |

Expand Down Expand Up @@ -827,14 +827,17 @@ skill's `AB3003`.

## The composite plugin root (`AB4100`, `AB4103`, `AB4105`, `AB4106`)

`build` emits **one** plugin root at the artifact directory (#555). The
`build` emits **one** composite root at the artifact directory (#555). The
`targets` list selects which host *projections* the root carries —
`claude`, `codex`, `cursor`, `portable` — and every selected host reads the
same directory as its plugin root: host manifests sit in their own dotfolders
(`.claude-plugin/`, `.codex-plugin/`, `.cursor-plugin/`, or `plugin.json`
for the portable format), while `skills/`, `hooks/`, `mcp/`, `scripts/`,
`bin/`, and `INSTALL.md` are shared. There is no `<root>/<host>/` partition
and no `plugin` target: the composite *is* the output. Only those four
`amp`, `claude`, `codex`, `cursor`, `portable`. `claude`, `codex`, `cursor`, and
`portable` read the artifact directory itself as their plugin root: their
manifests sit in `.claude-plugin/`, `.codex-plugin/`, `.cursor-plugin/`, or the
portable root `plugin.json`, while `skills/`, `hooks/`, `mcp/`, `scripts/`,
`bin/`, and `INSTALL.md` are shared. Amp is the exception: its plugin root is
the nested `.amp/plugins/<plugin>/` directory, self-contained down to its own
`skills/` and `hooks/`, and `install amp` copies that subdirectory rather than
the composite root. There is no `<root>/<host>/` partition and no `plugin`
target: the composite *is* the output. Only those five
built-in hosts share a root; an adapter registered on an advanced
`TargetRegistry` is built alone (`AB4106`). `validate` and `inspect` plan the
same composite root the build stages, so they report `AB4103` and `AB4105`
Expand All @@ -844,7 +847,7 @@ exactly where `build` would refuse.
| --- | --- | --- | --- |
| `AB4103` | error | Two selected projections plan the same component path with different bytes, so one root cannot hold both without changing native precedence. The diagnostic names the component location, path, and hosts. Common cases are a Skill whose host extension lowers to different `skills/<name>/SKILL.md` bytes, or a command whose Claude and Cursor dialects lower differently. Projections are compared in host-name order and paths in path order, so the same selection reports the same collision however `targets` is written. | Make the component identical for every selected host, or build the conflicting hosts into separate artifacts (one `targets` entry per build). |
| `AB4105` | error | A component scoped to a subset of the selected hosts (a command or rule with frontmatter `targets`) would be discovered by another selected host that scans the same conventional directory (`commands/` for Claude Code and Cursor, `rules/` for Cursor). Inside one root the file cannot be hidden from that host, so the build refuses rather than leaking it. Skills are never host-scoped — every skill ships to every selected host, and a per-host frontmatter extension that changes its bytes is an `AB4103` collision instead. | Extend the component's `targets` to every selected host that discovers its directory, or build those hosts into separate artifacts. |
| `AB4106` | error | The selection mixes an adapter registered on an advanced `TargetRegistry` — any target whose adapter is not one of the shipped `claude`, `codex`, `cursor`, `portable` adapters, judged by adapter identity, so a custom adapter registered under one of those names counts as advanced — with one or more other targets. The built-in hosts agree on where the files they cannot share live, which conventional directories each discovers, and one install surface; a third-party adapter has made none of those agreements, so it cannot share a root. Judged on the normalized model, so `validate`, `inspect`, and `build` all report it, on the non-built-in target with its config provenance. A selection of one target never triggers it, whatever the target; unknown names are `AB4100`'s and do not count. | Build that target alone — `targets: ['<name>']` — into its own `--output`, and the remaining targets into another. |
| `AB4106` | error | The selection mixes an adapter registered on an advanced `TargetRegistry` — any target whose adapter is not one of the shipped `amp`, `claude`, `codex`, `cursor`, `portable` adapters, judged by adapter identity, so a custom adapter registered under one of those names counts as advanced — with one or more other targets. The built-in hosts agree on where the files they cannot share live, which conventional directories each discovers, and one install surface; a third-party adapter has made none of those agreements, so it cannot share a root. Judged on the normalized model, so `validate`, `inspect`, and `build` all report it, on the non-built-in target with its config provenance. A selection of one target never triggers it, whatever the target; unknown names are `AB4100`'s and do not count. | Build that target alone — `targets: ['<name>']` — into its own `--output`, and the remaining targets into another. |

## Artifact-hosted routed CLI and npm lifecycle paths (`AB4765`–`AB4768`)

Expand Down Expand Up @@ -1893,7 +1896,7 @@ therefore does not prove the absence of such a load.
| `AB6016` | error | `Emitted Skill reference "<ref>" escapes its Skill root.` or `Emitted Skill references missing regular resource "<ref>".` — a relative reference inside a `SKILL.md` body points outside the Skill directory or at a file the artifact does not contain as a regular file. | Copy every referenced Skill resource inside its Skill root, then rebuild the artifact. |
| `AB6017` | error | Target MCP manifest coherence (`generatedPath` is the target's MCP manifest): the manifest is not strict JSON or does not contain only modern supported servers; a server's runtime values cannot be resolved; a `cwd`, `command`, or `args` path escapes the target, references a missing or unmanifested file, or names a non-executable command file; a compiler-emitted MCP entry is referenced by no server or by more than one; `projections[host].documents.mcp` does not point at the target's MCP manifest; a launchable `executables.mcpServers[]` server declared for the target is missing from the target's document under its name; or the document's server disagrees with the launch record of the same name — it is not a stdio server, the first artifact-local path its command and arguments name is not the record's `entry`, or the record's `artifact` arguments do not follow the entry in the record's order (the host document and `<plugin> web` would start different bytes; the document may add flags and literal arguments around them). | Rebuild the artifact so every target MCP manifest references its exact compiler outputs. |
| `AB6018` | error | Hook coherence, judged from `agent-bundle.manifest.json` `executables.hooks[]`: a hook row selects an undeclared or hook-incompatible host, or references a missing or invalid wrapper; a host with hook rows is missing its native hook document, or that document is invalid for command enumeration; a manifest hook row does not map to exactly one native command, or a native command has no manifest row (or more than one). | Rebuild the artifact so native hook commands and the manifest's hook rows agree. |
| `AB6023` | error | `Artifact is missing required install surface "INSTALL.md".` — the selection includes a built-in host (`claude`, `codex`, `cursor`, `portable`, judged by adapter identity, so an advanced registry's own adapter named like one requires nothing) but the composite root has no `INSTALL.md`; the surface is emitted once at the root, never per target. | Rebuild the artifact so the root carries its generated `INSTALL.md`. |
| `AB6023` | error | `Artifact is missing required install surface "INSTALL.md".` — the selection includes a built-in host (`amp`, `claude`, `codex`, `cursor`, `portable`, judged by adapter identity, so an advanced registry's own adapter named like one requires nothing) but the composite root has no `INSTALL.md`; the surface is emitted once at the root, never per target. | Rebuild the artifact so the root carries its generated `INSTALL.md`. |
| `AB6024` | error | `Artifact is missing required install surface "install.mjs".` — the selection includes the shipped `cursor` or `portable` adapter (judged by adapter identity, like `AB6023`) but the composite root has no `install.mjs` (a root selecting only `claude` and/or `codex` requires none). | Rebuild the artifact so the root carries its generated `install.mjs`. |
| `AB6025` | error | `Plugin logo "<logo>" escapes the artifact for target "<name>".` or `Plugin logo "<logo>" references missing artifact file "<path>".` — a `plugin.json` `logo` string resolves outside the target directory or to a file the artifact does not contain. | Rebuild the artifact so every manifest-declared logo path copies into the deploy tree. |
| `AB6039` | error | The artifact or package-only compile evidence sidecar is unreadable, invalid, judged under another policy, does not cover a compiled file, describes different bytes, names a path the corresponding file table does not list as compiled, misclassifies an external, or references a missing compiled sibling. An MCP App view also fails when its record names any external. A record with any `AB6039` finding, or with `coverage.rewritable` set, proves nothing to the emitted-module walk, which then parses every module in full. | Rebuild the artifact or generated npm root so its compile evidence describes the emitted files; do not edit generated evidence or outputs. |
Expand Down
Loading
Loading