Skip to content
Developer Preview

Validation diagnostics

Use this page when muse plugins validate or muse plugins install prints a diagnostic you do not recognise. Each code below says what triggered it and what to change. The output shapes, the valid rule, the compatibility summary and the exit codes are at the end. Every output on this page was produced by Muse Code 1.3.0 against a copy of the weather example with one deliberate edit. The plugin surface is part of the Developer Preview and may change.

Text output prints one line per diagnostic:

diagnostic=<code> severity=<error|warning> path=<file or directory> message=<text>

severity is error or warning. A report is valid when it has no error; warnings never flip it. Some codes are always errors, some are always warnings, and two (unsupported-capability and unsupported-field) change severity with context, as their rows say. The path names the manifest for manifest problems and the offending file for file problems.

These fire before or while the manifest itself is read.

Code Severity When it fires What to change
invalid-plugin-package error The path you gave is not a readable directory or cannot be resolved. From muse plugins list, a cached package no longer matches its install record. Point at the plugin directory. For a drifted cache, remove and reinstall the plugin.
missing-manifest error No supported manifest: no root plugin.json with the exact Agent Plugins 1.0.0 $schema and no .muse-plugin/, .claude-plugin/ or .codex-plugin/ plugin.json. Add .muse-plugin/plugin.json.
multiple-manifests warning More than one nested marker exists; the message names the winner and the ignored files. Precedence is .muse-plugin, .claude-plugin, .codex-plugin. Delete the markers you do not mean, or accept the choice.
ignored-root-manifest warning A root plugin.json exists but is unreadable, not JSON, not an object, or has a $schema that is not an Agent Plugins URI. It is ignored and nested discovery continues. Remove the file or give it the exact Agent Plugins 1.0.0 $schema.
unsupported-agent-schema error The root plugin.json $schema is under https://agent-plugins.org/schemas/ but is not the exact 1.0.0 URI. The package is rejected with no fallback to nested markers. Use https://agent-plugins.org/schemas/1.0.0/plugin.schema.json.
invalid-manifest-json error The manifest is not valid JSON; the message carries the parser position. Fix the JSON.
invalid-manifest-schema error A structural rule broke: schemaVersion is not 1; the root is not an object; a required string (name, version, description) is missing or empty; capabilities is missing or not an object; a family value is not an array; an entry is not an object; a command array contains a non-string; an MCP transport is not stdio or http; an http server has no url; when has the wrong shape; a compatibilityName or outputCapabilities rule broke; a reminder decision is invalid; the manifest is over 128 KiB or not UTF-8; a foreign manifest contains a terminal-control character; the package mints more than 8,192 compatibility declarations. Read the message; it names the field and the rule. See the Manifest reference.
manifest-family-mismatch error compat.manifestDir is missing or does not equal the directory the manifest is in. Set "compat": {"manifestDir": ".muse-plugin"} for a native plugin.
invalid-plugin-id error name does not match ^[a-z0-9][a-z0-9._-]{0,79}$. Use lowercase letters, digits, ., _, -; start with a letter or digit; at most 80 characters.
invalid-version error version is present but blank. Write a non-blank version such as 0.1.0.

These fire while individual entries under capabilities are checked.

Code Severity When it fires What to change
invalid-capability-id error An entry has no string id, or the id breaks the identifier grammar. Add an id that matches ^[a-z0-9][a-z0-9._-]{0,79}$.
duplicate-capability-id error Two entries in one family share an id; a command reuses a skill id; a reminder reuses a skill or command id. Rename one of them.
missing-capability-path error A skill, command or reminder entry has no path, or a declared path (including a hook or MCP script) does not exist, is not a regular file, or cannot be resolved. The message is “plugin file is not readable” for a missing file. Add the file or fix the path.
unsafe-path error A path is absolute, contains .. or a drive prefix, is not UTF-8, or resolves outside the plugin root. Use a relative path that stays inside the package.
missing-capability-command error A hook, or a stdio MCP server, has no command array or an empty one. Add "command": ["<program>", "<args>"...].
unsupported-hook-event error event is missing from the accepted list for this manifest format. Use one of the names in Hook events and payloads, spelled exactly.
duplicate-hook-source error Two hooks name the same script file in their command. Give each hook its own script, or merge the hooks.
unsupported-field error on a hook or reminder entry; warning elsewhere A hook or reminder entry carries a key outside its accepted list (for hooks: matcher, type, timeout, if, …). At the top level or directly under capabilities, an unknown key such as author or widgets is a warning and is ignored. Remove the key. For matcher, drop it: native hooks are selected by event, and compatibilityName narrows tool events.
unsupported-capability warning when the manifest also declares a supported capability; error when it declares nothing else A tools, agents, outputStyles, settings, apps or developerPrompts family is declared (top level or under capabilities). Each entry becomes an unsupported declaration such as tool:lookup in the compatibility inventory and never runs. Remove the family, or provide the behaviour another way (custom tools through an MCP server).

