Skip to content
Developer Preview

The muse plugins command

Use this page to look up any muse plugins verb: what it takes, what it prints, what its --json output contains, and how it fails. The plugin surface is part of the Developer Preview and may change. This page is long on purpose: it is the only place every verb’s --json shape is shown.

Every output on this page was produced by Muse Code 1.3.0 against a copy of the weather example in an empty plugin store. The store path is shown as <data dir>, which is ~/.local/share/muse unless you set XDG_DATA_HOME; the source directory is shown as <absolute path to weather>, and digests inside paths are shortened. Long outputs are trimmed where marked.

You do not have to type any of these verbs. In a Muse Code session, enter /plugins with nothing after it and a panel opens with four tabs, Discover, Installed, Marketplaces and Errors. Tab moves between them, typing filters the current list, and Esc closes the panel. Most of this page maps onto those tabs:

Verb In the panel
list The Installed tab; [x] marks an enabled plugin and needs review marks one with capabilities waiting for you.
inspect Enter on a plugin row opens its details: status, capability rows, source and cache paths.
enable, disable Space on a plugin row on the Installed tab, or the action row in its details.
approve, reject In a plugin’s details, Tab to the Runtime tab; Enter approves the selected hook, MCP server, reminder or agent definition and Space rejects it.
install <plugin>@<marketplace> The Discover tab lists every marketplace plugin; Enter on one installs it, as does Enter on a plugin inside a marketplace’s details.
update, remove Action rows in the plugin’s details; remove asks you to confirm.
marketplace add, marketplace list, marketplace update, marketplace remove The Marketplaces tab: Enter on “Add marketplace” prompts for a source, Enter on a marketplace opens it, Space removes it.
install <path>, validate, hook test Command line only. The panel installs from marketplaces; a local directory is installed with the command.

Two things exist only in the panel: a skill row in a plugin’s details can apply that plugin’s skills to the current session, and the Errors tab gathers every plugin diagnostic in one list. --json output and --scope project exist only on the command line. The composer also accepts the same verbs typed after the slash, such as /plugins install <path>, for the rare case where a session is the only terminal you have.

muse plugins <command>

muse plugins --help prints this table. Every leaf command also answers --help (or -h) with its own usage line and exit code 0.

Verb Positionals Flags What it does
validate <path> --json Validate a plugin directory without installing or running anything
install <path> or <plugin>@<marketplace> --scope user or --scope project (local path only), --json Copy a plugin into the store and enable it
list none --available, --json List installed plugins, or plugins offered by configured marketplaces
inspect <id> --json Show one installed plugin, its review-gated capabilities and their status
approve selector --json Trust and enable the current definition of one or more capabilities
reject selector --json Trust and disable the current definition of one or more capabilities
hook test <plugin-id>:<hook-id> --fixture <path> (required), --json Run one installed hook against a fixture file
marketplace add <name> <source> --json Register a marketplace and store an offline snapshot of its catalog
marketplace list none --json List configured marketplaces
marketplace update <name> --json Refresh a marketplace snapshot
marketplace remove <name> --json Forget a marketplace and delete its snapshot
enable <id> --json Enable an installed plugin for future sessions
disable <id> --json Disable an installed plugin
update <id> --json Re-read an installed plugin from the source it was installed from
remove <id> --delete-data, --json Delete the installed record, cached package and review decisions

muse plugins with no verb prints missing plugins command; an unknown verb prints unsupported plugins command `<verb>` . Both exit with code 2.

Human output is one line per result, fields separated by tabs, with key=value pairs. A second line starting with warning follows when the store has something to say about the plugin. Control characters and bidirectional format characters are stripped from ids, versions and messages before printing.

--json prints one pretty-printed JSON document on stdout and nothing else on stdout. Warnings that the human form sends to stderr appear as fields in the document.

Help is honoured only when every other argument is valid. muse plugins list --help --nope is still a usage error.

Exit codes:

Exit code Meaning Where the text goes
0 Success stdout
1 The command ran and failed (plugin not installed, invalid package, source gone, and so on) Human form: one line on stderr. --json: the error envelope on stdout and the same message on stderr
2 Usage error: missing or extra argument, unknown flag, bad --scope value, missing --fixture The message on stderr, followed by the root muse --help text

The --json error envelope has one error object with a stable kebab-case code and a human message. validate and install add a details member carrying the full validation report when the package was invalid.

