Skip to main content

Documentation 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.

A Mux Extension is an npm package whose 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 the contributes block (see the manifest reference below).

1. Lay out the package

my-extension/
├── package.json   # npm manifest + Extension Manifest under "mux"
├── SKILL.md       # body of the contributed skill
└── README.md      # optional but recommended
The package can live anywhere — bundled (inside 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

{
  "name": "@publisher/extension-name",
  "version": "0.1.0",
  "description": "One-sentence description of what this Extension contributes.",
  "license": "MIT",
  "files": ["SKILL.md", "README.md"],
  "mux": {
    "manifestVersion": 1,
    "id": "publisher.extensionName",
    "displayName": "Extension Display Name",
    "description": "User-facing description shown on the Extension Card.",
    "publisher": "publisher",
    "homepage": "https://example.com/extension",
    "contributes": {
      "skills": [
        {
          "id": "my-skill",
          "displayName": "My Skill",
          "description": "What this skill helps the agent do.",
          "body": "SKILL.md",
          "advertise": true
        }
      ]
    }
  }
}
Key constraints — all of which are enforced by the Manifest Validator and surface as diagnostics on the Extension Card:
  • mux.id must match the Extension Identity regex ^[a-z0-9]+(?:\.[a-z0-9][a-z0-9-]*)+$ and must not start with mux or mux.. The mux.* prefix is reserved for bundled Extensions; non-bundled manifests claiming it are rejected with the extension.identity.reserved diagnostic.
  • mux.contributes is a closed shape. Unknown top-level keys are rejected with manifest.contributes.unknown_key. Adding a new contribution type is a Mux-side decision, not an opt-in escape hatch.
  • mux.manifestVersion must be the literal 1. Unknown values are rejected with manifest.version.unsupported.
Optional manifest fields not listed in the schema are tolerated with an info-severity diagnostic (e.g., the legacy icon field is ignored, not rejected).

3. Write the skill body

# my-skill

A short title and a few paragraphs of guidance. Body files are read
during Activation Discovery only when the Extension is trusted,
enabled, and granted, so it's safe to ship private prose here without
worrying about untrusted reads.
The 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:
cd <project>/.mux/extensions
bun add file:../path/to/my-extension
For shared use across projects:
cd ~/.mux/extensions
bun add file:/abs/path/to/my-extension
# or, if published to npm:
bun add @publisher/extension-name
Then run Reload Extensions from the command palette. The new Extension appears in Settings → Extensions under the matching root.

5. Trust, then approve

Project-local roots are existence-checked before trust, but Mux does not read their package.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 discriminator manifestVersion is frozen at 1; new contribution types and descriptor fields evolve via per-contribution descriptor versions instead of bumping the envelope.

Envelope

FieldTypeRequiredNotes
manifestVersion1yesFrozen at 1 for the v1 platform.
idstringyesExtension Identity regex ^[a-z0-9]+(?:\.[a-z0-9][a-z0-9-]*)+$. mux.* reserved for bundled.
contributesobjectyesClosed shape. Unknown keys rejected.
displayNamestringnoFalls back to package.json#name on the Extension Card.
descriptionstringnoFalls back to package.json#description.
publisherstringnoFree-form. Used for grouping in the Extensions section.
homepagestringnoRendered as a link in the Identity block.
requestedPermissionsstring[] (operational permission ids)noListed alongside Inferred Registration Permissions in the Permissions block.
Unknown optional fields produce an info-severity diagnostic; they do not invalidate the manifest.

Permissions

Two permission categories appear together in the Permissions block:
  • Inferred Registration Permissions are derived from the declared contribution types (e.g., declaring a skills entry implies skill.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.
Effective Permissions = 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 (currently skills and agents; the others are descriptor-only in v1 but share the same descriptor envelope).
KeyDescriptorNotes
skillsid, body, displayName?, description?, advertise?body is a relative path to a Markdown file inside the package.
agentsid, body, displayName?, description?Same shape as skills.
themesid, displayName?, tokenstokens is a curated CSS-variable map; passthrough not allowed.
layoutsid, displayName?, presetpreset matches the LayoutPreset schema.
runtimePresetsid, displayName?, runtimeruntime matches RuntimeConfig.
commandsid, 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 bumping descriptorVersion. Authors who declare them must accept that risk.
  • runtimeDrivers
  • tools
  • mcpServers
  • panels
  • agentLifecycleHooks
  • secretProviders
Each takes the shape { id, displayName?, description? }.

Descriptor versions

Every contribution descriptor carries a descriptorVersion (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 by skills 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
Allow-missing-leaf semantics apply — declaring a body that does not exist on disk surfaces a diagnostic rather than crashing discovery.

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 a package-renamed drift 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. The extensionId 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