These fire only for packages with a .claude-plugin, .codex-plugin or Agent Plugins manifest. What each format imports is described in Compatibility with other plugin formats.

Code Severity When it fires What to change
honored-declaration warning A Claude command template sets disable-model-invocation; the message says how Muse Code applied it (user-invocable only when true). Nothing; this confirms the declaration took effect.
unsupported-capability (foreign cases) error, or warning when other capabilities are supported A Claude or Codex MCP server is rejected (non-stdio transport, non-empty env, an unknown key, or a placeholder other than the plugin root and data variables); a conditional hook with an invalid if selector is left inactive; a Claude Setup hook is skipped; agents, dependencies, lspServers, outputStyles, requiredPlugins, settings, userConfig (Claude) or apps (Codex) are declared; a Claude commands value is a bare string instead of a path array. A rejected MCP server or a dependencies or requiredPlugins declaration also blocks install. The message names the entry and the clause. Fix the MCP server entry; drop the unsupported declaration or accept that it stays inactive.
unsupported-field (foreign cases) warning; error for an unknown hook group or handler key A Claude manifest key is presentation-only (author, homepage, repository, license, keywords, tags, interface) or not modelled; an unknown key sits in a hook file. Nothing for presentation keys; remove unknown hook keys.
agent-component-invalid warning In an Agent Plugins package, skills/ or the root mcp.json is the wrong kind of entry, escapes the package or is invalid. Only that component is disabled. Fix the component.
agent-skill-skipped warning One skill directory under skills/ is invalid and is skipped; siblings survive. Fix the named skill.
agent-mcp-server-skipped warning One entry in the root mcp.json is invalid and is skipped; siblings survive. Fix the named entry.
agent-overlay-inactive warning A nested marker sits beside an authoritative Agent Plugins root; its keys other than a matching name are ignored. Remove the overlay or move its content into the Agent Plugins manifest.

One more code, bundled_plugin_id_reserved (note the underscores), is a warning printed by muse plugins list and muse plugins inspect rather than by validate: an installed plugin uses the id of a built-in plugin, the built-in wins and the installed plugin contributes nothing. Rename the plugin.

Each command below ran against a copy of the weather example with one edit. The copy is named after the edit, which is why the invalid line names the directory: the validator prints the plugin id only for a valid report.

name changed to Weather_App:

Terminal window
muse plugins validate bad-name
invalid bad-name diagnostics=1
diagnostic=invalid-plugin-id severity=error path=bad-name/.muse-plugin/plugin.json message=plugin id `Weather_App` is invalid

Skill path pointing at a file that does not exist:

invalid missing-file diagnostics=1
diagnostic=missing-capability-path severity=error path=missing-file/skills/forecast/SKILLS.md message=plugin file is not readable: No such file or directory (os error 2)

"matcher": "Bash" added to the hook entry. The real message is longer; paraphrased, it says that matcher is a Claude or Codex hook field and that plugin hooks key on event:

invalid matcher diagnostics=1
diagnostic=unsupported-field severity=error path=matcher/.muse-plugin/plugin.json message=hook capability field `matcher` is a Claude/Codex hook field; ... plugin hooks key on `event`; matcher aliasing is tracked separately

Hook event changed to OnSave:

invalid bad-event diagnostics=1
diagnostic=unsupported-hook-event severity=error path=bad-event/.muse-plugin/plugin.json message=hook capability `log-tool-use` event `OnSave` is unsupported

The skill entry duplicated:

invalid dup-id diagnostics=1
diagnostic=duplicate-capability-id severity=error path=dup-id/.muse-plugin/plugin.json message=duplicate skill capability id `forecast`

compat removed:

invalid no-compat diagnostics=1
diagnostic=manifest-family-mismatch severity=error path=no-compat/.muse-plugin/plugin.json message=plugin manifest must declare compat.manifestDir

Command path changed to ../outside.md:

invalid unsafe-path diagnostics=1
diagnostic=unsafe-path severity=error path=unsafe-path/.muse-plugin/plugin.json message=plugin capability path must stay inside plugin root