{
"error": {
"code": "unknown-plugin",
"message": "plugin `nope` is not installed"
}
}

The full list of codes is in Error codes.

usage: muse plugins validate <path> [--json]

Validates the plugin directory at <path>. Nothing is installed and no plugin code runs. Use it before install, and on a Claude Code plugin to see what Muse Code will import.

Terminal window
$ muse plugins validate ./weather
valid weather native skills=1 commands=1 hooks=1 mcp=0 reminders=0 diagnostics=0

The human line is valid, the plugin id, the manifest family (native, claude-compatible, codex-compatible or agent-plugins), capability counts and the number of diagnostics. Warning diagnostics go to stderr as diagnostic=<code> severity=<severity> path=<path> message=<text>.

An invalid package prints invalid, the id or path, and one line per diagnostic, then exits 1:

Terminal window
$ muse plugins validate ./broken
invalid ./broken diagnostics=5
diagnostic=invalid-plugin-id severity=error path=./broken/.muse-plugin/plugin.json message=plugin id `Broken Plugin` is invalid
diagnostic=invalid-manifest-schema severity=error path=./broken/.muse-plugin/plugin.json message=plugin manifest must declare string field `version`
diagnostic=invalid-manifest-schema severity=error path=./broken/.muse-plugin/plugin.json message=plugin manifest must declare string field `description`
diagnostic=manifest-family-mismatch severity=error path=./broken/.muse-plugin/plugin.json message=plugin manifest must declare compat.manifestDir
diagnostic=invalid-manifest-schema severity=error path=./broken/.muse-plugin/plugin.json message=plugin manifest must declare capabilities

With --json, a valid package returns the validation report:

{
"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": { /* same shape as "capabilities" below */ },
"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": []
}

An invalid package returns the error envelope. code and message come from the first error-severity diagnostic, and details is the same report shape with "valid": false and the full diagnostics array:

{
"error": {
"code": "invalid-plugin-id",
"message": "plugin id `Broken Plugin` is invalid",
"details": {
"valid": false,
"source_path": "./broken",
"plugin": null,
"capabilities": { "skills": [], "hooks": [], "mcp_servers": [], "commands": [], "reminders": [] },
"diagnostics": [
{
"code": "invalid-plugin-id",
"severity": "error",
"message": "plugin id `Broken Plugin` is invalid",
"path": "./broken/.muse-plugin/plugin.json"
}
// four more
]
}
}
}

Capability entries in capabilities have these fields:

Kind Fields
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

Diagnostic codes and their meanings are listed in Validation diagnostics. To validate one skill directory on its own, run muse skills validate <dir>.

Missing <path> is a usage error: missing plugin package path.

usage: muse plugins install <path> [--scope user|project] [--json]
usage: muse plugins install <plugin>@<marketplace> [--json]

Validates the package, copies it into the content-addressed cache, records it in the store and enables it. Skills and commands are usable right away; hooks, MCP servers, reminders and agent definitions wait for approve.

The target is a marketplace reference only when it contains @, does not exist on disk, and is not shaped like a path (no leading . or ~, no / or \). Anything else is a local directory.

Terminal window
$ muse plugins install ./weather
installed weather 0.1.0 enabled=true trust=user-local provenance=native-local cache=<data dir>/plugins/cache/local/weather/bacc26ed…/package
warning third-party plugin: hooks require review before activation; skills and commands are active without review while the plugin is enabled

The human line is installed, id, version, an optional marketplace=<name>, then enabled, trust (user-local or project-trusted), provenance (native-local, foreign-import or marketplace-user-added) and the cache path. Install-time diagnostics go to stderr.

Terminal window
$ muse plugins install weather@local
installed weather 0.1.0 marketplace=local enabled=true trust=user-local provenance=marketplace-user-added cache=<data dir>/plugins/cache/local/weather/bacc26ed…/package
warning third-party plugin: hooks require review before activation; skills and commands are active without review while the plugin is enabled

With --json:

