Skip to content

Commit a2a3fbe

Browse files
feat(agent-bundle): add Amp native plugin factory (#729)
* feat(agent-bundle): add Amp native plugin target * test(agent-bundle): harden Amp host contract * docs: reference Amp pull request * fix(agent-bundle): harden Amp artifact ownership * fix(agent-bundle): address Amp review findings * fix(agent-bundle): close Amp review risks * fix(agent-bundle): preserve dev host narrowing * test(agent-bundle): align installer host usage * fix(agent-bundle): avoid cwd for Amp user installs
1 parent 62e5c3a commit a2a3fbe

102 files changed

Lines changed: 3991 additions & 338 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"agent-bundle": minor
3+
---
4+
5+
Add the `amp` target and `AmpSkillExtension`, emit PluginAPI factories with registered skills and events, install receipt-owned project or system copies through `agent-bundle install amp`, and advance artifacts to `manifestVersion: 4` with `projections[].documents.entry`; unrelocatable local MCP entries fail with `amp.mcp.generated-local` (#729)

‎README.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# agent-bundle
22

3-
agent-bundle compiles an agent plugin — skills, hooks, MCP servers, and scripts, described by one typed config — into one installable plugin root that Claude Code, Codex, Cursor, and portable Agent Plugins clients load. You write the plugin once; the compiler emits each selected host's manifests and wrappers into that root.
3+
agent-bundle compiles an agent plugin — skills, hooks, MCP servers, and scripts, described by one typed config — into installable output for Amp, Claude Code, Codex, Cursor, and portable Agent Plugins clients. You write the plugin once; the compiler emits each selected host's entry, manifests, and wrappers into one composite root.
44

55
Documentation: [scriptedalchemy.github.io/agent-bundle](https://scriptedalchemy.github.io/agent-bundle/) (English and 简体中文; guide, reference, generated type API, host capability matrices).
66

@@ -51,7 +51,7 @@ npx agent-bundle build --root . # write the plugin root to artif
5151
npx agent-bundle dev --root . # local workbench with live rebuilds
5252
```
5353

54-
`agent-bundle build` writes one composite plugin root (`artifact/` by default; `--output` or `output.distPath` relocates it), and `targets` selects which host projections it carries: the `.claude-plugin/`, `.codex-plugin/`, and `.cursor-plugin/` manifests and the portable `plugin.json` sit at the root over shared `skills/`, `hooks/`, `mcp/`, and `scripts/` directories, emitted once. Every selected host installs from that same directory, and the generated `INSTALL.md` explains how. Omitting `targets` emits only the `portable` projection.
54+
`agent-bundle build` writes one composite root (`artifact/` by default; `--output` or `output.distPath` relocates it), and `targets` selects which host projections it carries: Amp's `.amp/plugins/<name>/index.js`, the `.claude-plugin/`, `.codex-plugin/`, and `.cursor-plugin/` manifests, and the portable `plugin.json`. Amp installs its nested directory; the other hosts install the composite root, and the generated `INSTALL.md` explains how. Omitting `targets` emits only the `portable` projection.
5555

5656
The `portable` target is the [Agent Plugins open standard](https://agent-plugins.org/specification) (specification 1.0.0) adapter — the default projection, and the layout Cursor loads natively (Claude Code consumes it only through CLI translation). Every other client that reads this artifact is recorded with its tier, install command, and dated evidence in the `clients` section of that same capability table, rendered as the [hosts reference](https://scriptedalchemy.github.io/agent-bundle/reference/hosts). It emits the closed root `plugin.json` (canonical `$schema`, `name`, `version`, `description`, plus `author`, `homepage`, `repository`, `license`, `keywords`, and reverse-domain `extensions` authored under the `portable` config key), `skills/<name>/SKILL.md`, and `mcp.json` with stdio and Streamable HTTP servers whose `args`, `env` values, and `cwd` use the standard's `${PLUGIN_ROOT}`/`${PLUGIN_DATA}` placeholders. Rules, commands, hooks, marketplaces, and client extension directories are honestly unavailable there because the v1 standard packages only skills and MCP servers. Both documents are validated against the vendored, hash-pinned 1.0.0 schemas and the normative text at plan time (`portable.mcp.*.standard`), after every ordinary build and `validate --artifact` (`AB6011`/`AB6012` plus the Agent Plugins byte lane `AB6035`–`AB6037`), under `validate --artifact --host-validation` (same lane with the `AB6038` provenance note), and by `agent-bundle doctor` for installed Cursor local plugins that declare the standard's `$schema` (`AB7320`); see [Diagnostics](docs/diagnostics.md#agent-plugins-portable-validation-ab6035ab6038). Pins live in `packages/agent-bundle/src/adapters/schemas/portable/PROVENANCE.json`; the capability table `packages/agent-bundle/src/adapters/capabilities/portable-1.0.0.json` carries a dated row for every standard feature.
5757

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Amp native adapter proof — 2026-09-07
2+
3+
## Pins and boundary
4+
5+
- `@ampcode/plugin@0.0.0-20260907001852-gf348fed`
6+
- `@ampcode/cli@0.0.1788739286-gf348fe`
7+
- Official Plugin, PluginAPI, Skills, and MCP pages retrieved 2026-09-07
8+
- No Amp account was available. Live thread, model, and tool execution was not run and remains
9+
**unverified**, not unsupported.
10+
11+
Everything below ran under `/tmp/agent-bundle-amp-proof` with
12+
`HOME=/tmp/agent-bundle-amp-proof/home`.
13+
14+
## Build and static artifact proof
15+
16+
The disposable consumer installed the two pinned Amp packages, TypeScript, Node/Bun type
17+
declarations, and the locally built `agent-bundle` package. npm 12 blocked the CLI postinstall by
18+
default, so the proof completed the package's own `node node_modules/@ampcode/cli/install.cjs`
19+
before invoking Amp.
20+
21+
`agent-bundle build --target amp` emitted:
22+
23+
```text
24+
artifact/
25+
├── .amp/plugins/amp-proof/index.js
26+
├── .amp/plugins/amp-proof/skills/review/SKILL.md
27+
├── INSTALL.md
28+
├── agent-bundle.compile-evidence.json
29+
└── agent-bundle.manifest.json
30+
```
31+
32+
The manifest recorded `manifestVersion: 4`,
33+
`builtInHost: "amp"`, `documents.entry: ".amp/plugins/amp-proof/index.js"`,
34+
adapter revision `1.0.0`, and the pinned PluginAPI version. The compile evidence used
35+
`closed-world-externals` revision 1 and recorded no compiled assets for the content-only plugin.
36+
37+
## PluginAPI type and fake-host proof
38+
39+
Two generated entries were checked with TypeScript 7.0.2 in strict `checkJs` mode:
40+
41+
1. the content-only factory with one explicit `registerSkill`;
42+
2. a callback factory containing inline handlers for `session.start`, `tool.call`, `tool.result`,
43+
`agent.start`, and `agent.end`.
44+
45+
The disposable `tsconfig.json` alone used `skipLibCheck: true`, because the pinned upstream
46+
declaration references `Symbol.observable`, which the selected TypeScript libs do not declare.
47+
No repository compiler setting was weakened.
48+
49+
Both entries passed. Neither has a runtime `@ampcode/plugin` import; its only reference is the
50+
JSDoc type on the default async factory. A typed fake `PluginAPI` then imported the factories and
51+
asserted:
52+
53+
- exactly `registerSkill({ path: "skills/review" })`;
54+
- no event registrations for the content-only entry;
55+
- exactly the five documented event registrations for the callback entry;
56+
- `tool.call` native results preserved as `reject-and-continue`, `modify`, and `synthesize`;
57+
- `tool.result` replacement preserved as `{ status: "done", output: "replaced" }`.
58+
59+
The repository adapter tests additionally cover `allow`, `agent.start` appended context,
60+
`agent.end` continuation, generated wrapper execution, MCP/frontmatter precedence, relocation,
61+
and receipt-owned install/replace/uninstall.
62+
63+
## Account-free CLI observations
64+
65+
- `amp --help`: exit 0; lists `plugins`, `skill`, and `mcp`.
66+
- `amp skill add --help`: exit 0; source is `owner/repo[/path]`, a Git URL, or a local path;
67+
`--global` targets `~/.config/agents/skills/`.
68+
- `amp plugins list`: exit 1:
69+
70+
```text
71+
Error: failed to load global plugins. Unable to connect to https://ampcode.com/.
72+
```
73+
74+
- `amp skills list --json`: started the login flow with `No API key found. Starting login flow...`
75+
and was terminated rather than opening or completing an account login.
76+
77+
Amp documents `plugins: reload` only as an interactive command-palette action. No standalone
78+
plugin validator exists, so the implementation does not invent or automate either operation.

‎docs/diagnostics.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1928,10 +1928,10 @@ the uninstall refusals `AB7007`–`AB7009`, have their own sections above.
19281928

19291929
| Code | Severity | Meaning | Recovery |
19301930
| --- | --- | --- | --- |
1931-
| `AB7000` | error | Install/uninstall: `Unsupported install host <host>.` / `Unsupported uninstall host <host>.` — the exhaustive host switch received a host that is not `claude`, `codex`, or `cursor`. Project preparation: `Unable to load project source.` — evaluating the configuration module or discovering source threw before validation. | Install: pass `--host claude`, `codex`, or `cursor`. Preparation: fix the Agent Bundle configuration and source files, then inspect again. |
1932-
| `AB7001` | error | Install/uninstall/doctor: the bundle identity or authoritative file inventory is unreadable from `agent-bundle.manifest.json` — no manifest directly under the `--from` directory (the composite root is every selected host's bundle root, so `<from>/<host>` is never probed and host documents are never read for identity); a manifest that is not the canonical `manifestVersion: 3` document (the message carries the parser's reason); a manifest with no projection whose `builtInHost` is the requested host (identity is the shipped adapter, never the selected name), whose projection has no `documents.plugin`, or whose `documents.plugin` / `documents.marketplace` pointer names a file the root does not contain; a `files[]` row whose path is missing or whose size, digest, bytes, or executable state is invalid after installation (a declared package bin must remain executable; a file the manifest does not declare executable must remain non-executable; another manifest executable may have lost its bit while being packed from a filesystem without executable modes); a Cursor `application.name` that is not a safe local plugin name; a Claude or Codex projection with no `marketplace.name`. `install` restores manifest modes before copying an npm-installed artifact into a host, while Doctor only compares. Project preparation: `Unable to validate project source.`, `Unable to normalize project source.`, `Unable to validate normalized project.`, or `Unable to create project context.` — the source validator, normalizer, adapter planner, or project-context factory threw; `inspectProject` adds `Unable to prepare inspection plans.` and, for `inspect --bundler`, `Unable to compose the bundler inspection: <reason>` — loading entries, generating the declaration tsconfig, or lowering and asserting the build's own Rslib/Rsbuild configuration failed. The reason carries the underlying source, project-tsconfig, toolchain, or invariant error, including a `tools` value the build would refuse. | Install: point `--from` at the unchanged composite root `agent-bundle build` wrote, rebuilt with the host among `targets`; if a listed file is missing or changed, rebuild or restore that file from the matching artifact. Preparation: fix normalized project configuration and source references, then inspect again. Bundler inspection: fix the source, project tsconfig, toolchain, or refused `tools` value named by the reason. |
1931+
| `AB7000` | error | Install/uninstall: `Unsupported install host <host>.` / `Unsupported uninstall host <host>.` — the exhaustive host switch received a host that is not `amp`, `claude`, `codex`, or `cursor`. Project preparation: `Unable to load project source.` — evaluating the configuration module or discovering source threw before validation. | Install: pass `--host amp`, `claude`, `codex`, or `cursor`. Preparation: fix the Agent Bundle configuration and source files, then inspect again. |
1932+
| `AB7001` | error | Install/uninstall/doctor: the bundle identity or authoritative file inventory is unreadable from `agent-bundle.manifest.json` — no manifest directly under the `--from` directory (the composite root is every selected host's bundle root, so `<from>/<host>` is never probed and host documents are never read for identity); a manifest that is not the canonical `manifestVersion: 4` document (the message carries the parser's reason); a manifest with no projection whose `builtInHost` is the requested host (identity is the shipped adapter, never the selected name), whose projection has neither its required `documents.plugin` nor Amp `documents.entry`, or whose `documents.entry` / `documents.plugin` / `documents.marketplace` pointer names a file the root does not contain; a `files[]` row whose path is missing or whose size, digest, bytes, or executable state is invalid after installation (a declared package bin must remain executable; a file the manifest does not declare executable must remain non-executable; another manifest executable may have lost its bit while being packed from a filesystem without executable modes); a Cursor or Amp `application.name` that is not a safe local plugin name; a Claude or Codex projection with no `marketplace.name`. `install` restores manifest modes before copying an npm-installed artifact into a host, while Doctor only compares. Project preparation: `Unable to validate project source.`, `Unable to normalize project source.`, `Unable to validate normalized project.`, or `Unable to create project context.` — the source validator, normalizer, adapter planner, or project-context factory threw; `inspectProject` adds `Unable to prepare inspection plans.` and, for `inspect --bundler`, `Unable to compose the bundler inspection: <reason>` — loading entries, generating the declaration tsconfig, or lowering and asserting the build's own Rslib/Rsbuild configuration failed. The reason carries the underlying source, project-tsconfig, toolchain, or invariant error, including a `tools` value the build would refuse. | Install: point `--from` at the unchanged composite root `agent-bundle build` wrote, rebuilt with the host among `targets`; if a listed file is missing or changed, rebuild or restore that file from the matching artifact. Preparation: fix normalized project configuration and source references, then inspect again. Bundler inspection: fix the source, project tsconfig, toolchain, or refused `tools` value named by the reason. |
19331933
| `AB7002` | error | Install/uninstall: `<host> is not installed or is not available on PATH.`, `Cursor is not installed in "<root>".` / `Cursor home "<root>" is not a directory.`, or `git` is missing for `--mode marketplace`. Project preparation: `Unable to prepare project paths.` — the project root or a configured output root could not be resolved inside the project. | Install: install the host CLI the message names; for the `git` refusal, install git or use `--mode local`. Preparation: ensure the project root and configured output roots are readable and remain inside the project root, then inspect again. |
1934-
| `AB7003` | error | Install/uninstall scope and mode refusals: `--mode` on a host other than `cursor`; `--scope` other than `user` for Codex or Cursor; `--mode marketplace` without `.cursor-plugin/plugin.json` or with bundle-internal Git metadata. Project preparation: `Unable to snapshot project source.` — the source snapshot could not be taken. | Install: use `--scope user`, drop `--mode` for non-Cursor hosts, or — as the message says — stage a Cursor Plugin bundle without `.git`, or use `--mode local`. Preparation: ensure project source files and ignore rules are readable and remain inside the project root, then inspect again. |
1934+
| `AB7003` | error | Install/uninstall scope and mode refusals: `--mode` on a host other than `cursor`; `--scope` other than `user` for Codex or Cursor; Amp `--scope local` instead of `project` or `user`; `--mode marketplace` without `.cursor-plugin/plugin.json` or with bundle-internal Git metadata. Project preparation: `Unable to snapshot project source.` — the source snapshot could not be taken. | Install: use a documented host scope, drop `--mode` for non-Cursor hosts, or — as the message says — stage a Cursor Plugin bundle without `.git`, or use `--mode local`. Preparation: ensure project source files and ignore rules are readable and remain inside the project root, then inspect again. |
19351935
| `AB7004` | error | Install/uninstall command and safety failures: `<host> plugin <operation> failed: <detail>` (a host CLI verb exited nonzero); `<host> plugin list --json` was unusable when `--replace` or an uninstall needed it; an installed copy could not be compared and `--replace` was not given; a rollback after a failed install also failed (the message lists the host verbs to run by hand); a Cursor marketplace `git` step failed or the committed tree differs from the staged bytes; or any non-diagnostic error thrown by a Cursor installer. `inspectProject`: `Requested inspection target "<name>" is not selected for this project.` | Install: read the host's detail in the message, then rerun (with `--replace` where the message says so). Inspection: choose a target selected by the project configuration, then inspect again. |
19361936

19371937
## Development server (`AB80xx`)

‎packages/agent-bundle/README.md‎

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# agent-bundle
22

3-
Compile a typed Agent Bundle configuration into portable, Codex, Claude Code, and Cursor artifacts. Node.js 22.19 or later is required.
3+
Compile a typed Agent Bundle configuration into Amp, portable, Codex, Claude Code, and Cursor artifacts. Node.js 22.19 or later is required.
44

55
Full documentation: [scriptedalchemy.github.io/agent-bundle](https://scriptedalchemy.github.io/agent-bundle/).
66

@@ -189,6 +189,7 @@ so their public CLIs can install the emitted directory directly:
189189
```sh
190190
agent-bundle install claude --from artifact --scope user
191191
agent-bundle install codex --from artifact
192+
agent-bundle install amp --from artifact --scope user
192193
```
193194

194195
The installer delegates to `claude plugin marketplace add` /
@@ -205,6 +206,11 @@ agent-bundle install cursor --from artifact
205206
node ./install.mjs
206207
```
207208

209+
Amp installs only `artifact/.amp/plugins/<name>/` into the project or system
210+
plugin root. The generated `index.js` default-exports the async PluginAPI
211+
factory, registers each bundled Skill once, and imports no Amp runtime.
212+
Reloading remains the interactive Ctrl+O → `plugins: reload` action.
213+
208214
Cursor loads the copied `.cursor-plugin/plugin.json` and its manifest-declared
209215
`.cursor-plugin/hooks.json` from that directory; plugin hooks run from the plugin root
210216
with `${CURSOR_PLUGIN_ROOT}` substituted and need no `~/.cursor/hooks.json`
@@ -227,8 +233,9 @@ the shipped document in the install receipt (`cursorExpansion`), and
227233
`agent-bundle doctor --host cursor` proves the expansion (`AB7326`). The bundle
228234
itself stays spec-conformant for other Agent Plugins clients.
229235

230-
Cursor installation is user-scoped. Claude also accepts `--scope project` and
231-
`--scope local`; Codex is user-scoped. `--from` names the composite root itself —
236+
Cursor installation is user-scoped. Amp accepts project scope and user scope
237+
(its system root). Claude also accepts `--scope project` and `--scope local`;
238+
Codex is user-scoped. `--from` names the composite root itself —
232239
the directory that holds `agent-bundle.manifest.json` — and a source-free copy
233240
of that root is accepted. Identity (name, version, marketplace) and the host
234241
plugin document come from that manifest's `application` and `projections[]`
@@ -305,7 +312,7 @@ Receipts (`agent-bundle-install-receipt/2`) are the single source of truth for
305312
an install's lifecycle: version, content hash, delivery mode, scope, owned files
306313
and directories, the host directories the installer created, the host
307314
registrations it performed in order, and install/update timestamps. Cursor
308-
local copies carry the receipt in-tree; Claude, Codex, and Cursor
315+
local and Amp project/system copies carry the receipt in-tree; Claude, Codex, and Cursor
309316
marketplace-mode installs keep theirs under `<host root>/agent-bundle/receipts/`
310317
(`~/.claude`, `~/.codex`, `~/.cursor`, honouring `CLAUDE_CONFIG_DIR` and
311318
`CODEX_HOME`). `agent-bundle uninstall <host> --from <bundle-dir>`, the package

‎packages/agent-bundle/package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "agent-bundle",
33
"version": "0.1.0",
4-
"description": "Compile a typed Agent Bundle configuration into portable, Codex, Claude Code, and Cursor artifacts.",
4+
"description": "Compile a typed Agent Bundle configuration into Amp, portable, Codex, Claude Code, and Cursor artifacts.",
55
"license": "Apache-2.0",
66
"keywords": [
77
"agent",

0 commit comments

Comments
 (0)