You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Agent Bundle should always emit one composite plugin artifact. plugin should not be a public target. The public targets remain claude, codex, cursor, and portable; selecting them controls which host projections are present inside the composite root.
The same directory should be publishable through Git, npm, or used locally without changing its internal layout. Distribution is a separate axis from host projection selection.
For example:
targets: ['claude','codex']
emits one root containing the Claude and Codex conventions plus shared implementation files. It must not emit sibling claude/, codex/, or plugin/ packs.
Adding cursor adds the Cursor projection and the Cursor lifecycle helper. Adding portable adds the Agent Plugins projection inside the same distributable, subject to the compatibility constraint below.
If targets is omitted, keep the current default inclusion policy (portable) unless that default is changed separately. The output shape is still one composite root.
Artifact contract
The publishable root contains the files required by the selected hosts, alongside shared compiled content:
package.json # when published to npm
.claude-plugin/plugin.json # when claude is selected
.claude-plugin/marketplace.json
.codex-plugin/plugin.json # when codex is selected
.agents/plugins/marketplace.json
.cursor-plugin/plugin.json # when cursor is selected
.cursor-plugin/marketplace.json
plugin.json # portable projection, when compatible
.mcp.json / mcp.json / host variants
hooks/
skills/
scripts/
bin/
mcp/
mcp-apps/
assets/
INSTALL.md
install.mjs # only when a selected host needs it
agent-bundle.manifest.json
Shared byte-identical scripts, MCP servers, apps, assets, and skills are emitted once. Host manifests point to those shared files. A host-specific document or wrapper is emitted only when that host requires a different representation.
Target-scoped declarations retain their current meaning. A Claude-only component must not become visible to Codex merely because both projections share one filesystem root. Where a conventionally discovered directory cannot faithfully isolate a host-specific component, the builder must either emit a host-specific view supported by that host or fail with an explicit diagnostic. It must not silently widen the component's target scope.
The artifact manifest records the selected real host projections and their provenance. It does not record plugin as a target or use target names as physical output partitions.
Current implementation
The current code has most of the format-specific emitters, but the planner still treats output format and host selection as the same axis:
config/normalize.ts selects registered target names and synthesizes a plugin lowering target.
adapters/registry.ts registers pluginAdapter as an ordinary selectable target; portable is the current default.
build/build.ts plans each selected adapter independently and stages it at <artifactRoot>/<target.name>.
adapters/plugin.ts is an always-Claude-plus-Codex-plus-Cursor adapter. It filters resources through the synthetic plugin target, always invokes those host planners, and has static validation requirements for Claude and Codex.
api.ts, package inventory, artifact validation, dev/workbench services, eval harnesses, and test helpers assume that a host is found under <output>/<target>.
build/package-build.ts currently creates a sibling npm package whose installer reaches back to a nested artifact. The npm package root is not itself the plugin root.
install/install.ts probes the supplied root, then <root>/<host>, then <root>/plugin; install/doctor.ts probes the root and <root>/<host>. The composite root should become canonical in both.
This is not a default-target change. It requires separating two concepts:
Compute capability and notice-delivery diagnostics over the selected projections rather than a fixed Claude/Codex/Cursor set.
Make artifact validation conditional on the projections actually selected.
Preserve native hooks for every selected host; the current composite path must not strip them through a hook-free intermediate model.
3. Resolve the portable/Codex/Cursor root collision
The portable adapter requires a root plugin.json and may emit root mcp.json. The current composite adapter intentionally omits root plugin.json because Codex can prefer it over .codex-plugin/plugin.json, which loses Codex hooks/apps and changes MCP lookup. Cursor also uses root MCP conventions.
portable + codex and portable + cursor therefore cannot be implemented as an unchecked file merge. Define and prove one of:
a namespaced portable view with install/materialization support while keeping one distributable root;
a merged representation proven to preserve all selected host features; or
a clear build-time incompatibility diagnostic for combinations that cannot yet be represented faithfully.
The intended end state is additive portable support, but the implementation must not claim that support by degrading another selected host.
4. Make the root distribution-neutral
The exact composite root should work in each of these forms:
Git/GitHub: committed at a repository root, artifact branch, release repository, or a documented subdirectory referenced by a root marketplace catalog.
npm: packed with package.json, host manifests, generated runtime files, and all referenced assets at the npm package root; never under artifact/<host> or artifact/plugin.
local directory: passed directly to host marketplace/install commands or Agent Bundle lifecycle commands.
Git is the common discovery path for both Claude and Codex: users add an owner/repo, Git URL, or local marketplace, then install the named plugin. Both Claude and Codex marketplaces can use an npm package as the plugin source. Codex materializes the package with npm pack --ignore-scripts, requires the standard npm package/ archive root, verifies the package.json name against the requested package, and installs the extracted plugin root without running package scripts. The npm tarballs inspected for @prismer/claude-code-plugin, @ours.network/codex, and @useorgx/codex-plugin put .claude-plugin/ or .codex-plugin/, skills, hooks, and package.json at the same package root; that is the layout to produce.
Supported source and install mapping
npm is a plugin source inside a marketplace catalog, not a replacement for the marketplace itself. The user still adds a catalog and installs a named plugin; the host materializes the package declared by that catalog.
Distribution form
Claude
Codex
Cursor
Composite-root requirement
GitHub or Git marketplace
claude plugin marketplace add owner/repo, then claude plugin install <plugin>@<marketplace>
codex plugin marketplace add owner/repo, then codex plugin add <plugin>@<marketplace>
The generated helper can stage a committed local marketplace; Cursor then requires its Customize import/install step
Repository catalog resolves the composite root through ./ or a documented relative subdirectory
Local directory
Native marketplace add/install commands accept the local catalog/root
Native marketplace add/plugin add commands accept the local catalog/root
node install.mjs copies the root safely into Cursor's local plugin directory
Supplied directory is already the complete composite root
npm package
Marketplace entry uses { "source": "npm", "package": "@scope/name", "version": "..." }; Claude installs the package
Same source shape; Codex uses npm pack --ignore-scripts, validates the standard package/ archive root and package name, then installs the extracted plugin root
No native npm-backed non-interactive install path is assumed; the bundled helper installs from the acquired package root
Host manifests and every referenced file are at the npm package root, not under artifact/
The generated catalogs and INSTALL.md must use only source types actually supported by that host. The Git/local/npm delivery choice must not change the plugin's internal bytes or require a post-install Agent Bundle build.
Marketplace catalogs for a repository root and catalogs that resolve an npm package are different distribution metadata, but both must resolve to the same composite plugin root. Do not introduce npm, git, or plugin as host targets. If configuration is needed for distribution wrappers/catalogs, keep it separate from targets.
5. Generate installation surfaces from selected projections
INSTALL.md must contain only the selected hosts and exact commands for the chosen distribution form.
Claude and Codex should use their native marketplace/plugin CLIs whenever the source form is supported.
Cursor currently has marketplace management but no complete non-interactive install/uninstall verb. When cursor is selected, include the existing self-contained install.mjs and its uninstall path.
Preserve the existing Cursor local mode: receipt-owned, idempotent copy into ~/.cursor/plugins/local/<name>, replacement checks, --uninstall, and guarded data purge.
Preserve marketplace mode: stage a committed repository, print the required Cursor Customize import step, and report that removal of Cursor-owned cached imports is manual when the host exposes no CLI operation.
Emit install.mjs only when at least one selected projection needs it. If a future host CLI provides the complete lifecycle, the generated instructions can use it instead.
A requested install for an unselected host must fail with a clear missing-projection diagnostic.
6. Use one marketplace identity
Marketplace naming is currently inconsistent: Claude can configure its name while other adapters and install text hardcode <plugin>-marketplace. Normalize a single marketplace identity, use it in every selected manifest, instruction, receipt, install/uninstall command, and Doctor result, and validate host-reserved names. A reasonable default is the plugin name.
7. Update all composite-root consumers
Update artifact validation, package inventory, prepack, install, uninstall, Doctor, dev host sync, Workbench/playground, MCP services, eval harnesses, and installed-test helpers to resolve the composite root first and select a logical host view within it. Nested <root>/<host> and <root>/plugin probing may remain temporarily as an explicit backward-compatibility path, but new output and documentation use the root.
Generated AGENTS.md must be optional, selected-projection-aware, or placed so it cannot overwrite a repository's authored AGENTS.md when the composite is published at the repository root.
Acceptance tests
targets: ['claude', 'codex'] emits one root with .claude-plugin/ and .codex-plugin/, no claude/, codex/, portable/, or plugin/ output partitions, and no Cursor projection.
Cursor-only emits one root with Cursor files, INSTALL.md, and the self-contained install.mjs --uninstall lifecycle.
plugin is rejected as a config or CLI target.
Omitting targets emits one composite root with the documented default projection set.
Reversing target order produces byte-identical output.
Shared implementation files compile once; each selected host manifest references them correctly; host-scoped components do not leak.
Selected native hook documents and wrappers survive composition; unselected host files are absent.
The artifact manifest and hook index list real projections only.
portable + codex and portable + cursor preserve the native host feature set or fail with the documented incompatibility diagnostic.
npm pack --json shows manifests and plugin content at package/ root, with no artifact/**; installing the packed tarball uses no source checkout and no post-install Agent Bundle build.
The same committed root passes native local/Git marketplace install checks for Claude and Codex, and the supported npm-source install checks.
Install, replacement, uninstall, and Doctor are exercised from the composite root for every selected host. Cursor local and staged-marketplace receipt, purge, and manual-final-step behavior remain covered.
Marketplace name configuration is consistent in all manifests, instructions, receipts, and lifecycle commands.
Authored AGENTS.md preservation and generated-instruction behavior are covered.
Decision
Agent Bundle should always emit one composite plugin artifact.
pluginshould not be a public target. The public targets remainclaude,codex,cursor, andportable; selecting them controls which host projections are present inside the composite root.The same directory should be publishable through Git, npm, or used locally without changing its internal layout. Distribution is a separate axis from host projection selection.
For example:
emits one root containing the Claude and Codex conventions plus shared implementation files. It must not emit sibling
claude/,codex/, orplugin/packs.Adding
cursoradds the Cursor projection and the Cursor lifecycle helper. Addingportableadds the Agent Plugins projection inside the same distributable, subject to the compatibility constraint below.If
targetsis omitted, keep the current default inclusion policy (portable) unless that default is changed separately. The output shape is still one composite root.Artifact contract
The publishable root contains the files required by the selected hosts, alongside shared compiled content:
Shared byte-identical scripts, MCP servers, apps, assets, and skills are emitted once. Host manifests point to those shared files. A host-specific document or wrapper is emitted only when that host requires a different representation.
Target-scoped declarations retain their current meaning. A Claude-only component must not become visible to Codex merely because both projections share one filesystem root. Where a conventionally discovered directory cannot faithfully isolate a host-specific component, the builder must either emit a host-specific view supported by that host or fail with an explicit diagnostic. It must not silently widen the component's target scope.
The artifact manifest records the selected real host projections and their provenance. It does not record
pluginas a target or use target names as physical output partitions.Current implementation
The current code has most of the format-specific emitters, but the planner still treats output format and host selection as the same axis:
config/normalize.tsselects registered target names and synthesizes apluginlowering target.adapters/registry.tsregisterspluginAdapteras an ordinary selectable target;portableis the current default.build/build.tsplans each selected adapter independently and stages it at<artifactRoot>/<target.name>.adapters/plugin.tsis an always-Claude-plus-Codex-plus-Cursor adapter. It filters resources through the syntheticplugintarget, always invokes those host planners, and has static validation requirements for Claude and Codex.api.ts, package inventory, artifact validation, dev/workbench services, eval harnesses, and test helpers assume that a host is found under<output>/<target>.build/package-build.tscurrently creates a sibling npm package whose installer reaches back to a nested artifact. The npm package root is not itself the plugin root.install/install.tsprobes the supplied root, then<root>/<host>, then<root>/plugin;install/doctor.tsprobes the root and<root>/<host>. The composite root should become canonical in both.This is not a default-target change. It requires separating two concepts:
claude | codex | cursor | portable.Required changes
1. Remove
pluginfrom the public target modeltargets: ['plugin']and--target pluginas unknown.plugintarget from normalized components, host documents, manifests, hook indexes, diagnostics, and user-facing target lists.pluginAdaptermay remain as an internal composite assembler, but it must not be registered as a public target.2. Plan selected projections into one stage
<artifactRoot>/<target>stages with one stage rooted atartifactRoot.3. Resolve the portable/Codex/Cursor root collision
The portable adapter requires a root
plugin.jsonand may emit rootmcp.json. The current composite adapter intentionally omits rootplugin.jsonbecause Codex can prefer it over.codex-plugin/plugin.json, which loses Codex hooks/apps and changes MCP lookup. Cursor also uses root MCP conventions.portable + codexandportable + cursortherefore cannot be implemented as an unchecked file merge. Define and prove one of:The intended end state is additive portable support, but the implementation must not claim that support by degrading another selected host.
4. Make the root distribution-neutral
The exact composite root should work in each of these forms:
package.json, host manifests, generated runtime files, and all referenced assets at the npm package root; never underartifact/<host>orartifact/plugin.Git is the common discovery path for both Claude and Codex: users add an
owner/repo, Git URL, or local marketplace, then install the named plugin. Both Claude and Codex marketplaces can use an npm package as the plugin source. Codex materializes the package withnpm pack --ignore-scripts, requires the standard npmpackage/archive root, verifies thepackage.jsonname against the requested package, and installs the extracted plugin root without running package scripts. The npm tarballs inspected for@prismer/claude-code-plugin,@ours.network/codex, and@useorgx/codex-pluginput.claude-plugin/or.codex-plugin/, skills, hooks, andpackage.jsonat the same package root; that is the layout to produce.Supported source and install mapping
npmis a plugin source inside a marketplace catalog, not a replacement for the marketplace itself. The user still adds a catalog and installs a named plugin; the host materializes the package declared by that catalog.claude plugin marketplace add owner/repo, thenclaude plugin install <plugin>@<marketplace>codex plugin marketplace add owner/repo, thencodex plugin add <plugin>@<marketplace>./or a documented relative subdirectorynode install.mjscopies the root safely into Cursor's local plugin directory{ "source": "npm", "package": "@scope/name", "version": "..." }; Claude installs the packagenpm pack --ignore-scripts, validates the standardpackage/archive root and package name, then installs the extracted plugin rootartifact/The generated catalogs and
INSTALL.mdmust use only source types actually supported by that host. The Git/local/npm delivery choice must not change the plugin's internal bytes or require a post-install Agent Bundle build.Marketplace catalogs for a repository root and catalogs that resolve an npm package are different distribution metadata, but both must resolve to the same composite plugin root. Do not introduce
npm,git, orpluginas host targets. If configuration is needed for distribution wrappers/catalogs, keep it separate fromtargets.5. Generate installation surfaces from selected projections
INSTALL.mdmust contain only the selected hosts and exact commands for the chosen distribution form.cursoris selected, include the existing self-containedinstall.mjsand its uninstall path.~/.cursor/plugins/local/<name>, replacement checks,--uninstall, and guarded data purge.install.mjsonly when at least one selected projection needs it. If a future host CLI provides the complete lifecycle, the generated instructions can use it instead.6. Use one marketplace identity
Marketplace naming is currently inconsistent: Claude can configure its name while other adapters and install text hardcode
<plugin>-marketplace. Normalize a single marketplace identity, use it in every selected manifest, instruction, receipt, install/uninstall command, and Doctor result, and validate host-reserved names. A reasonable default is the plugin name.7. Update all composite-root consumers
Update artifact validation, package inventory,
prepack, install, uninstall, Doctor, dev host sync, Workbench/playground, MCP services, eval harnesses, and installed-test helpers to resolve the composite root first and select a logical host view within it. Nested<root>/<host>and<root>/pluginprobing may remain temporarily as an explicit backward-compatibility path, but new output and documentation use the root.Generated
AGENTS.mdmust be optional, selected-projection-aware, or placed so it cannot overwrite a repository's authoredAGENTS.mdwhen the composite is published at the repository root.Acceptance tests
targets: ['claude', 'codex']emits one root with.claude-plugin/and.codex-plugin/, noclaude/,codex/,portable/, orplugin/output partitions, and no Cursor projection.INSTALL.md, and the self-containedinstall.mjs --uninstalllifecycle.pluginis rejected as a config or CLI target.portable + codexandportable + cursorpreserve the native host feature set or fail with the documented incompatibility diagnostic.npm pack --jsonshows manifests and plugin content atpackage/root, with noartifact/**; installing the packed tarball uses no source checkout and no post-install Agent Bundle build.AGENTS.mdpreservation and generated-instruction behavior are covered.References
claude plugin validateon the bundle directory, which Claude treats as a marketplace (hooks/skills/agents never checked) #475Version audited
Agent Bundle main at
42539ff5fand issue/code state inspected on 2026-09-04.