{
"installed": {
"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",
"enabled": true,
"trust": "user-local",
"source": {
"provenance": "native-local",
"path": "<absolute path to weather>"
},
"installed_at": "2026-09-17T04:24:55.92179Z",
"updated_at": "2026-09-17T04:24:58.191445Z",
"manifest_sha256": "sha256:b0cf4aec5eb6cef64aae6e93804589aa574704b638ea53922dc6f329ccdf7b78",
"package_sha256": "sha256:bacc26ede05bf8aa08c888ddacf24540f757fb51f5248927df265bdcd41ea62c",
"cache_path": "<data dir>/plugins/cache/local/weather/bacc26ed…/package"
},
"warning": "third-party plugin: hooks require review before activation; skills and commands are active without review while the plugin is enabled",
"diagnostics": [],
"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": { /* same shape as in validate */ }
},
"lockfile_path": "<data dir>/plugins/installed.json"
}

A marketplace install adds "marketplace": "<name>" at the top level. The installed object is the installed record; list, inspect, enable, disable and update return the same shape:

Field Meaning
id, display_name, version, description Copied from the manifest
manifest_family native, claude-compatible, codex-compatible or agent-plugins
enabled Whether the plugin loads in new sessions
trust user-local or project-trusted (the install scope, not capability review)
source.provenance native-local, foreign-import or marketplace-user-added
source.path The directory update re-reads
installed_at, updated_at RFC 3339 timestamps; updated_at is null until the first reinstall or update
manifest_sha256, package_sha256 Digests of the manifest and of the whole package tree
cache_path The immutable installed copy; plugin processes see it as MUSE_PLUGIN_ROOT

Installing an id that is already installed from the same path is an update: enabled and installed_at are kept and updated_at is set. Installing an id that is already installed from a different path is refused; pass --scope user to rebind it on purpose.

--scope accepts user or project, also as --scope=<value>; the last occurrence wins. --scope project requires the current directory to be a trusted workspace and <path> to be inside it, and records trust=project-trusted. Without the flag or with --scope user the record is user-local. Scope is recorded in your own store and is not shared with other users of the workspace. See Trust, review and scopes.

Notable errors:

Message Exit --json code
plugins install --scope project requires a local plugin path (marketplace target) 2 usage error, no envelope
invalid plugins install --scope `nope` (expected user or project) 2 usage error, no envelope
plugins install --scope requires a value 2 usage error, no envelope
failed to read plugin store `./missing`: No such file or directory (os error 2) 1 plugin-store-read-failed
plugin `weather` is already installed from a different source (reinstall from another path without --scope user) 1 invalid-plugin-package
A validation error message, with the report in details 1 the first diagnostic code, or invalid-plugin-package
marketplace `x` is not configured 1 unknown-marketplace
usage: muse plugins list [--available] [--json]

Without flags, lists installed plugins, one per line, or no plugins.

Terminal window
$ muse plugins list
weather 0.1.0 enabled=true active=true trust=user-local provenance=native-local valid=true diagnostics=0
warning third-party plugin: hooks require review before activation; skills and commands are active without review while the plugin is enabled

valid says the cached package still matches its recorded digests. active is valid && enabled for the package as a whole; it never means a review-gated capability is running. diagnostics counts cache and manifest diagnostics for that record.

With --json, each entry wraps the installed record:

{
"plugins": [
{
"record": { /* installed record */ },
"warning": "third-party plugin: hooks require review before activation; skills and commands are active without review while the plugin is enabled",
"plugin": { /* descriptor: id, display_name, version, description, manifest_family, capabilities */ },
"valid": true,
"active": true,
"active_scope": "installed-plugin",
"diagnostics": []
}
]
}

Each diagnostics element has code, severity, message and path. list takes no positional; muse plugins list weather is a usage error (unexpected argument `weather` ).

Lists the plugins offered by every configured marketplace snapshot. This reads stored snapshots only and never touches the network.

Terminal window
$ muse plugins list --available
weather@local 0.1.0 status=available transport=local-path

status is available, deprecated or blocked; only available entries can be installed. Marketplaces whose snapshot cannot be read are reported on stderr as warning: marketplace `<name>` skipped: <reason>.

{
"available": [
{
"marketplace": "local",
"name": "weather",
"version": "0.1.0",
"status": "available",
"install": {
"transport": "local-path",
"source": "<absolute path to market>/plugins/weather"
},
"digest": "sha256:bacc26ede05bf8aa08c888ddacf24540f757fb51f5248927df265bdcd41ea62c"
}
],
"skipped": [],
"warnings": []
}

skipped lists catalog entries that were dropped when the snapshot was taken (marketplace, name, reason); warnings lists unreadable marketplaces (marketplace, reason).

usage: muse plugins inspect <id> [--json]

Shows one installed plugin with capability counts, then one runtime-capability line per review-gated capability with its review status, then any capability-diagnostic lines.

Terminal window
$ muse plugins inspect weather
weather 0.1.0 enabled=true active=true trust=user-local valid=true skills=1 commands=1 hooks=1 mcp=0 reminders=0 cache=<data dir>/plugins/cache/local/weather/bacc26ed…/package
warning third-party plugin: hooks require review before activation; skills and commands are active without review while the plugin is enabled
runtime-capability plugin:weather:hook:log-tool-use status=review_needed

status is one of review_needed, trusted_enabled, trusted_disabled, modified, invalid or blocked; only trusted_enabled capabilities load. Trust, review and scopes explains each status and what moves a capability between them.

Agent definitions render as runtime-capability agent_definition <scoped-id> ordinal=<n> status=<status>.

With --json, the document is the list entry plus four members:

{
"record": { /* installed record */ },
"warning": "third-party plugin: hooks require review before activation; skills and commands are active without review while the plugin is enabled",
"plugin": { /* descriptor */ },
"valid": true,
"active": true,
"active_scope": "installed-plugin",
"diagnostics": [],
"effective_capabilities_scope": "plugin-capability-snapshot",
"effective_capabilities": [
{ "kind": "command", "stable_id": "plugin:weather:forecast-brief" },
{ "kind": "skill", "stable_id": "plugin:weather:forecast" }
],
"capability_diagnostics": [],
"runtime_capabilities": [
{
"candidate": {
"kind": "hook",
"plugin_id": "weather",
"capability_id": "log-tool-use",
"stable_id": "plugin:weather:hook:log-tool-use",
"display_path": "plugin://weather/hook/log-tool-use",
"definition_hash": "sha256:9a35bebf76782df57992d18e4f653c6e38ccbd3fd3d7121517b1e1bb6b958a2a",
"source_digest": "sha256:bacc26ede05bf8aa08c888ddacf24540f757fb51f5248927df265bdcd41ea62c"
},
"status": "review_needed",
"diagnostic": null
}
]
}

effective_capabilities are the skills and commands that load without review. runtime_capabilities are the review-gated ones; definition_hash is what approve binds to, and source_digest is the package digest that feeds it. capability_diagnostics elements have code, message, path.

Unknown id: plugin `nope` is not installed (exit 1, code unknown-plugin).

usage: muse plugins approve <plugin-id[[:kind]:capability-id] | stable-id> [--json]
usage: muse plugins reject <plugin-id[[:kind]:capability-id] | stable-id> [--json]

approve records that you trust the current definition of the selected capabilities and enables them; reject records the same hash and disables them. Either way the decision is bound to definition_hash, which includes the package digest, so any change to the package returns the capability to modified. Decisions apply to new sessions. Skills and commands never need review.

Terminal window
$ muse plugins approve weather
approve plugin:weather:hook:log-tool-use
$ muse plugins reject weather
reject plugin:weather:hook:log-tool-use

One line per capability: the verb and the stable id (agent definitions print <scoped-id> (ordinal <n>)).

Terminal window
$ muse plugins approve plugin:weather:hook:log-tool-use --json
{
"decision": "approve",
"runtime_capabilities": [
{
"stable_id": "plugin:weather:hook:log-tool-use",
"trusted_definition_hash": "sha256:9a35bebf76782df57992d18e4f653c6e38ccbd3fd3d7121517b1e1bb6b958a2a",
"enabled": true
}
]
}

decision is approve or reject. Each runtime_capabilities element has stable_id, trusted_definition_hash and enabled; an agent definition element instead has kind: "agent_definition", plugin_id, scoped_definition_id, original_ordinal and enabled.

approve is allowed when the status is review_needed, trusted_enabled, trusted_disabled or modified. reject is additionally allowed on blocked entries. Anything else fails with runtime-capability-not-reviewable.

Selector Matches
<plugin-id> Every review-gated capability of that plugin
<plugin-id>:<capability-id> Capabilities with that id in any kind; fails as ambiguous if more than one kind matches
<plugin-id>:<kind>:<capability-id> Exactly one capability
plugin:<plugin-id>:<kind>:<capability-id> The stable id as printed by inspect; the plugin: prefix is recognised only when at least three segments follow it
<plugin-id>:agent_definition:<ordinal> An agent definition by the ordinal inspect prints

Kinds: hook, reminder, mcp_server, agent_definition and invocation_preapproval. The parser accepts the last one, but the current release lists no reviewable capability of that kind (a Claude Code allowed-tools declaration is inventoried as unsupported instead), so in practice you spell one of the first four.

Notable errors:

Message Exit --json code
no runtime capabilities match `weather:bogus` 1 runtime-capability-not-found
plugin `nope` is not installed 1 unknown-plugin
unknown runtime capability kind `foo`; expected one of `hook`, `reminder`, `mcp_server`, `agent_definition`, `invocation_preapproval` 1 none (printed on stderr even with --json)
runtime capability selector `<sel>` is ambiguous; qualify by kind, e.g. `<plugin>:<kind>:<cap>` 1 runtime-capability-ambiguous
cannot approve non-reviewable runtime capabilities: <stable-id> (<status>) 1 runtime-capability-not-reviewable
cached plugin `x` is invalid: <reason>; run `muse plugins inspect x` for details 1 plugin-cache-invalid
settings are busy; retry runtime capability review 1 runtime-capability-trust-write-failed

If the capability changed between selection and the write, nothing is written and the command fails with runtime-capability-not-found.

usage: muse plugins hook test <plugin-id>:<hook-id> | plugin:<plugin-id>:hook:<hook-id> --fixture <path> [--json]

Runs one hook of an installed, enabled plugin against a fixture and reports what the hook returned. The hook does not need to be approved first, and the run does not record a decision. The hook process gets the same environment as in a session, including MUSE_PLUGIN_ROOT and MUSE_PLUGIN_DATA_DIR, so a hook that writes files will write them.

The fixture is a JSON file:

Member Required Meaning
event yes The event the manifest declares for this hook, as PostToolUse or post_tool_use; any other event is rejected
stdin yes The JSON object the hook reads on stdin; see Hook events and payloads for each event’s keys
matcher_input no The string the hook’s matcher is tested against
cwd no Working directory for the hook process; defaults to your current directory
{
"event": "PostToolUse",
"stdin": {
"hook_event_name": "PostToolUse",
"tool_name": "read_file",
"tool_input": { "path": "README.md" },
"tool_response": { "ok": true }
}
}
Terminal window
$ muse plugins hook test weather:log-tool-use --fixture fixture.json
hook-test weather:log-tool-use status=completed

status is the first handler’s terminal status (completed, failed, and so on). A hook that returns malformed output is a failed status, not a command failure.

With --json, the output is the full run document:

{
"decision": {
"should_block": false,
"block_reason": null,
"additional_contexts": [],
"updated_input": null,
"permission_decision": null,
"feedback_message": null,
"should_stop": false,
"stop_reason": null
},
"terminals": [
{
"run_id": "plugin:weather:log-tool-use:1",
"hook_key": "plugin:weather:log-tool-use",
"event": "post_tool_use",
"status_message": "Logging tool use",
"system_message": null,
"status": "completed",
"duration_ms": 343,
"exit_code": 0,
"effects": [],
"stdout": "",
"stderr": "",
"error": null
}
],
"records": 2
}

decision is the aggregate effect Muse Code would apply (should_block, block_reason, additional_contexts, updated_input, permission_decision, feedback_message, should_stop, stop_reason). terminals has one entry per handler run with status, exit_code, duration_ms, stdout, stderr, effects and error.

Notable errors:

Message Exit --json code
plugins hook test requires --fixture <path> 2 usage error
missing plugins hook test selector 2 usage error
plugins hook test selector `weather:mcp_server:x` has capability kind `mcp_server`; expected `hook` 2 usage error
plugin hook `weather:nope` is not installed and enabled 1 plugin-hook-test-failed
fixture event must be `PostToolUse` or `post_tool_use` (wording varies with the event) 1 plugin-hook-test-failed
fixture must contain `stdin` 1 plugin-hook-test-failed

muse plugins hook with anything other than test prints unsupported plugins hook command `<word>` (exit 2).

usage: muse plugins enable <id> [--json]
usage: muse plugins disable <id> [--json]

disable stops the plugin from loading in new sessions and touches nothing else. enable re-checks the cached package against its recorded digests, then turns the plugin back on. Review decisions survive both.

