Skip to content

feat: prebuilt payload adapter mode (RFC #50 Phase 3) - #71

Merged
ScriptedAlchemy merged 9 commits into
mainfrom
feat/prebuilt-payload-adapters
Aug 31, 2026
Merged

feat: prebuilt payload adapter mode (RFC #50 Phase 3)#71
ScriptedAlchemy merged 9 commits into
mainfrom
feat/prebuilt-payload-adapters

Conversation

@ScriptedAlchemy

Copy link
Copy Markdown
Owner

Summary

Implements the deferred "prebuilt payload" adapter mode — RFC #50 Phase 3, the examples-phase2 plan's Q9 — and migrates examples/rsc-agent-runtime off its hand-rolled host packaging in the same PR as proof.

Config surface

  • Top-level payload blockpayload: { runtime: './dist/runtime', app: { source: './dist/app', targets: [...] } }. Each key names an artifact-root destination directory; the whole source tree is packaged byte-for-byte into every selected target.
  • { prebuilt: ... } markers on mcp.servers.<name>.entry and hook handler point the generated host manifests at files inside a declared payload. Hooks additionally accept shell-safe args (e.g. ['--host', 'claude']) — prebuilt handlers only.
  • Stable paths, not content-hashing. The framework did not compile these files, so it cannot rewrite the references inside them — sibling chunk imports and worker entries resolved from import.meta.url (the reason this example compiles with splitChunks: false) — and hosts, manuals, and tests pin the entry paths. Integrity stays content-addressed anyway: every payload file lands in the artifact manifest with its SHA-256 under the new prebuilt file kind, and payload files hash into project.sourceInputs, so the project revision changes whenever payload bytes change.
  • Same adapter lowering. A prebuilt MCP entry normalizes to a command-shaped stdio server whose first argument is the payload path anchored on the plugin-root token, so all four adapters render it natively with zero adapter changes to the MCP documents (${CLAUDE_PLUGIN_ROOT}/runtime/mcp/stdio.js, Codex ./runtime/mcp/stdio.js + cwd: "./", ${PLUGIN_ROOT}/…), the AGENT_BUNDLE_PLUGIN_ROOT env anchor is injected as usual, and the existing MCP artifact-reference validator confirms the referenced payload file is present and manifested. Prebuilt hooks emit node "<root>/<payload path>" <args…> into the generated hooks/hooks.json and are packaged like native hooks (no compiled wrapper, not in the simulatable hook index).
  • Provenance — declaration provenance is recorded as kind: 'prebuilt'; manifest/ArtifactOutputKind gain the prebuilt file kind; prebuilt files are exempt from generated-content validation (bundled-ESM graph, strict generated JSON) but remain hash-locked to the manifest, and the AB6014 ownership check admits them by manifest kind.
  • Diagnostics (documented in docs/diagnostics.md): AB4740AB4742 config errors, AB4743/AB4745 warnings for not-yet-built payloads/entries (surfaced through validate; dev flows keep working from a clean checkout), AB4744/AB4746 reference/args errors, AB4747AB4749 build-time refusals (empty payload, absent prebuilt entry, payload/output overlap), AB4750 staleness info nudge.

Example migration (the consumer proof)

  • Deleted scripts/package-hosts.mjs (75 lines) and packaging/ (7 hand-rolled host manifests, 88 lines).
  • agent-bundle.config.ts is now the single declaration: payload trees, a prebuilt MCP entry, and one prebuilt hook per host (--host claude / --host codex) replacing the dual dev-config + native-hooks.json declaration; marketplace: true keeps the Codex marketplace document.
  • "build": "rsbuild build --mode production && agent-bundle build --json --output dist/plugins" — the demo's multi-environment RSC compilation stays untouched as the subject of the example.
  • rsbuild.config.ts pins the runtime flavor (mode: 'production'): previously the dev artifact epoch's bundler runs set NODE_ENV=production in-process before the provider session compiled, silently pinning production React; with nothing left to compile the flavor would float with ambient NODE_ENV (development React's Flight debug frames overflow the workbench's 4 KB preview cap).

Test-pin updates

  • docs-contract.test.ts — build-script pin updated in the same commit with rationale.
  • host-artifacts.test.ts — repackaging step is now agent-bundle build; manifests pin the config-owned identity (rsc-agent-runtime-demo/1.0.0), the timeline server key, canonical capability matchers (^(?:Write|Edit)$, ^(?:apply_patch|Edit|Write)$), the token-free-Codex guarantee restated as "no ${…} host tokens" (the env anchor is a plain variable name), and no empty skills/ directory. Stable entry paths and the exact hook command shape (node "${ROOT}/runtime/hook/index.js" --host <host>) are unchanged.
  • dev-provider.integration.test.ts — one prebuilt hook per host instead of one dual-target hook; the dev-epoch test provisions the payload it now packages.
  • runtime-playground.e2e.test.ts + fixture — the fixture provisions the example's Rsbuild payload; Hooks/Playground nav pages are hidden for this example (prebuilt hooks are packaged like native hooks).

Gate results

  • pnpm build, pnpm typecheck, pnpm lint — clean.
  • pnpm test:unit — 1760 passed (includes new prebuilt-payload.test.ts covering adapter lowering across claude/codex/portable, manifest provenance, artifact revalidation from disk, validation diagnostics, and the three build refusals).
  • examples:check — all examples green, including the migrated demo (176 tests: 170 passed, 6 platform skips).
  • examples-contract.test.ts, test:packed (22/22, manifest kind union extended), check:runtime-topology (doc regenerated for the deleted script), eval:spot — green.
  • Workbench runtime-playground/inspector/HMR/capture e2e — green in isolation; the 4-file parallel local run flakes identically-or-worse on main (5/8 vs 1/8) under load, so that instability is environmental, not introduced here.

Refs #50 (Phase 3, item: adapter prebuilt-payload mode / examples-phase2 Q9).

The `payload` config block declares already-built directory trees that
`agent-bundle build` packages byte-for-byte at stable paths, and
`{ prebuilt: ... }` markers point MCP server entries and hook handlers at
files inside those payloads. Prebuilt entries skip compilation but flow
through the same adapter lowering as compiled entries: path-token expansion
in every target MCP document, the injected env anchor, generated
hooks/hooks.json commands (with shell-safe prebuilt hook args), MCP
artifact-reference validation, and manifest provenance (new `prebuilt` file
kind; payload files hash into project.sourceInputs). New diagnostics:
AB4740-AB4746 at validate (missing payloads warn), AB4747-AB4749 as
build-time refusals, AB4750 staleness nudge.

examples/rsc-agent-runtime migrates in the same change: it deletes
scripts/package-hosts.mjs and packaging/, declares its Rsbuild output trees
as payloads with prebuilt MCP/hook entries, and packages hosts with
`agent-bundle build --json --output dist/plugins`. Its Rsbuild config pins
the runtime flavor (`mode: 'production'`) that was previously implied by
the epoch build's in-process NODE_ENV side effect.
@changeset-bot

changeset-bot Bot commented Aug 31, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: ced8257

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
agent-bundle Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 31, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-08-31T08:10:11.943488Z e180e17 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

…-adapters

# Conflicts:
#	docs/diagnostics.md
#	packages/agent-bundle/src/config/discover.ts
#	packages/agent-bundle/src/config/validate.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e180e17546

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/agent-bundle/src/adapters/hook-contract.ts
Comment thread packages/agent-bundle/src/dev/project-service.ts Outdated
Comment thread packages/workbench/src/runtime-client.ts Outdated
@pkg-pr-new

pkg-pr-new Bot commented Aug 31, 2026

Copy link
Copy Markdown
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle@71
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle/create-agent-bundle@71
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle/@agent-bundle/rsc-runtime@71

commit: ced8257

Wholesale invalidations (registry replay gap, runtime shutdown, foreground
replacement) and server-announced revocations now record the superseded
session revision before revoking bindings, and runtime previews degrade to
fallback instead of re-creating authority from superseded run evidence.
Also lands review follow-ups: prebuilt hook commands are exempt from the
AB6018 wrapper-index coherence check, validate-command diagnostics retain
warnings and infos, and runtime response debug logging is removed.
…s, e2e prebuilt entry

Prebuilt hook commands are exempt from the AB6018 wrapper-index coherence
check, validate-command diagnostics retain warnings and infos (AB4750 stays
visible), runtime response debug logging is removed, and the overview e2e
transport probe targets the prebuilt stdio entry shape.
…dation

A dev artifact epoch flip (for example a consumer compiler rewriting
prebuilt payload outputs beside the dev host) put the capability gate
back into its loading state, unmounting the whole workbench UI and any
live runtime preview with it. The remounted preview then re-created its
session binding from stale evidence, which surfaced as duplicate
POST /api/runtime/apps creates and teardown hangs in the overview e2e
suite. Keep the last known catalog rendered while the new epoch's
capabilities load (or fail), so revalidation is invisible to mounted
routes. This supersedes the session-superseded revision guard, which is
reverted here: with the UI stable across epochs, the preview never
remounts from stale evidence in the first place.
An argument-less prebuilt hook command parses exactly like a compiler
wrapper command; the coherence check recognizes it by payload location.
Pin that a build with such a hook validates and revalidates without
AB6018.
… narration

Reuse the exported isInside and isRecord helpers instead of the two
open-coded reimplementations in discover.ts and normalize.ts, drop the
type assertions the isPrebuiltEntryInput guard already narrows away,
collapse the duplicated empty-payload branches in discoverPayloads, and
extract the payload targets check so validatePayload stays shallow.

Write the two capability-state updates in main.tsx with the conditional
spread the rest of the codebase uses, rather than duplicating the object
literal per branch.

Comment edits keep one authoritative statement per rationale and drop
narration about what the branch changed.
@ScriptedAlchemy
ScriptedAlchemy merged commit 28830bd into main Aug 31, 2026
9 checks passed
@ScriptedAlchemy
ScriptedAlchemy deleted the feat/prebuilt-payload-adapters branch August 31, 2026 15:18
ScriptedAlchemy added a commit that referenced this pull request Aug 31, 2026
* refactor: simplify prebuilt-payload internals (post-#71 follow-up)

Deferred /simplify pass on PR #71's merged diff, applying the reviewer
findings that survived aggregation:

- Skip the AB4750 payload-freshness mtime walk unless the operator ran
  `validate` — every dev/inspect/build preparation was paying a blocking
  full-project stat sweep whose diagnostics were then discarded.
- Extract payloadDeclarationEntry/payloadDeclarationSource in discover.ts
  and consume them from configuredPayloadRoots, discoverPayloads,
  normalizePayloads, declaredPayloads, and validatePayload, replacing five
  open-coded copies with three divergent malformed-input policies.
- Extract owningPayload and share the innermost-payload ownership rule
  between prebuiltArtifactPath and validatePrebuiltReference, which had
  drifted to inside-or-equal semantics in validate.ts.
- Make PreparedProject.snapshotSource required so the artifact-service
  fallback that silently dropped payload roots (recreating the drift bug
  the closure exists to prevent) is unrepresentable.
- Probe prebuilt references against one Set of artifact paths, share the
  AB4748 emitter, reuse fast-glob stats over per-file stat calls, trust
  the declared hook-args type instead of silently filtering, and derive
  MCP-app prebuilt-ness from normalized provenance instead of raw config.
- Migrate prebuilt-payload.test.ts onto the shared project fixture
  helpers used by the sibling suites.

* chore: add patch changeset for the prebuilt-payload simplification

* chore: retrigger CI (previous run wedged in queue)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant