A Mux Extension is an npm package whoseDocumentation Index
Fetch the complete documentation index at: https://mux-extensions-main.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
package.json carries a
mux field — the Extension Manifest. The manifest declares an
Extension Identity, a contributes map, and optional metadata.
Extensions never execute imperative bootstrap code at install time;
the v1 manifest is purely declarative.
The bundled
@coder/mux-extension-platform-demo
package is the canonical reference implementation. This page mirrors
its layout step-by-step, then catalogs every field the Manifest
Validator accepts.
Quickstart: a single-skill Extension
This walkthrough produces an Extension with one advertised skill, the same shape as the Demo Extension. Adapt it to other contribution types by swapping thecontributes block (see the
manifest reference below).
1. Lay out the package
packages/ in the Mux
repo), user-global (~/.mux/extensions/node_modules/<package>), or
project-local (<project>/.mux/extensions/node_modules/<package>). The
manifest itself is identical across roots; trust and grant decisions
happen at install time, not in the manifest.
2. Write package.json
mux.idmust match the Extension Identity regex^[a-z0-9]+(?:\.[a-z0-9][a-z0-9-]*)+$and must not start withmuxormux.. Themux.*prefix is reserved for bundled Extensions; non-bundled manifests claiming it are rejected with theextension.identity.reserveddiagnostic.mux.contributesis a closed shape. Unknown top-level keys are rejected withmanifest.contributes.unknown_key. Adding a new contribution type is a Mux-side decision, not an opt-in escape hatch.mux.manifestVersionmust be the literal1. Unknown values are rejected withmanifest.version.unsupported.
icon field is ignored,
not rejected).
3. Write the skill body
body field is a relative path inside the package. Absolute
paths, traversal segments (..), and any path whose realpath crosses
a symbolic link are rejected by Path Containment.
4. Install and reload
For local development against a project:5. Trust, then approve
Project-local roots are existence-checked before trust, but Mux does not read theirpackage.json or show Extension cards until the root is
trusted. For project-local installs, first click Trust this root in
Settings → Extensions. After the root reloads, the Extension cards
appear and Quick setup applies enable + grant. Review
individually falls through to the granular ladder if you want to
step through each decision separately.
Bundled and user-global Extensions skip the trust step (those roots are
always trusted) but still go through enable + grant.
Manifest reference
The fields below are the complete v1 envelope. The discriminatormanifestVersion is frozen at 1; new contribution types and
descriptor fields evolve via per-contribution
descriptor versions instead of bumping the
envelope.
Envelope
| Field | Type | Required | Notes |
|---|---|---|---|
manifestVersion | 1 | yes | Frozen at 1 for the v1 platform. |
id | string | yes | Extension Identity regex ^[a-z0-9]+(?:\.[a-z0-9][a-z0-9-]*)+$. mux.* reserved for bundled. |
contributes | object | yes | Closed shape. Unknown keys rejected. |
displayName | string | no | Falls back to package.json#name on the Extension Card. |
description | string | no | Falls back to package.json#description. |
publisher | string | no | Free-form. Used for grouping in the Extensions section. |
homepage | string | no | Rendered as a link in the Identity block. |
requestedPermissions | string[] (operational permission ids) | no | Listed alongside Inferred Registration Permissions in the Permissions block. |
Permissions
Two permission categories appear together in the Permissions block:- Inferred Registration Permissions are derived from the
declared contribution types (e.g., declaring a
skillsentry impliesskill.register). Authors do not list these explicitly — the Manifest Validator materializes them. - Operational Permissions are listed in
requestedPermissions. Use them to declare runtime needs that aren’t implied by a contribution type.
requested ∩ granted. New permissions
introduced by an update never auto-grant; they surface as
Pending re-grant on the card. See
Drift
for the user-facing flow.
Available contribution types
These types reach Available Contribution Support Level in v1 — they are wired to capability consumers end-to-end (currentlyskills and agents; the others are descriptor-only in v1 but
share the same descriptor envelope).
| Key | Descriptor | Notes |
|---|---|---|
skills | id, body, displayName?, description?, advertise? | body is a relative path to a Markdown file inside the package. |
agents | id, body, displayName?, description? | Same shape as skills. |
themes | id, displayName?, tokens | tokens is a curated CSS-variable map; passthrough not allowed. |
layouts | id, displayName?, preset | preset matches the LayoutPreset schema. |
runtimePresets | id, displayName?, runtime | runtime matches RuntimeConfig. |
commands | id, target, title, description? | target references a Mux-owned Command Target id (mux.<area>.<verb>). |
Provisional descriptor types (inspection-only in v1)
Listed here for completeness; these contribution types are visible in the Extensions section but are not yet wired to runtime capability consumers. Their schemas may evolve in breaking ways without bumpingdescriptorVersion. Authors who declare them must accept
that risk.
runtimeDriverstoolsmcpServerspanelsagentLifecycleHookssecretProviders
{ id, displayName?, description? }.
Descriptor versions
Every contribution descriptor carries adescriptorVersion (default
1). Adding a new optional field stays at descriptorVersion: 1 and
emits an info-severity diagnostic if older Mux versions encounter it.
Breaking changes bump descriptorVersion; an unknown
descriptorVersion on a single contribution invalidates only that
contribution, not the whole Extension.
This per-contribution versioning is intentional: it lets one
contribution type evolve under its own descriptorVersion without
forcing a global manifestVersion bump that would invalidate every
existing manifest.
Path containment
Body files referenced byskills and agents are validated against
the package’s realpath. The Manifest Validator rejects:
- absolute paths (
/foo,C:\foo) - traversal segments (
..anywhere in the path) - any segment whose realpath crosses a symbolic link
Identity vs distribution
- The Extension Identity (
mux.id) is the stable identifier across versions and is what Grant Records key off. - The Distribution Identity is
<package.json#name>@<version>and is what users see on the card. Renaming the npm package surfaces as apackage-renameddrift status without revoking grants on the Extension Identity.
Roots and lookup
Mux discovers Extensions from up to three roots, in this precedence order during conflict resolution:Core bundled Extensions cannot be shadowed; non-core bundled
Extensions can be overridden by user-global or project-local
Extensions claiming the same identity. Ties at the same precedence
level drop all conflicting candidates so neither side silently
shadows the other; the Extension Card surfaces the conflict
diagnostic.
Privacy
Telemetry never emits third-party Extension or contribution identifiers. TheextensionId and contributionId fields are gated
by two independent checks (the value matches the reserved prefix
and the source root is bundled). See
Extension Telemetry for the full v1 events
catalog and gate rules.
Where to go next
- The Demo Extension source:
packages/mux-extension-platform-demo/. - The release checklist: Release Checklist.
- Contribution support levels and ADRs: ADR-0002 — stable v1 excludes code execution surfaces, ADR-0003 — Extension Identity vs Distribution Identity, ADR-0004 — v1 is an additive platform, ADR-0005 — v1 platform security boundaries.