Terminal window
$ muse plugins disable weather
disable weather enabled=false trust=user-local
$ muse plugins enable weather
enable weather enabled=true trust=user-local

With --json, the document is {"disable": <record>} or {"enable": <record>}:

{
"disable": {
"id": "weather",
"enabled": false,
"trust": "user-local"
// remaining installed record fields
}
}

Unknown id: plugin `nope` is not installed (exit 1, unknown-plugin).

usage: muse plugins update <id> [--json]

Re-reads the plugin from the recorded source.path (the directory you installed from, or the marketplace copy), revalidates it and replaces the cached package. enabled and provenance are kept. If the new package differs, every approved capability shows as modified until you approve it again. A source manifest that now declares a different name is refused.

Terminal window
$ muse plugins update weather
updated weather sha256:b0cf4aec… trust=user-local previous=sha256:b0cf4aec…
warning third-party plugin: hooks require review before activation; skills and commands are active without review while the plugin is enabled

The line carries the new manifest_sha256 and the previous one.

{
"updated": { /* installed record */ },
"warning": "third-party plugin: hooks require review before activation; skills and commands are active without review while the plugin is enabled",
"diagnostics": [],
"plugin": { /* descriptor */ },
"previous_manifest_sha256": "sha256:b0cf4aec5eb6cef64aae6e93804589aa574704b638ea53922dc6f329ccdf7b78",
"lockfile_path": "<data dir>/plugins/installed.json"
}

When the source directory is gone, the command fails and the previous record is kept:

Terminal window
$ muse plugins update weather --json
{
"error": {
"code": "plugin-source-unavailable",
"message": "plugin `weather` source `<absolute path to weather>` is no longer available; run `muse plugins remove weather`, then reinstall the plugin from an available source"
}
}

For a plugin installed from a marketplace the message names muse plugins install <id>@<marketplace> instead. After muse plugins marketplace update <name>, muse plugins update for a plugin from that marketplace can report its source unavailable; remove the plugin and reinstall it with muse plugins install <plugin>@<name>.

usage: muse plugins remove <id> [--delete-data] [--json]

Deletes the installed record and the cached package, and forgets every review decision for that plugin, so a reinstall starts at review_needed. The plugin’s data directory (MUSE_PLUGIN_DATA_DIR) is kept unless you pass --delete-data.

Terminal window
$ muse plugins remove weather
removed weather
Terminal window
$ muse plugins remove weather --delete-data --json
{
"removed": "weather",
"cache_path": "<data dir>/plugins/cache/local/weather/bacc26ed…/package",
"data_path": "<data dir>/plugins/data/weather",
"warning": null,
"lockfile_path": "<data dir>/plugins/installed.json"
}

data_path is null without --delete-data. If the record was removed but a directory could not be deleted, the command still succeeds and warning (or a warning line) names the directory that may remain.

Unknown id: plugin `nope` is not installed (exit 1, unknown-plugin). A failure while updating settings or the store reports plugin-remove-failed.

usage: muse plugins marketplace <command>
Commands:
add <name> <source> [--json] Add a local file/directory or Git marketplace source and store a snapshot
list [--json] List configured marketplaces
update <name> [--json] Refresh a marketplace snapshot explicitly
remove <name> [--json] Remove a marketplace source and snapshot

A marketplace is a catalog file plus the plugin directories it points to. add reads the catalog once and stores an offline snapshot; list --available and install <plugin>@<name> read that snapshot and never fetch. update takes a fresh snapshot. Names follow plugin id rules. muse plugins marketplace with no subcommand prints missing plugins marketplace command (exit 2).

<source> How it is read Recorded source.kind
An existing directory The catalog is looked for inside it local-dir
An existing marketplace.json file Loaded directly local-file
git@host:path, ssh://, git://, file://, http://, https://, or anything ending in .git Cloned, then the catalog is looked for in the checkout git
owner/repo (GitHub shorthand; letters, digits, -, _, and . in the repo name) Expanded to https://github.com/owner/repo.git and cloned git

Any git form may end in #<ref> to pin a branch or tag. A path that exists on disk wins over the git interpretation unless it ends in .git.

Inside a directory or checkout the catalog is probed in this order: marketplace.json, .agents/plugins/marketplace.json, .claude-plugin/marketplace.json. A source with none of them fails with a message naming all three.