A second hook that reuses hooks/log-tool-use.sh (this diagnostic names the file by its absolute path, shortened here):

invalid dup-source diagnostics=1
diagnostic=duplicate-hook-source severity=error path=<absolute path to dup-source>/hooks/log-tool-use.sh message=hook capability `log-again` reuses source `hooks/log-tool-use.sh` already used by `log-tool-use`

Hook command removed:

invalid no-command diagnostics=1
diagnostic=missing-capability-command severity=error path=no-command/.muse-plugin/plugin.json message=hook capability `log-tool-use` must declare a command array

An http MCP server without url:

invalid http-no-url diagnostics=1
diagnostic=invalid-manifest-schema severity=error path=http-no-url/.muse-plugin/plugin.json message=mcp server `remote` with http transport must declare url

"when": {}:

invalid bad-when diagnostics=1
diagnostic=invalid-manifest-schema severity=error path=bad-when/.muse-plugin/plugin.json message=plugin manifest `when` must be exactly {"env": {"VAR": "value"}}

The .muse-plugin directory deleted:

invalid no-manifest diagnostics=1
diagnostic=missing-manifest severity=error path=no-manifest message=plugin root must contain one supported plugin manifest: a root plugin.json with the exact Agent Plugins 1.0.0 $schema, or exactly one nested .muse-plugin/.codex-plugin/.claude-plugin plugin.json

Warnings leave the report valid. With "author": "Docs team" added at the top level, the summary line goes to stdout and the warning to stderr:

valid weather native skills=1 commands=1 hooks=1 mcp=0 reminders=0 diagnostics=1
diagnostic=unsupported-field severity=warning path=unknown-field/.muse-plugin/plugin.json message=plugin manifest field `author` is not used by this runtime

A tools family next to supported capabilities is a warning; on its own it is an error:

valid weather native skills=1 commands=1 hooks=1 mcp=0 reminders=0 diagnostics=1
diagnostic=unsupported-capability severity=warning path=tools-family/.muse-plugin/plugin.json message=plugin tools capabilities are not supported in this phase
invalid only-tools diagnostics=1
diagnostic=unsupported-capability severity=error path=only-tools/.muse-plugin/plugin.json message=plugin tools capabilities are not supported in this phase

A .claude-plugin/plugin.json added beside the native manifest:

valid weather native skills=1 commands=1 hooks=1 mcp=0 reminders=0 diagnostics=1
diagnostic=multiple-manifests severity=warning path=two-markers message=selected `.muse-plugin/plugin.json`; ignoring `.claude-plugin/plugin.json`

Several problems at once are all reported, in manifest order, and the diagnostics= count matches the lines that follow:

invalid multi diagnostics=3
diagnostic=unsupported-field severity=warning path=multi/.muse-plugin/plugin.json message=plugin manifest field `homepage` is not used by this runtime
diagnostic=invalid-plugin-id severity=error path=multi/.muse-plugin/plugin.json message=plugin id `Weather_App` is invalid
diagnostic=unsupported-hook-event severity=error path=multi/.muse-plugin/plugin.json message=hook capability `log-tool-use` event `OnSave` is unsupported

Valid: one line on stdout, warnings (if any) on stderr. Repeated unsupported-field warnings with the same message are rolled into one line with count=N and path=-.

valid <plugin-id> <native|claude-compatible|codex-compatible|agent-plugins> skills=N commands=N hooks=N mcp=N reminders=N diagnostics=N

Invalid: a header naming the path you passed, then every diagnostic in report order with no rollup, then the line plugin validation reported diagnostics on stderr.

invalid <path> diagnostics=N
diagnostic=... (N lines)

muse plugins validate <path> --json prints one JSON document. A valid report has this shape (the weather example, trimmed):

