From 8256eadfd3547b7d4c8437181be48927b4322595 Mon Sep 17 00:00:00 2001 From: ScriptedAlchemy Date: Mon, 31 Aug 2026 02:08:29 +0000 Subject: [PATCH 1/3] docs(readme): pare the root README down to a human-written overview Closes #53. Replace the 325-line generated-reading README with a short overview: honest description, the pkg.pr.new install path (the npm `agent-bundle` name belongs to an unrelated project), a verified quickstart, a command list, the examples table, and pointers to the package README and docs that own the deep detail. --- README.md | 324 ++++++------------------------------------------------ 1 file changed, 35 insertions(+), 289 deletions(-) diff --git a/README.md b/README.md index e666fe8b0..04df6e986 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,28 @@ # agent-bundle -`agent-bundle` compiles one Agent Bundle project into portable, Codex, Claude Code, and Cursor artifacts. It discovers skills, validates a typed configuration, bundles local JavaScript/TypeScript entry points, and writes the host-specific metadata needed by each selected target. +agent-bundle compiles an agent plugin — skills, hooks, MCP servers, and scripts, described by one typed config — into installable artifacts for Claude Code, Codex, and Cursor, plus a portable layout. You write the plugin once; the compiler emits each host's manifests and wrappers. -It requires Node.js 22.19 or later. +Requires Node.js 22.19 or later. -## Quick start +## Install -Install the package in the project that owns the plugin, describe the plugin -once, and compile it for every host you target: +Nothing is published to npm yet (the `agent-bundle` name on npm currently belongs to an unrelated project). Until the first release, install the preview tarballs CI publishes for every commit and pull request: ```sh -npm install --save-dev agent-bundle +npm i -D https://pkg.pr.new/ScriptedAlchemy/agent-bundle/agent-bundle@ ``` -No version has been published to npm yet. Until the first release is cut, -install the identical preview package CI publishes for every commit and pull -request — see [Preview packages](docs/preview-packages.md). +Any `main` commit SHA or PR number works. See [Preview packages](docs/preview-packages.md) for pinning and details. + +## Quick start + +Describe the plugin in `agent-bundle.config.ts` at the project root: ```ts -// agent-bundle.config.ts import { defineConfig } from 'agent-bundle/config'; export default defineConfig({ - plugin: { name: 'my-plugin', version: '0.1.0', description: 'One bundle, every agent host.' }, + plugin: { name: 'my-plugin', version: '0.1.0', description: 'What it does.' }, targets: ['plugin'], skills: ['skills/*'], hooks: { sessionStart: { handler: './src/session-start.ts' } }, @@ -30,296 +30,42 @@ export default defineConfig({ }); ``` -```sh -agent-bundle dev --root . # local workbench with live rebuilds -agent-bundle build --root . --output dist -``` - -`targets: ['plugin']` emits one **agent plugin bundle** at `dist/plugin/` that -installs into multiple hosts from the same root: `.claude-plugin/` (Claude -Code), `.codex-plugin/` (Codex), and `.cursor-plugin/` (Cursor) manifests over -shared `skills/`, `hooks/`, `mcp/`, `scripts/`, and `assets/` directories, -plus a generated `AGENTS.md` install matrix. Hooks compile into host-detecting -wrappers shared by Claude Code and Codex plus dedicated Cursor-codec wrappers, -so one authored hook serves all three hosts. Per-host artifacts remain -available as `claude`, `codex`, `cursor`, and `portable` targets when a -host-specific layout is required. - -## Install and build - -```sh -agent-bundle dev --root . -agent-bundle build --root . --output artifact -``` - -The implemented commands are: - -- `agent-bundle build` validates source and writes an artifact. -- `agent-bundle inspect` displays the normalized source configuration and target plans. -- `agent-bundle validate` validates source; `agent-bundle validate --artifact ` validates a previously built artifact without reading source configuration. -- `agent-bundle mcp list` and `agent-bundle mcp invoke` operate a local artifact MCP server. -- `agent-bundle hooks list` and `agent-bundle hooks simulate` inspect and simulate generated hooks. -- `agent-bundle dev` starts the local development server and Workbench for an - ordinary project. Runtime remains an advanced optional extension: - `dev.runtime.provider` selects an application-owned provider when configured. -- `agent-bundle eval` runs deterministic or native Claude/Codex eval suites and records a run. - -`inspect` is intentionally a source/config-plan command; run it before source removal. Artifact-only inspection is the validation contract (`validate --artifact`). - -## Install the built bundle into hosts - -The compiled `dist/plugin/` directory is the installable product, and its -generated `AGENTS.md` repeats this install matrix next to the artifact: - -- **Claude Code** — add the directory (or its repository) as a plugin: - `claude plugin marketplace add `. -- **Codex** — `codex plugin marketplace add `; the manifest is - `.codex-plugin/plugin.json`. -- **Cursor** — clone (or symlink) the directory to - `~/.cursor/plugins/local/`; the manifest is - `.cursor-plugin/plugin.json`. -- **skills CLI** — `npx skills add --skill ` consumes the - shared `skills/` directory directly. - -Per-host artifacts (`dist/claude/`, `dist/codex/`, `dist/portable/`) install -the same way into their single host. Validate any artifact after the source -project is gone with `agent-bundle validate --artifact `. - -`agent-bundle dev` is available without the RSC example. Installing -`agent-bundle` does not install the example provider or React/RSC dependencies. -The optional example and Workbench architecture are documented in -[the RSC Runtime topology](docs/architecture/rsc-runtime-workbench.md). Native -evaluation evidence is example-owned, reuses an already signed-in host session -when a contributor runs it, and never accepts or stores API keys. - -## Developer workbench and Agent API - -`agent-bundle dev` is a loopback-only foreground session for inspecting source and published artifact -epochs, exercising artifact-bound MCP, hook, script, and native-host operations, and running evals. -It never becomes part of a generated artifact. - -The same foreground session is available programmatically through the public `startDevServer` -export. It accepts the options the CLI flags map to (`root`, `port`, `open`, `agentApi`) and -resolves to a `DevServerSession` exposing the loopback `url`, a `status()` snapshot, and `close()`: - -```ts -import { startDevServer } from 'agent-bundle'; - -const session = await startDevServer({ root: process.cwd(), port: 3100 }); -console.log(session.url); -await session.close(); -``` - -The Playground is the durable whole-plugin workflow. `script.run` is available there for trusted -local use: it selects a manifest-owned emitted script for the selected target and records its exit, -bounded stdout/stderr, cancellation, and epoch-bound evidence. Native prompts select a -server-cataloged case, fixture, host, and pinned model for that epoch; they do not accept a browser -provided command or model. Completed Playground sessions can replay or export their ordered raw -event references and promote selected durable evidence into a draft eval case. - -The Hook and MCP pages also execute generated artifacts, but their independent operations do not -silently join an open Playground session. Start the operation from Playground when it must form part -of the ordered export or a promoted draft. Logs stay grouped by producer (build, diagnostics, MCP, -hook, host, and grader) with raw stdout/stderr and protocol streams available as evidence. The MCP -page opens an epoch-bound generated-server session, supports cancellation and explicit **Restart**, -and previews a compatible MCP App through that same session. - -The optional Agent API exposes a fixed Streamable HTTP MCP endpoint at `/mcp` on that same foreground -URL. It is disabled by default. Enable it with `--agent-api` (or set `dev: { agentApi: true }` in the -project config) only after setting a fixed bearer secret: +Then build, or work interactively: ```sh -AGENT_BUNDLE_AGENT_API_TOKEN='replace-with-a-secret' agent-bundle dev --agent-api --no-open --port 3100 +npx agent-bundle build --root . --output dist # write installable artifacts +npx agent-bundle dev --root . # local workbench with live rebuilds ``` -`--no-agent-api` overrides config enablement. The endpoint accepts standard `Authorization: Bearer` -authentication, allows Codex clients without an `Origin` header, and rejects a browser-origin request -unless it is exactly the foreground origin. The token is read once at startup and is never logged, -persisted, or returned. A running endpoint uses the same URL and token across foreground restarts; -its stateless MCP transport lets an initialized client issue later requests when the foreground -server returns. +`targets: ['plugin']` emits one multi-host bundle at `dist/plugin/`: `.claude-plugin/`, `.codex-plugin/`, and `.cursor-plugin/` manifests over shared `skills/`, `hooks/`, `mcp/`, and `scripts/` directories. The bundle's generated `AGENTS.md` explains how to install it into each host. Per-host layouts are available as the `claude`, `codex`, `cursor`, and `portable` targets. -The API exposes exactly thirteen stable tools: `project_status`, `skills_list`, `skill_inspect`, -`artifacts_list`, `artifact_inspect`, `mcp_servers_list`, `mcp_invoke`, `hooks_list`, -`hook_simulate`, `evals_list`, `eval_run`, `eval_get`, and `diagnostics_list`. `eval_run` admits -deterministic evals only; native-harness choice is never an Agent API input. Their schemas reject -undeclared fields, so clients cannot name filesystem roots, artifact paths, commands, working -directories, environments, harnesses, or browser-authored evidence/outcomes. Omitted artifact epochs -bind atomically to the active publication; in-flight and explicitly selected epoch operations stay -pinned until they complete. A hot rebuild sends new calls to the new active epoch, while an open -generated MCP session remains bound to its original epoch until it is closed or explicitly restarted. -Host MCP catalog changes can require that host to reload its MCP connection; Agent Bundle does not -use `notifications/tools/list_changed` as a workbench HMR mechanism. +## Commands -Rsbuild UI HMR is contributor-only. It runs through -`AGENT_BUNDLE_WORKBENCH_API_PROXY= pnpm --filter agent-bundle-workbench dev`, -whose `packages/workbench/scripts/dev.mjs` wrapper refuses to start without the foreground API -proxy. Published `agent-bundle dev` serves prebuilt assets and live project events instead. +- `build` — validate the project and write an artifact +- `validate` — check project source, or a built artifact with `--artifact ` +- `inspect` — show the normalized configuration and per-target plans +- `dev` — serve the local development workbench +- `mcp list` / `mcp invoke` — operate an artifact's MCP server locally +- `hooks list` / `hooks simulate` — inspect and simulate generated hooks +- `eval` — run eval suites against a built artifact -## Configuration +The [package README](packages/agent-bundle/README.md) is the full reference: configuration semantics, the workbench, the optional Agent API, evals, and limitations. -Create `agent-bundle.config.ts` at the project root. `defineConfig` is available from `agent-bundle/config` for type checking: +## Examples -```ts -import { defineConfig } from 'agent-bundle/config'; - -export default defineConfig({ - plugin: { - name: 'review-tools', - version: '1.0.0', - description: 'Review helpers for an agent host.', - }, - targets: ['portable', 'codex', 'claude', 'cursor'], // or ['plugin'] for the unified multi-host bundle - skills: ['skills/*'], - scripts: { - report: './src/report.ts', - bootstrap: { entry: './scripts/bootstrap.sh', targets: ['codex', 'claude'] }, - migrate: './scripts/migrate.py', - }, - hooks: { - sessionStart: { handler: './src/session-start.ts' }, - }, - mcp: { - servers: { - local: { - entry: './src/mcp.ts', - apps: { - dashboard: { - entry: './views/dashboard.ts', - resourceUri: 'ui://review-tools/dashboard.html', - targets: ['portable'], - _meta: { ui: { prefersBorder: true } }, - }, - }, - }, - remote: { - transport: 'streamable-http', - url: 'https://example.invalid/mcp', - }, - }, - }, -}); -``` - -`scripts` is a record: its key is the stable output name and each value is either an entry path or `{ entry, targets? }`. JavaScript-family entries (`.js`, `.jsx`, `.mjs`, `.cjs`, `.ts`, `.tsx`, `.mts`, `.cts`) are bundled. Shell and Python entries (`.sh`, `.bash`, `.py`) are copied byte-for-byte and keep the source permission mode. Every target receives selected scripts at `scripts/.mjs` for bundled entries or `scripts/` for copied entries. - -Skills follow the Agent Skills directory layout and may contain references and binary assets. Local MCP server entries and hook handlers are bundled. A local MCP App may import its generated browser resource list with `import apps from 'agent-bundle/mcp-apps'`; the generated resource uses the configured `resourceUri` and metadata. Several local servers may serve one shared app by declaring the same app name with an identical definition (`entry`, `resourceUri`, `template`, `_meta`; `targets` may differ per server): the view compiles into one `mcp-apps/.html` output and every declaring server's registry includes it. Conflicting redeclarations of an app name, or one `resourceUri` spread across different app names, stay rejected. - -The compiler rejects unsafe output names, unsupported extensions, nonexistent or escaping source paths, unknown targets, and output collisions before it stages an artifact. It does not call Codex, Claude, or another host CLI, and it does not require API keys. - -### Adapter-owned extensions - -Ordinary projects need no runtime extension key. `AgentBundleConfig` explicitly -intersects the bundled portable, Codex, and Claude extension interfaces through -`AgentBundleConfigExtensions`, so packed declarations retain their author -fields. `TargetRegistry` owns each unique descriptor and adapter. Extension -values are strict finite JSON; host-specific values belong to their adapter. A -new host registers an adapter and exports/merges its interface rather than adding -a raw compiler or Runtime configuration parser. ChatGPT/OpenAI and Claude -Workbench profiles are local simulation profiles, not configuration-extension -claims. - -## Artifact contract - -Artifacts use stable, unhashed script output names. A representative tree is: - -```text -artifact/ - agent-bundle.manifest.json - agent-bundle.hooks.json - portable/ - plugin.json - scripts/.mjs - skills//... - mcp.json - mcp-apps/.html - codex/ - .codex-plugin/plugin.json - .mcp.json - scripts/.mjs - hooks/.mjs - claude/ - .claude-plugin/plugin.json - .mcp.json - scripts/.mjs - hooks/.mjs - cursor/ - .cursor-plugin/plugin.json - mcp.json - scripts/.mjs - hooks/.mjs - skills//... -``` - -`agent-bundle.manifest.json` records each emitted file's path, byte length, and SHA-256 digest. This allows `validate --artifact` and artifact operations to run after the source project is no longer present. - -Portable artifacts contain portable plugin, skills, MCP, and App-resource files. Codex and Claude artifacts contain their respective native metadata and generated hook wrappers. Cursor artifacts contain the `.cursor-plugin/plugin.json` manifest, the auto-discovered `mcp.json` (Cursor's typeless server format), the flat versioned `hooks/hooks.json` with Cursor-codec wrappers, and shared skills, scripts, and assets. Terminal hosts can use normal MCP tools and resources; visual rendering of an MCP App depends on the host supporting the standard resource metadata. - -Every emitted stdio MCP server entry carries an `AGENT_BUNDLE_PLUGIN_ROOT` environment variable holding the plugin install root in the target's native spelling (`${CLAUDE_PLUGIN_ROOT}`, `${PLUGIN_ROOT}`, `${CURSOR_PLUGIN_ROOT}`, or Codex's `./` resolved against the entry's plugin-root `cwd`); server runtime code should resolve persistent state against this anchor rather than the process working directory, and a server's own `env` entries win over the injected value. See the [package README](packages/agent-bundle/README.md) for the exact per-target semantics. - -## Public examples - -The repository includes credential-free public example workspaces. Each -uses only the public `agent-bundle` CLI and package exports, exactly as an -external project would. The Workbench is a desktop product; these walkthroughs -and its acceptance suite use a 1440×900 desktop viewport. - -| Example | Start here when you want to… | Command | +| Example | What it shows | Run | | --- | --- | --- | -| [Skills Starter](examples/skills-starter) | author a release-review Skill and deterministic evidence | `pnpm example:skills` | -| [Hooks and Scripts](examples/hooks-and-scripts) | simulate a Hook and inspect successful and blocking script traces | `pnpm example:hooks` | -| [MCP App](examples/mcp-app) | exercise a degraded service result in an interactive App and deterministic eval | `pnpm example:mcp-app` | -| [Audiobook Curator](examples/audiobook-curator) | inspect, safely prepare, and audit local audiobook media through Claude or Codex | `pnpm example:audiobook` | +| [Skills Starter](examples/skills-starter) | author a release-review skill with deterministic evidence | `pnpm example:skills` | +| [Hooks and Scripts](examples/hooks-and-scripts) | simulate a hook and inspect script traces | `pnpm example:hooks` | +| [MCP App](examples/mcp-app) | an interactive MCP App with a deterministic eval | `pnpm example:mcp-app` | +| [Audiobook Curator](examples/audiobook-curator) | a real media-management plugin for Claude or Codex | `pnpm example:audiobook` | -Run these commands from the repository root. The filtered package command runs -inside the selected example, so `agent-bundle` infers that example directory as -its project root. `pnpm examples:check` performs every example's noninteractive -validation and build. To run a command from an example directly, first `cd` to -that example; its package-local `pnpm validate`, `pnpm build`, and `pnpm dev` -commands infer the same root. +Run these from the repository root. `pnpm examples:check` validates and builds every example noninteractively. -Every Workbench starts on **Overview**, the Bundle dashboard: **Author** points -to Skills and Hooks, **Build** to Artifacts, **Exercise** to Skills, Hooks, -Playground, and MCP, and **Evaluate** to Evals and Comparisons. The pages show -different evidence rather than alternative launchers: - -- **Skills** compares authored source, linked resources, generated output, and - declared eval coverage. -- **Hooks** simulates canonical host input and replays the saved epoch-bound - input. **Playground** runs an emitted capability and retains its durable - trace; **Logs** exposes those producer records and raw details. -- **Artifacts** shows the selected target's emitted files and provenance. - **Comparisons** needs two recorded eval runs before it can align outcomes. -- **MCP playground** opens an epoch-bound generated-server session, invokes - tools, shows the protocol trace, and renders a compatible MCP App. **Evals** - runs the selected deterministic case against checked-in fixtures. - -The per-example walkthroughs record the actual initial selections and a safe -diagnostic repair loop. Wait for a completed, failed, or idle state before -capturing or judging a Workbench result; a loading/building state is not a -durable outcome. - -## Contributor delivery and release gates - -From this repository, run the complete local delivery gate with: - -```sh -pnpm check && pnpm check:release -``` +## Development -`pnpm check:release` is the release-only gate: it runs `pnpm pack:dry-run`, -`pnpm audit:release`, and `pnpm test:packed`; it does not replace `pnpm check`. +`pnpm check` runs the local delivery gate (build, unit and integration tests, lint, typecheck); `pnpm check:release` adds the packaging gates. Versioning goes through Changesets. Native Claude/Codex host smokes are opt-in and intentionally skipped in CI. The Workbench architecture and the optional RSC runtime are documented in [docs/architecture/rsc-runtime-workbench.md](docs/architecture/rsc-runtime-workbench.md). -Native Claude/Codex host smokes are intentionally opt-in and stay skipped in CI. They run only on a -machine with that CLI installed and signed in — via `AGENT_BUNDLE_NATIVE_CLAUDE_SMOKE=1` / -`AGENT_BUNDLE_NATIVE_CODEX_SMOKE=1`, the packed variants `pnpm test:packed:native:claude` / -`pnpm test:packed:native:codex`, or the manually dispatched self-hosted **Native host smoke** -workflow. A skipped native smoke in CI is the intended state, not a delivery gap. +## Status -Repository-owned Chromium E2E runs independently of a connected ChatGPT Chrome extension. The -extension is for the separate final manual visual pass, not a substitute for repository or packed -consumer verification. Package versions and release PRs use Changesets. Add a changeset with -`pnpm changeset`; merges to `main` update or publish through the standard Changesets action. Pull -requests and every push to `main` publish `agent-bundle` and `@agent-bundle/rsc-runtime` canaries -through pkg.pr.new — the interim release channel while npm publishing waits on the final package -name (see [Preview packages](docs/preview-packages.md)). +Pre-release. The final npm package name and license are not yet chosen; pkg.pr.new previews are the release channel until then. From 7fe528020bd0a55f8f10222bfef1ea583e2c5bbf Mon Sep 17 00:00:00 2001 From: ScriptedAlchemy Date: Mon, 31 Aug 2026 02:15:01 +0000 Subject: [PATCH 2/3] docs(readme): qualify which SHAs have preview tarballs (Codex review) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1294d4144..8ebe2c832 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Nothing is published to npm yet (the `agent-bundle` name on npm currently belong npm i -D https://pkg.pr.new/ScriptedAlchemy/agent-bundle/agent-bundle@ ``` -Any `main` commit SHA or PR number works. See [Preview packages](docs/preview-packages.md) for pinning and details. +Use a PR number or the SHA of a commit whose package-preview run succeeded (every green `main` commit has one). See [Preview packages](docs/preview-packages.md) for pinning and details. ## Quick start From 7f58fb4625636cd5fae689c253b4e1c25e6781bb Mon Sep 17 00:00:00 2001 From: ScriptedAlchemy Date: Mon, 31 Aug 2026 02:30:25 +0000 Subject: [PATCH 3/3] test(api): pin the documented MCP App resourceUri to the mcp-app example config --- packages/agent-bundle/tests/api.test.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/agent-bundle/tests/api.test.ts b/packages/agent-bundle/tests/api.test.ts index 3a7cce86b..8798fa543 100644 --- a/packages/agent-bundle/tests/api.test.ts +++ b/packages/agent-bundle/tests/api.test.ts @@ -1080,8 +1080,12 @@ it('canonicalizes copied script extensions in emitted artifact paths', async () it('documents a versioned MCP App resource URI accepted by source validation', async () => { const parent = await mkdtemp(join(tmpdir(), 'agent-bundle-readme-uri-parent-')); const root = join(parent, 'project'); - const readme = await readFile(join(process.cwd(), 'README.md'), 'utf8'); - const resourceUri = /resourceUri: '([^']+)'/u.exec(readme)?.[1]; + const documentedConfig = await readFile( + join(process.cwd(), 'examples', 'mcp-app', 'agent-bundle.config.ts'), + 'utf8', + ); + const resourceUri = /resourceUri: '([^']+)'/u.exec(documentedConfig)?.[1]; + expect(resourceUri).toBeDefined(); await mkdir(join(root, 'src'), { recursive: true }); await mkdir(join(root, 'views'), { recursive: true }); await Promise.all([