Terminal window
$ muse plugins marketplace add local ./market
local plugins=1 source=<absolute path to market>

The line is the name, the number of catalog entries kept, and the resolved source. Entries that were dropped are reported on stderr as warning: marketplace plugin `<name>` skipped: <reason> followed by warning: marketplace snapshot plugins=<n> skipped=<m>.

With --json (update returns the identical shape; the document below came from update, which writes each new snapshot into a generations/ subdirectory, whereas the first add writes snapshot.json directly under the marketplace directory):

{
"marketplace": {
"name": "local",
"source": {
"kind": "local-dir",
"path": "<absolute path to market>"
},
"plugin_count": 1,
"skipped": [],
"snapshot_path": "<data dir>/plugins/marketplaces/local/generations/1789619275399478000/snapshot.json",
"last_updated_at": "2026-09-17T04:27:55.47694Z",
"fetched": true
}
}

skipped elements have name and reason. Reserved names are refused with marketplace `<name>` is reserved and cannot be added (exit 1). add with fewer than two positionals prints the usage line (exit 2).

Terminal window
$ muse plugins marketplace list
local plugins=1 source=<absolute path to market>

Prints no marketplaces when none is configured. A marketplace that has no snapshot yet carries a trailing not fetched. With --json:

{
"marketplaces": [ { /* marketplace record, as in add */ } ],
"warnings": []
}

muse plugins marketplace update <name> re-reads the source and replaces the snapshot; a failed update keeps the previous snapshot. Output is the same line and --json shape as add. Unknown name: marketplace `nope` is not configured (exit 1, unknown-marketplace).

Terminal window
$ muse plugins marketplace remove local
removed local

With --json, {"removed": "<name>", "snapshot_path": "<path>"}. Plugins already installed from that marketplace stay installed.

Codes that appear in error.code with --json. Without --json the same message is printed on stderr with exit code 1.

Code Raised by Meaning
invalid-plugin-package validate, install, update, marketplace add The package or catalog failed validation; details carries the report when there is one
incompatible-plugin-package install, update A foreign-format package cannot be imported
unknown-plugin inspect, approve, reject, enable, disable, update, remove No installed plugin with that id
unknown-marketplace install <plugin>@<name>, marketplace update, marketplace remove No configured marketplace with that name
plugin-source-unavailable update The recorded source path no longer exists
plugin-store-read-failed any A path (including an install target) could not be read
plugin-store-write-failed any mutation The store could not be written
plugin-store-format-invalid any The store file is not in a format this build understands
plugin-cache-invalid approve, reject, enable The cached package no longer matches its recorded digests
plugin-remove-failed remove The settings prune or store removal failed
plugin-hook-test-failed hook test The hook was not found or the fixture was unusable
runtime-capability-not-found approve, reject The selector matched nothing, or the match changed before it was written
runtime-capability-ambiguous approve, reject A two-segment selector matched more than one kind
runtime-capability-not-reviewable approve, reject The current status does not allow that decision
runtime-capability-trust-write-failed approve, reject Settings were locked or could not be written
runtime-capability-review-failed inspect, approve, reject The capability snapshot could not be built

Validation diagnostic codes such as invalid-plugin-id can also appear as error.code from validate and install; they are listed in Validation diagnostics.

Two variables change where the command reads and writes.

Variable Effect Default
XDG_DATA_HOME The plugin store lives at $XDG_DATA_HOME/muse/plugins ~/.local/share/muse/plugins
XDG_CONFIG_HOME Review decisions are written to $XDG_CONFIG_HOME/muse/settings.json ~/.config/muse/settings.json
Path (under the data directory) Contents
plugins/installed.json The installed records; lockfile_path in --json output
plugins/cache/local/<id>/<package-digest>/package The immutable installed copy (cache_path, MUSE_PLUGIN_ROOT)
plugins/data/<id> The plugin’s writable directory (MUSE_PLUGIN_DATA_DIR); created by the plugin, deleted only by remove --delete-data
plugins/marketplaces.json and plugins/marketplaces/<name>/ Marketplace registry and snapshots

Review decisions live in settings.json under runtime_capabilities, keyed by stable id, each with enabled and trusted_definition_hash. Every store mutation takes a lock, so two muse plugins commands cannot corrupt each other. Trust, review and scopes explains how these files relate to what a session loads; Marketplaces and updates covers the marketplace files.