{
"valid": true,
"source_path": "weather",
"plugin": {
"id": "weather",
"display_name": "Weather",
"version": "0.1.0",
"description": "Example plugin: a forecast skill, a forecast-brief command, and a hook that logs tool use.",
"manifest_family": "native",
"capabilities": { "skills": ["..."], "hooks": ["..."], "mcp_servers": [], "commands": ["..."], "reminders": [] },
"compatibility": {
"summary": "full",
"declarations": [
{ "id": "skill:forecast", "kind": "skill", "classification": "supported" },
{ "id": "hook:log-tool-use", "kind": "hook", "classification": "supported" },
{ "id": "command:forecast-brief", "kind": "command", "classification": "supported" }
]
}
},
"capabilities": {
"skills": [
{ "id": "forecast", "path": "skills/forecast/SKILL.md", "source_path": "<absolute path to weather>/skills/forecast/SKILL.md", "enabled_default": true }
],
"hooks": [
{ "id": "log-tool-use", "event": "PostToolUse", "matcher": null, "command": ["sh", "hooks/log-tool-use.sh"], "shell_command": null, "source_path": "<absolute path to weather>/hooks/log-tool-use.sh", "source_relative_path": "hooks/log-tool-use.sh", "timeout_ms": 5000, "async": false, "compatibility_name": null }
],
"mcp_servers": [],
"commands": [
{ "id": "forecast-brief", "path": "commands/forecast-brief.md", "source_path": "<absolute path to weather>/commands/forecast-brief.md", "enabled_default": true }
],
"reminders": []
},
"diagnostics": []
}
Member Meaning
valid true when no diagnostic has severity: "error". Warnings do not change it.
source_path The path you passed, as you wrote it.
plugin Identity and inventory of the parsed manifest: id, display_name, version, description, manifest_family (native, claude-compatible, codex-compatible or agent-plugins), a nested capabilities copy, and compatibility. null when no plugin could be parsed.
plugin.compatibility.summary full, partial or unsupported; see below. Absent when a hard error (an error-severity unsupported-field or unsupported-hook-event) stopped the inventory.
plugin.compatibility.declarations One row per capability and per unsupported declaration: id is <kind>:<local-id>, kind is one of skill, command, hook, mcp, reminder, tool, agent, app, dependency, developer-prompt, invocation-preapproval, lsp, output-style, setting, user-config, agent-tool-projection; classification is supported or unsupported.
capabilities Parsed entries by family: skills, commands (id, path, source_path, enabled_default), hooks (id, event, matcher, command, shell_command, source_path, source_relative_path, timeout_ms, async, compatibility_name), mcp_servers (id, transport, command, url, source_path, source_relative_path), reminders (id, path, source_path, tools, blocking, default_priority, max_priority, max_child_steps, max_installs_per_run, reasoning_effort). All five arrays are empty when the report is invalid. timeout_ms is null when the manifest declared none; enabled_default is null for Claude-format skills.
diagnostics Array of {code, severity, message, path}. path is null when no file applies.

An invalid report is wrapped in an error envelope. code and message come from the first error-severity diagnostic; details is the full report with valid: false:

{
"error": {
"code": "missing-capability-path",
"message": "plugin file is not readable: No such file or directory (os error 2)",
"details": {
"valid": false,
"source_path": "missing-file",
"plugin": {
"compatibility": {
"summary": "full",
"declarations": [
{ "id": "hook:log-tool-use", "kind": "hook", "classification": "supported" },
{ "id": "command:forecast-brief", "kind": "command", "classification": "supported" }
]
}
},
"capabilities": { "skills": [], "hooks": [], "mcp_servers": [], "commands": [], "reminders": [] },
"diagnostics": [
{
"code": "missing-capability-path",
"severity": "error",
"message": "plugin file is not readable: No such file or directory (os error 2)",
"path": "missing-file/skills/forecast/SKILLS.md"
}
]
}
}
}

Note that the inventory inside an invalid report lists only the entries that parsed: the broken skill is absent from declarations, so a summary in an invalid report says nothing about the package as a whole.

plugin.compatibility.summary is derived from the declaration rows; you never write it.

Value Meaning Install
full Every declaration is supported. allowed
partial At least one supported and at least one unsupported declaration. Unsupported ones are visible in muse plugins inspect but never run. allowed, unless an unsupported declaration is a rejected foreign MCP server or a Claude dependencies or requiredPlugins entry
unsupported No supported declaration. refused with “plugin compatibility is unsupported: no supported behavior capabilities”
Exit code When
0 The report is valid (warnings allowed). With --json, the document has valid: true.
1 The report has at least one error. With --json, the document is the error envelope. Also returned when the path is not a plugin directory (invalid-plugin-package).
2 Usage error: no path, or an unknown option. The message (for example missing plugin package path) is printed on stderr followed by the general usage.

muse plugins validate never executes plugin code, starts an MCP server, runs a hook, touches the network or changes your plugin store. The same validator runs again on the copied package during muse plugins install and muse plugins update, so a package that validates cleanly here can still be refused at install for reasons the validator cannot see: symlink entries, more than 4,096 entries, nesting deeper than 16 levels, or an unsupported compatibility summary.