Apus can install plugins from four external ecosystems: the vendor-neutral Agent Plugins standard, plus Codex, Claude, and Cursor. These are called bundles - content and metadata packs that Apus maps into native features like skills, hooks, and MCP tools.
Bundles are not the same as native Apus plugins. Native plugins run in-process and can register any capability. Bundles are content packs with selective feature mapping and a narrower trust boundary.
Why bundles exist
Many useful plugins are published in the Agent Plugins, Codex, Claude, or Cursor format. Instead of requiring authors to rewrite them as native Apus plugins, Apus detects these formats and maps their supported content into the native feature set. You can install an Agent Plugins package, a Claude command pack, or a Codex skill bundle and use it immediately.
Install a bundle
Install from a directory, archive, or marketplace
```bash
# Local directory
apus plugins install ./my-bundle
# Archive
apus plugins install ./my-bundle.tgz
# Claude marketplace
apus plugins marketplace list <source>
apus plugins install <plugin> --marketplace <source>
```
`<source>` is a local marketplace path/repo or a git/GitHub source.
Verify detection
```bash
apus plugins list
apus plugins inspect <id>
```
Bundles show `Format: bundle` plus a `Bundle format:` value of
`agent (Agent Plugins)`, `codex`, `claude`, or `cursor`.
Use the bundle
<a id="restart-and-use" />
Installation applies to the running local Gateway without restarting it.
Start the Gateway if it was stopped. See
[Apply changes and inspect](/plugins/manage-plugins#apply-changes-and-inspect).
Mapped features (skills, hooks, MCP tools, LSP defaults) are available in the next session.
What Apus maps from bundles
Not every bundle feature runs in Apus. Here is what works and what is detected but not wired.
Supported now
| Feature | How it maps | Applies to |
|---|---|---|
| Skill content | Bundle skill roots load as normal Apus skills | All formats |
| Commands | commands/ and .cursor/commands/ treated as skill roots |
Claude, Cursor |
| Agents and output styles | Claude agents/ and output-styles/ treated as skill roots |
Claude |
| Hook packs | Apus-style HOOK.md + handler.ts layouts |
Claude, Codex |
| MCP tools | Bundle MCP config merged into embedded Apus settings; supported stdio and HTTP servers loaded | All formats |
| Env contract | PLUGIN_ROOT and PLUGIN_DATA env vars plus placeholder expansion for stdio MCP servers |
Agent Plugins |
| LSP servers | Claude .lsp.json and manifest-declared lspServers merged into embedded Apus LSP defaults |
Claude |
| Settings | Claude settings.json imported as embedded Apus defaults |
Claude |
Skill content
- Bundle skill roots load as normal Apus skill roots.
- Claude
commands/,agents/, andoutput-styles/roots are treated as additional skill roots. - Cursor
.cursor/commands/roots are treated as additional skill roots.
Claude markdown command files and Cursor command markdown both work through the normal Apus skill loader.
Hook packs
Bundle hook roots are collection directories. Put each hook's HOOK.md and
handler.ts or handler.js in its own child directory, such as hooks/my-hook/,
and declare hooks/ as the root. Declaring the hook's leaf directory directly does
not load it.
Plugin inspection lists these hook packs separately from detected JSON automation.
Claude hooks/hooks.json remains in the declared capabilities, but does not appear
as a supported hook. A bundle containing both layouts keeps its Apus hook packs.
Inspection does not execute handlers or prove that the running Gateway loaded them.
Embedded Apus settings
Claude settings.json is imported as default embedded Apus settings when
the bundle is enabled. Apus sanitizes shell override keys before applying
them:
shellPathshellCommandPrefix
Embedded Apus LSP
- Enabled Claude bundles can contribute LSP server config.
- Apus loads
.lsp.jsonplus any manifest-declaredlspServerspaths. - Bundle LSP config is merged into the effective embedded Apus LSP defaults.
- Runtime tool allowlists can select bundle LSP tools with
bundle-lsp,group:plugins, or matchinglsp_*names and globs. Each independent restriction must permit the tool. - Only supported stdio-backed LSP servers are runnable; unsupported
transports still show up in
apus plugins inspect <id>. - Canceling a turn or compaction cancels pending LSP startup, stops additional servers from starting, and cleans up servers already acquired by that operation.
Detected but not executed
These are recognized and shown in diagnostics, but Apus does not run them:
- Claude
hooks/hooks.jsonautomation - Cursor
.cursor/agents,.cursor/hooks.json,.cursor/rules - Codex
.app.jsonmetadata beyond capability reporting
MCP for embedded Apus
- Enabled bundles can contribute MCP server config.
- Stdio commands default their working directory to the plugin config directory. Remote HTTP servers do not receive an implicit working directory.
- Apus merges bundle MCP config into the effective embedded Apus
settings as
mcpServers. - Apus exposes supported bundle MCP tools during embedded Apus agent turns by launching stdio servers or connecting to HTTP servers.
- The
codingandmessagingtool profiles include bundle MCP tools by default; usetools.deny: ["bundle-mcp"]to opt out for an agent or gateway. - Project-local embedded agent settings still apply after bundle defaults, so workspace settings can override bundle MCP entries when needed.
- Bundle MCP tool catalogs are sorted deterministically before registration, so
upstream
listTools()order changes do not thrash prompt-cache tool blocks.
Transports
MCP servers can use stdio or HTTP transport.
Stdio launches a child process:
{
"mcp": {
"servers": {
"my-server": {
"command": "node",
"args": ["server.js"],
"env": { "PORT": "3000" }
}
}
}
}
HTTP connects to a running MCP server, defaulting to sse unless
streamable-http is requested:
{
"mcp": {
"servers": {
"my-server": {
"url": "http://localhost:3100/mcp",
"transport": "streamable-http",
"headers": {
"Authorization": "Bearer ${MY_SECRET_TOKEN}"
},
"connectionTimeoutMs": 30000
}
}
}
}
transportaccepts"streamable-http"or"sse"; omitted defaults tosse.type: "http"is a CLI-native downstream shape; usetransport: "streamable-http"in Apus config.apus mcp setandapus doctor --fixnormalize the common alias.- Only
http:andhttps:URL schemes are allowed. headersvalues support${ENV_VAR}interpolation.- A server entry with both
commandandurlis rejected. - URL credentials (userinfo and query params) are redacted from tool descriptions and logs.
connectionTimeoutMsoverrides the default 30-second connection timeout for both stdio and HTTP transports. Request timeout defaults to 60 seconds and can be overridden withrequestTimeoutMs. Tool listing (tools/list) at session start usesrequestTimeoutMswhen it is set, and 10 seconds otherwise.
Tool naming
Apus registers bundle MCP tools with provider-safe names in the form
serverName__toolName. For example, a server keyed "vigil-harbor" exposing a
memory_search tool registers as vigil-harbor__memory_search.
- Characters outside
A-Za-z0-9_-are replaced with-. - Fragments that would start with a non-letter get a letter prefix, so numeric
server keys such as
12306become provider-safe tool prefixes. - Server prefixes are capped at 30 characters.
- Full tool names are capped at 64 characters.
- Empty server names fall back to
mcp. - Colliding sanitized names are disambiguated with numeric suffixes.
- Final exposed tool order is deterministic by safe name, keeping repeated embedded-agent turns cache-stable.
- Profile filtering treats every tool from one bundle MCP server as
plugin-owned by
bundle-mcp, so profile allow/deny lists can reference either individual exposed tool names or thebundle-mcpplugin key.
Bundle formats
Agent Plugins bundles
Marker: `plugin.json` at the package root, per the open
[Agent Plugins 1.0.0 standard](https://agent-plugins.org)
Optional content: `skills/`, `mcp.json`
Format behavior:
- The manifest is strict JSON (not JSON5). Apus requires a non-empty
`name`; other manifest fields are optional and unknown fields are ignored
- Immediate child directories of `skills/` that contain a `SKILL.md` load as
skills; children without one are skipped with a warning, and deeper
directories are not scanned
- `mcp.json` must declare the 1.0.0 `$schema` and an `mcpServers` object
only; `stdio`, `streamable-http`, and legacy `sse` transports are
supported
- stdio servers launch with `PLUGIN_ROOT` (the plugin root) and
`PLUGIN_DATA` (a persistent per-plugin data directory Apus creates
under its state dir) in their environment; `${PLUGIN_ROOT}` and
`${PLUGIN_DATA}` placeholders expand in `args`, `env` values, and `cwd`
in a single pass
- A stdio `command` must be a bare executable name or a `./`-relative path
inside the plugin; `cwd` must stay inside `PLUGIN_ROOT` or `PLUGIN_DATA`
- Invalid `mcp.json` disables MCP for the plugin with a diagnostic while
skills keep loading; invalid individual server entries are skipped
- `.mcp.json` (dot-prefixed) and inline manifest `mcpServers` are **not**
read for this format; the standard's closed schema wins
- Apus reads `extensions["ai.apus"]`; it supports only
`activation` with the same semantics as other bundle manifests
- Other manifest extension namespaces are ignored and reserved for their
clients
- Reverse-domain client directories are ignored and reserved
Codex bundles
Markers: `.codex-plugin/plugin.json`
Optional content: `skills/`, `hooks/`, `.mcp.json`, `.app.json`
Codex bundles fit Apus best when they use skill roots and Apus-style
hook-pack directories (`HOOK.md` + `handler.ts`).
Claude bundles
Two detection modes:
- **Manifest-based:** `.claude-plugin/plugin.json`
- **Manifestless:** default Claude layout (`skills/`, `commands/`, `agents/`, `hooks/`, `.mcp.json`, `.lsp.json`, `settings.json`)
`output-styles/` is not a detection marker. A bundle whose only content is
`output-styles/` is not recognized as a Claude bundle. Add
`.claude-plugin/plugin.json`, or one of the markers above, so detection
succeeds. Detection runs before manifest loading, so an undetected
directory never reaches the component paths below.
Claude-specific behavior:
- `commands/`, `agents/`, and `output-styles/` are treated as skill content
- `settings.json` is imported into embedded Apus settings (shell override keys are sanitized)
- `.mcp.json` exposes supported stdio tools to embedded Apus
- `.lsp.json` plus manifest-declared `lspServers` paths load into embedded Apus LSP defaults
- `hooks/hooks.json` is detected but not executed
- Custom component paths in the manifest are additive; they extend defaults, not replace them
Cursor bundles
Markers: `.cursor-plugin/plugin.json`
Optional content: `skills/`, `.cursor/commands/`, `.cursor/agents/`, `.cursor/rules/`, `.cursor/hooks.json`, `.mcp.json`
- `.cursor/commands/` is treated as skill content
- `.cursor/rules/`, `.cursor/agents/`, and `.cursor/hooks.json` are detect-only
Detection precedence
Apus checks for native plugin format first:
apus.plugin.jsonor a validpackage.jsonwithapus.extensions- treated as a native plugin- Client-specific bundle markers (
.codex-plugin/,.cursor-plugin/,.claude-plugin/) - treated as a bundle in that format - A root
plugin.json- treated as an Agent Plugins bundle - Default manifestless Claude layout (
skills/,commands/,.mcp.json, ...) - treated as a Claude bundle
If a package carries both a client-specific marker and a root plugin.json,
the client-specific format wins so its richer mappings (commands, hooks,
settings) are preserved. If a directory contains both a native manifest and
bundle markers, Apus uses the native path. This prevents dual-format
packages from being partially installed as bundles.
Runtime dependencies and cleanup
- Third-party compatible bundles do not get startup
npm installrepair. They should be installed throughapus plugins installand ship everything they need in the installed plugin directory. - Apus-owned bundled plugins are either shipped lightweight in core or downloadable through the plugin installer. Gateway startup never runs a package manager for them.
apus doctor --fixremoves stale local bundled-plugin install records and can recover downloadable plugins that are missing from the local plugin index when config still references them.
Security
Bundles have a narrower trust boundary than native plugins:
- Apus does not load arbitrary bundle runtime modules in-process.
- Skills and hook-pack paths must stay inside the plugin root (boundary-checked).
- Settings files are read with the same boundary checks.
- Supported stdio MCP servers may be launched as subprocesses.
This makes bundles safer by default, but you should still treat third-party bundles as trusted content for the features they do expose.
Troubleshooting
Bundle is detected but capabilities do not run
Run `apus plugins inspect <id>`. If a capability is listed but marked as
not wired, that is a product limit, not a broken install.
Claude command, agent, or output-style files do not appear
Make sure the bundle is enabled and the markdown files are inside a detected
`skills/`, `commands/`, `agents/`, or `output-styles/` root. All four load
through the same skill loader.
Claude settings do not apply
Only embedded Apus settings from `settings.json` are supported. Apus does
not treat bundle settings as raw config patches.
Claude hooks do not execute
`hooks/hooks.json` is detect-only. If you need runnable hooks, use the
Apus hook-pack layout or ship a native plugin.
Related
- Install and Configure Plugins
- Building Plugins - create a native plugin
- Plugin Manifest - native manifest schema