Skip to content
Developer Preview

Marketplaces and updates

After reading this page you can publish a small catalog of plugins, add it to Muse Code as a marketplace, install a plugin from it by name, and know what muse plugins update and muse plugins remove do to a plugin that came from a local path or from a marketplace. Every output below was produced by Muse Code 1.3.0 against the weather plugin in an empty plugin store. The plugin surface is part of the Developer Preview and may change.

A marketplace is a named catalog of plugin packages. You add it once with a source; Muse Code reads the catalog, copies what it needs, and stores a snapshot under your data directory. From then on muse plugins list --available and muse plugins install <plugin>@<name> read that snapshot and never touch the network. Refreshing is a separate, explicit command.

There is no public catalog to browse yet. A marketplace is something you or your team publish, and the rest of this page shows how.

Terminal window
muse plugins marketplace add <name> <source>

<name> follows the plugin id grammar: lowercase letters, digits, ., _ and -, starting with a letter or digit. A small set of names is reserved for Muse Code’s own use; adding one fails with a message that the name is reserved and cannot be added. Pick a name that describes your team or project.

The source is a marketplace.json file (package paths resolve relative to it), a directory that holds a catalog, or a git repository given as a URL (https://…/plugins.git, git@host:team/plugins.git, ssh://…, file:///path/to/repo) or as the GitHub shorthand owner/repo. Any git source may end in #ref to pin a branch, a tag or a commit, and clones time out after 60 seconds. A path that exists on disk is treated as local unless it ends in .git; anything else is treated as a git source. The muse plugins command lists every accepted form and the source kind each one records.

In a directory or a checkout, Muse Code looks for the catalog at three locations, in this order, and uses the first one it finds:

  1. marketplace.json (the native format described below)
  2. .agents/plugins/marketplace.json (a Codex catalog)
  3. .claude-plugin/marketplace.json (a Claude Code catalog)

Codex and Claude Code catalogs are translated into the native shape when the snapshot is taken. Entries that point at other repositories are only materialized when the marketplace itself was added from git, and entry types Muse Code cannot fetch are skipped with a reason. Compatibility with other plugin formats says what happens to the packages themselves.

A directory with none of the three fails and names all of them:

Terminal window
muse plugins marketplace add empty ./empty-dir
failed to read plugin store `<empty-dir>/marketplace.json`: no marketplace catalog found; probed `marketplace.json`, `.agents/plugins/marketplace.json`, `.claude-plugin/marketplace.json`

This catalog publishes one plugin. The directory that holds it has the weather plugin at plugins/weather, next to the catalog file:

team-marketplace/
├── marketplace.json
└── plugins/
└── weather/
├── .muse-plugin/plugin.json
├── skills/forecast/SKILL.md
├── commands/forecast-brief.md
└── hooks/log-tool-use.sh
team-marketplace/marketplace.json
{
"schemaVersion": 1,
"source": "local",
"plugins": [
{
"name": "weather",
"version": "0.1.0",
"install": {
"transport": "local-path",
"source": "plugins/weather"
},
"integrity": {
"digest": "sha256:bacc26ede05bf8aa08c888ddacf24540f757fb51f5248927df265bdcd41ea62c"
},
"availability": {
"status": "available"
}
}
]
}
Field Value
schemaVersion The integer 1.
source The string "local".
plugins[].name The plugin id. It must equal the name in the package’s own manifest.
plugins[].version A label shown in listings. Muse Code never compares versions.
plugins[].install.transport The string "local-path"; it is the only transport a snapshot supports.
plugins[].install.source The package directory, relative to the catalog file (an absolute path also works).
plugins[].integrity.digest sha256: followed by 64 hex digits: the SHA-256 of the package tree.
plugins[].availability.status available, deprecated or blocked. Only available entries install.

To get the digest, install the package once from its directory with muse plugins install <dir> --json and copy package_sha256; the digest covers every file in the package except .git, .hg and .svn directories, so it is the same on every machine that holds the same files. An entry with a missing or malformed field is skipped with a warning, and a catalog with no usable entry fails to add.

Adding the directory and reading the snapshot back:

Terminal window
muse plugins marketplace add team ./team-marketplace
muse plugins marketplace list
muse plugins list --available
team plugins=1 source=<absolute path to team-marketplace>
team plugins=1 source=<absolute path to team-marketplace>
weather@team 0.1.0 status=available transport=local-path

With --json, marketplace add reports the source kind, the counts and the snapshot location:

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

Adding the same directory from a git checkout instead (a file:// URL to a repository that holds the same files) records source=file:///… and stores the checkout with the snapshot; the rest of the flow is identical.

Terminal window
muse plugins install weather@team
installed weather 0.1.0 marketplace=team 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

A target is read as <plugin>@<marketplace> when it contains @, does not exist on disk, and does not look like a path. Before anything is copied, Muse Code checks the entry in the snapshot:

Check On failure
The marketplace is configured marketplace `nowhere` is not configured
The entry exists plugin `nothing` is not available in marketplace `team`
The entry’s status is available plugin `weather` in marketplace `team` is deprecated
The package tree’s digest equals integrity.digest plugin `weather` in marketplace `team` failed integrity check
The package validates The same diagnostics muse plugins validate would print
The manifest name equals the catalog name marketplace plugin `weather-renamed` resolves to a bundle whose manifest id `weather` does not match
The catalog version equals the manifest version A warning only; the install proceeds

Each message in the table was produced by a real failed install; the integrity one came from a catalog whose package had been edited after its digest was recorded, and the name one from an entry called weather-renamed that pointed at the weather package. The version check only warns. This is the receipt from a catalog that said 0.2.0 for a package whose manifest says 0.1.0:

warning third-party plugin: hooks require review before activation; skills and commands are active without review while the plugin is enabled; marketplace plugin `weather` catalog version `0.2.0` differs from manifest version `0.1.0`

The digest is the integrity mechanism; the version is a label. There is no version comparison, no downgrade protection and no pinning beyond a git #ref on the marketplace source and the digest in the snapshot.

After the checks the install is the same as a local one: the package is copied into your cache, recorded as enabled with trust=user-local, its skills and commands work at once, and its hooks, MCP servers, reminders and agent definitions wait at review_needed until you approve them. Trust, review and scopes covers that step. Marketplace installs are always user scope; --scope project is refused for them. The muse plugins command lists every flag install accepts and the exact lines it prints.

Terminal window
muse plugins marketplace update team
team plugins=1 source=<absolute path to team-marketplace>

update re-reads the source (for git, a fresh clone), builds a new snapshot and swaps it in; a failed refresh keeps the previous snapshot. Installed plugins are not touched by a marketplace refresh. For a marketplace added from git, muse plugins update does not follow the new snapshot; to move an installed plugin to what the refreshed catalog offers, remove it and install it again from the marketplace (your approvals are forgotten and must be given again). For a marketplace added from a local directory or file, the plugin’s recorded source is your directory itself, so muse plugins update <plugin-id> picks up changes without a refresh.

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

update <plugin-id> re-reads the plugin from the source recorded at install and replaces the cached copy. It keeps the plugin’s enabled state and provenance, prints the manifest digest before and after, and leaves the previous record in place if anything fails.

Installed from What update re-reads
A local path That directory, as it is now. This is the development loop: edit in place, run update.
A marketplace added from a local directory or file The package directory the catalog points at, as it is now. Refreshing the marketplace is not needed to pick up a changed package.
A marketplace added from git The checkout that was current when you installed. update never follows a refreshed snapshot; after a muse plugins marketplace update that checkout is superseded and deleted at the next marketplace change, and update then fails with plugin-source-unavailable. To move to what the refreshed catalog offers, run muse plugins remove <plugin-id>, then muse plugins install <plugin>@<name>, then approve its runtime capabilities again.

If the recorded source is gone, update fails closed and tells you the way out. This is a local install whose directory was deleted:

plugin `weather` source `<path>` is no longer available; run `muse plugins remove weather`, then reinstall the plugin from an available source

With --json the error code is plugin-source-unavailable. After a marketplace update, plugins update for a plugin installed from a git marketplace reports its source unavailable in the same way once the old checkout is gone; remove the plugin and reinstall it with muse plugins install <plugin>@<name>. For a marketplace added from git, the copy a plugin was installed from lives with the snapshot, so marketplace remove ends that plugin’s update path too; for a marketplace added from a local directory or file, the recorded source is your directory itself.

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"
}

remove <plugin-id> deletes the installed record and the cached package and forgets every review decision for the plugin. Without --delete-data the plugin’s data directory (MUSE_PLUGIN_DATA_DIR, where a hook may have written files) stays behind and a later reinstall finds it again; with the flag it is deleted too and data_path names it. A cleanup problem is reported in warning while the removal still succeeds.

Terminal window
muse plugins marketplace remove team
removed team

marketplace remove <name> deletes the marketplace record and its snapshot. Plugins you installed from it stay installed and keep working; only their update path is gone, as described above.