[GH-ISSUE #4933] [Design] Project captures into an environment manifest, serve it over streamable HTTP, export agent-environment bundles #3060

Closed
opened 2026-10-31 00:35:41 +00:00 by bsakaguchi · 4 comments
Owner

Originally created by @earakely-scale on GitHub (Oct 18, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/4933

Before submitting

  • I searched the open and closed issues and pull requests for a related discussion.
  • I understand the contribution scope must be reviewed before integration; open questions are welcome here.
  • This discussion does not include credentials, private samples, or sensitive target data.

Decision needed

Should REA (1) project retained web network capture Evidence into a canonical environment manifest analysis view, (2) optionally serve its MCP catalog over streamable HTTP behind an explicit rea mcp --http flag, (3) serve a manifest as an agent environment (rea environment-serve) that replays recorded exchanges with provenance, and (4) export a manifest as a bundle folder (rea environment-export) that the open-source agentenv framework can run with agent-env run? Each of the four can be decided independently; (1) is a pure analysis view, (2) and (3) add an inbound loopback listener, (4) adds a CI lane that needs Docker and a pinned Python package.

Context and evidence

Observed. REA's api-surface view already recovers an application's request-line inventory from a HAR capture. We ran the published rea-agents@6.5.0 against a Playwright 1.58.2 capture of one browsing session on a self-hosted Grafana 13.2.4 (open source, run locally, admin credentials only, login exchange dropped and secret body fields scrubbed before inspection): 305 records → 99 api-surface groups. A small external generator turned those groups plus the recorded exchanges into an MCP environment with 73 tools that the agentenv framework deployed through its gateway and verified end to end (four tool calls returned the recorded answers). Checked against the OpenAPI document Grafana serves itself, 16 of 16 templated path segments agreed with the spec's parameter positions; 0 were over-templated, 0 missed. The full 305-record capture exceeded the api-surface 96 MiB projection budget, so inspection ran in eight 40-record chunks.

Source-derived. createServer() and EvidenceMcpServer.connect(transport) are transport-agnostic; only src/main.ts binds serveStdio. The already-pinned @modelcontextprotocol/server@2.3.1 root export ships WebStandardStreamableHTTPServerTransport, so streamable HTTP needs a ~40-line node:http ↔ web Request/Response bridge and no new dependency. BinarySession owns one active target per process, so an HTTP mode is a one-client, one-session transport. REA's four template rules (numeric, uuid, hex, iso-date) leave Grafana's 14-character opaque UIDs and plugin identifiers literal, which the external generator covered with three extra rules.

Proposed. Everything REA does stays local and deterministic and produces ordinary files; running the result is the user's choice. Replay serving is not a replay engine in the orchestration sense: it answers each tool call with one retained record, cites the Evidence id and record ordinal, keeps _meta.provenance.untrusted_content, and executes nothing. The manifest carries explicit unknowns (authorization model, response semantics beyond recorded exchanges, state transitions) instead of inventing behavior.

Unknown. Whether the maintainer considers any inbound listener in scope given "REA is a local-only reverse-engineering tool"; whether a hosted lane that installs a pinned third-party Python package and builds a Docker image is acceptable; whether JavaScript application, EVM, WASM and SQLite Evidence should feed the same manifest view later (the view envelope is single-parent today).

Expected interaction with targets

  • Read existing files or captured data (all four)
  • Contact network services (2 and 3 only: an inbound HTTP listener bound to 127.0.0.1 by default; no outbound requests; 0.0.0.0 must be requested explicitly)
  • Write or change files/configuration (4 only: writes a new folder the caller names)

Boundary details (optional)

Non-goals: no outbound network calls; no process launch or attach by the serve runtime; no target execution; no change to server.json, rea setup registrations or installation docs, which stay stdio. The HTTP listener serves one session; host-header validation uses the SDK's localhost allow-list for loopback binds and is relaxed only when the caller binds a non-loopback host, which is logged. The manifest view inherits api-surface's sensitive-value refusal and byte budgets. Export writes the parent capture Evidence beside the manifest so the served environment can prove the manifest matches the Evidence it was projected from (ids must agree at startup).

Options and tradeoffs

  • Manifest as a view kind vs a new tool. A view kind reuses the single-parent inspect_analysis_view envelope, budgets and Evidence wrapping, and adds no catalog bytes beyond the request schema. A new tool would allow multi-parent fusion now but costs catalog tokens; we propose the view first and multi-parent fusion as a later decision.
  • Opt-in template rules vs defaults. The three extra rules (after-uid-literal, opaque-token, sibling-variance) are off unless requested in the view and are labelled per parameter, so default output stays as conservative as api-surface.
  • SDK transport + node bridge vs @modelcontextprotocol/node. The bridge is small and adds no dependency; the node package pulls hono and lags the server package version.
  • Bodies in the manifest vs beside it. Keeping bodies out of the derived view avoids copying target content into inferred Evidence and keeps the view inside the projection budget; the runtime reads bodies from the parent Evidence file by ordinal.
  • Flat command names. environment-serve and environment-export follow evidence-export/evidence-import; no nested command groups.
  • Spec placement. docs/specs/agent-environments/<slice>/{spec,plan,tasks,verification}.md with an Issue: line, following the multi-increment precedent, so one issue covers four small PRs.

Verification available so far

I have a prototype or observed results

Success criteria and open questions

  • rea inspect-analysis-view with view.kind = "environment-manifest" on the existing HAR fixtures yields a manifest whose templates match api-surface exactly when no extra rule is requested, and whose extra-rule parameters are each labelled with their rule.
  • rea mcp --http passes initialize, tools/list, one tool call and DELETE from the Python mcp streamable HTTP client, and refuses non-loopback hosts unless asked.
  • rea environment-serve serves the env card and replays the Grafana-shaped fixture; rea environment-export plus agent-env run <dir> passes the exported smoke task on a hosted Ubuntu runner.
  • Open: should the serve runtime expose a reset operation on the data plane, or stay stateless? Should REA ever template opaque identifiers by default?

References

Originally created by @earakely-scale on GitHub (Oct 18, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/4933 ### Before submitting - [x] I searched the open and closed issues and pull requests for a related discussion. - [x] I understand the [contribution scope](https://github.com/morluto/rea/blob/main/CONTRIBUTING.md#contribution-scope) must be reviewed before integration; open questions are welcome here. - [x] This discussion does not include credentials, private samples, or sensitive target data. ### Decision needed Should REA (1) project retained web network capture Evidence into a canonical **environment manifest** analysis view, (2) optionally serve its MCP catalog over **streamable HTTP** behind an explicit `rea mcp --http` flag, (3) **serve a manifest as an agent environment** (`rea environment-serve`) that replays recorded exchanges with provenance, and (4) **export** a manifest as a bundle folder (`rea environment-export`) that the open-source agentenv framework can run with `agent-env run`? Each of the four can be decided independently; (1) is a pure analysis view, (2) and (3) add an inbound loopback listener, (4) adds a CI lane that needs Docker and a pinned Python package. ### Context and evidence **Observed.** REA's `api-surface` view already recovers an application's request-line inventory from a HAR capture. We ran the published `rea-agents@6.5.0` against a Playwright 1.58.2 capture of one browsing session on a self-hosted Grafana 13.2.4 (open source, run locally, admin credentials only, login exchange dropped and secret body fields scrubbed before inspection): 305 records → 99 api-surface groups. A small external generator turned those groups plus the recorded exchanges into an MCP environment with 73 tools that the agentenv framework deployed through its gateway and verified end to end (four tool calls returned the recorded answers). Checked against the OpenAPI document Grafana serves itself, 16 of 16 templated path segments agreed with the spec's parameter positions; 0 were over-templated, 0 missed. The full 305-record capture exceeded the `api-surface` 96 MiB projection budget, so inspection ran in eight 40-record chunks. **Source-derived.** `createServer()` and `EvidenceMcpServer.connect(transport)` are transport-agnostic; only `src/main.ts` binds `serveStdio`. The already-pinned `@modelcontextprotocol/server@2.3.1` root export ships `WebStandardStreamableHTTPServerTransport`, so streamable HTTP needs a ~40-line `node:http` ↔ web `Request`/`Response` bridge and no new dependency. `BinarySession` owns one active target per process, so an HTTP mode is a one-client, one-session transport. REA's four template rules (numeric, uuid, hex, iso-date) leave Grafana's 14-character opaque UIDs and plugin identifiers literal, which the external generator covered with three extra rules. **Proposed.** Everything REA does stays local and deterministic and produces ordinary files; running the result is the user's choice. Replay serving is not a replay *engine* in the orchestration sense: it answers each tool call with one retained record, cites the Evidence id and record ordinal, keeps `_meta.provenance.untrusted_content`, and executes nothing. The manifest carries explicit `unknowns` (authorization model, response semantics beyond recorded exchanges, state transitions) instead of inventing behavior. **Unknown.** Whether the maintainer considers any inbound listener in scope given "REA is a local-only reverse-engineering tool"; whether a hosted lane that installs a pinned third-party Python package and builds a Docker image is acceptable; whether JavaScript application, EVM, WASM and SQLite Evidence should feed the same manifest view later (the view envelope is single-parent today). ### Expected interaction with targets - Read existing files or captured data (all four) - Contact network services (2 and 3 only: an inbound HTTP listener bound to 127.0.0.1 by default; no outbound requests; `0.0.0.0` must be requested explicitly) - Write or change files/configuration (4 only: writes a new folder the caller names) ### Boundary details (optional) Non-goals: no outbound network calls; no process launch or attach by the serve runtime; no target execution; no change to `server.json`, `rea setup` registrations or installation docs, which stay stdio. The HTTP listener serves one session; host-header validation uses the SDK's localhost allow-list for loopback binds and is relaxed only when the caller binds a non-loopback host, which is logged. The manifest view inherits `api-surface`'s sensitive-value refusal and byte budgets. Export writes the parent capture Evidence beside the manifest so the served environment can prove the manifest matches the Evidence it was projected from (ids must agree at startup). ### Options and tradeoffs - **Manifest as a view kind vs a new tool.** A view kind reuses the single-parent `inspect_analysis_view` envelope, budgets and Evidence wrapping, and adds no catalog bytes beyond the request schema. A new tool would allow multi-parent fusion now but costs catalog tokens; we propose the view first and multi-parent fusion as a later decision. - **Opt-in template rules vs defaults.** The three extra rules (`after-uid-literal`, `opaque-token`, `sibling-variance`) are off unless requested in the view and are labelled per parameter, so default output stays as conservative as `api-surface`. - **SDK transport + node bridge vs `@modelcontextprotocol/node`.** The bridge is small and adds no dependency; the node package pulls hono and lags the server package version. - **Bodies in the manifest vs beside it.** Keeping bodies out of the derived view avoids copying target content into inferred Evidence and keeps the view inside the projection budget; the runtime reads bodies from the parent Evidence file by ordinal. - **Flat command names.** `environment-serve` and `environment-export` follow `evidence-export`/`evidence-import`; no nested command groups. - **Spec placement.** `docs/specs/agent-environments/<slice>/{spec,plan,tasks,verification}.md` with an `Issue:` line, following the multi-increment precedent, so one issue covers four small PRs. ### Verification available so far I have a prototype or observed results ### Success criteria and open questions - `rea inspect-analysis-view` with `view.kind = "environment-manifest"` on the existing HAR fixtures yields a manifest whose templates match `api-surface` exactly when no extra rule is requested, and whose extra-rule parameters are each labelled with their rule. - `rea mcp --http` passes initialize, tools/list, one tool call and DELETE from the Python `mcp` streamable HTTP client, and refuses non-loopback hosts unless asked. - `rea environment-serve` serves the env card and replays the Grafana-shaped fixture; `rea environment-export` plus `agent-env run <dir>` passes the exported smoke task on a hosted Ubuntu runner. - Open: should the serve runtime expose a reset operation on the data plane, or stay stateless? Should REA ever template opaque identifiers by default? ### References - https://github.com/morluto/rea/blob/main/docs/web-network-captures.md#derived-api-surface - https://github.com/morluto/rea/blob/main/docs/tool-design.md - https://github.com/morluto/rea/blob/main/docs/mcp-contracts.md - https://github.com/scaleapi/agentenv-framework (the framework that runs the exported bundles; its `echo-mcp` example is the bundle shape we mirror) - MCP streamable HTTP transport: https://modelcontextprotocol.io/specification/2025-11-25/basic/transports
Author
Owner

@XinwangTao commented on GitHub (Oct 18, 2026):

Nice direction — the separation into four independently decidable items is the right framing. (1) as a pure analysis view is clearly safe and useful: it turns an already-recovered request-line inventory into a reusable contract artifact without any new runtime surface. I'd also like (4): exporting a bundle that agentenv can run is the strongest end-to-end validation of the manifest format itself, and making the verification reproducible (pinned Python package + Docker CI lane) keeps that signal trustworthy. For (2)/(3), since both add a loopback listener, one concern is lifetime and safety: binding only on 127.0.0.1, refusing cross-origin requests, and tying the server's lifecycle to the explicit flag (or to a short-lived, automatically-terminated process) would keep this from becoming a footgun for users who run rea mcp unattended. Also worth clarifying how secrets in recorded exchanges are handled when exporting a bundle — the scrubbing you did for Grafana should probably be an enforced step, not a manual one, before environment-export writes anything to disk.

<!-- gh-comment-id:6244127293 --> @XinwangTao commented on GitHub (Oct 18, 2026): Nice direction — the separation into four independently decidable items is the right framing. (1) as a pure analysis view is clearly safe and useful: it turns an already-recovered request-line inventory into a reusable contract artifact without any new runtime surface. I'd also like (4): exporting a bundle that agentenv can run is the strongest end-to-end validation of the manifest format itself, and making the verification reproducible (pinned Python package + Docker CI lane) keeps that signal trustworthy. For (2)/(3), since both add a loopback listener, one concern is lifetime and safety: binding only on 127.0.0.1, refusing cross-origin requests, and tying the server's lifecycle to the explicit flag (or to a short-lived, automatically-terminated process) would keep this from becoming a footgun for users who run `rea mcp` unattended. Also worth clarifying how secrets in recorded exchanges are handled when exporting a bundle — the scrubbing you did for Grafana should probably be an enforced step, not a manual one, before `environment-export` writes anything to disk.
Author
Owner

@XinwangTao commented on GitHub (Oct 18, 2026):

Two cents on the open questions: (1) keep the serve runtime stateless for v1 — a replay environment's value is deterministic, idempotent answers; a reset operation on the data plane implies mutable session state that agentenv would have to discover and use consistently, which complicates the bundle contract. Stateless replay keeps the exported bundle self-contained (state lives in the parent Evidence plus the manifest). (2) On templating opaque identifiers by default: keep it opt-in via the extra rules as proposed. Default templating of unknown-shaped identifiers would silently over-generalize paths in captures where the literal is actually part of the resource model — the Grafana 14-char UID is a good example of the former, but plenty of APIs have semantically meaningful path segments that don't match the four built-in rules. Label-and-opt-in keeps api-surface conservative and lets the caller decide per view.

<!-- gh-comment-id:6247559682 --> @XinwangTao commented on GitHub (Oct 18, 2026): Two cents on the open questions: (1) keep the serve runtime stateless for v1 — a replay environment's value is deterministic, idempotent answers; a reset operation on the data plane implies mutable session state that agentenv would have to discover and use consistently, which complicates the bundle contract. Stateless replay keeps the exported bundle self-contained (state lives in the parent Evidence plus the manifest). (2) On templating opaque identifiers by default: keep it opt-in via the extra rules as proposed. Default templating of unknown-shaped identifiers would silently over-generalize paths in captures where the literal is actually part of the resource model — the Grafana 14-char UID is a good example of the former, but plenty of APIs have semantically meaningful path segments that don't match the four built-in rules. Label-and-opt-in keeps api-surface conservative and lets the caller decide per view.
Author
Owner

@earakely-scale commented on GitHub (Oct 18, 2026):

@morluto, requesting a scope decision on the four items above, now that each has a PR to read:

  1. Environment-manifest analysis view: #4954. A projection of retained web-network Evidence; launches nothing, contacts nothing. Ready for review.
  2. Streamable HTTP transport for the MCP server: #4955. Opt-in flag; binds a port only when asked.
  3. environment-serve: #4975. Serves a manifest as a replay MCP server; reads two Evidence files once, binds one port, executes nothing from the captured application.
  4. environment-export plus the hosted real-agentenv lane: #4999. Writes a bundle folder at the path the caller names; the lane installs a pinned Python package and builds a Docker image on the runner, which is the second question asked above.

Items 1 and 2 stand alone; 3 stacks on both; 4 stacks on 3, so a decision on 1 and 2 alone would already let the first two merge.

What the four items produce end to end, built with the prerelease from these branches and published so it can be inspected: five replay environments generated from one recorded browser session each against self-hosted Grafana, Gitea, NocoDB, Mattermost and Ghost, with synthetic data.

Happy to narrow any item or split the lane into its own PR if that helps the decision.

<!-- gh-comment-id:6251096757 --> @earakely-scale commented on GitHub (Oct 18, 2026): @morluto, requesting a scope decision on the four items above, now that each has a PR to read: 1. **Environment-manifest analysis view**: #4954. A projection of retained web-network Evidence; launches nothing, contacts nothing. Ready for review. 2. **Streamable HTTP transport for the MCP server**: #4955. Opt-in flag; binds a port only when asked. 3. **`environment-serve`**: #4975. Serves a manifest as a replay MCP server; reads two Evidence files once, binds one port, executes nothing from the captured application. 4. **`environment-export` plus the hosted `real-agentenv` lane**: #4999. Writes a bundle folder at the path the caller names; the lane installs a pinned Python package and builds a Docker image on the runner, which is the second question asked above. Items 1 and 2 stand alone; 3 stacks on both; 4 stacks on 3, so a decision on 1 and 2 alone would already let the first two merge. **What the four items produce end to end**, built with the prerelease from these branches and published so it can be inspected: five replay environments generated from one recorded browser session each against self-hosted Grafana, Gitea, NocoDB, Mattermost and Ghost, with synthetic data. - Collection: https://huggingface.co/collections/earakely-scale/rea-environments-on-agentenv - Pipeline, cards and results: https://github.com/earakely-scale/rea-environments - 226 tools over 512 recorded exchanges across the five manifests; 12 deterministic retrieval tasks per environment; 118 of 120 recorded episodes passed across two models, and the two misses are model errors explained in the cards. Happy to narrow any item or split the lane into its own PR if that helps the decision.
Author
Owner

@morluto commented on GitHub (Oct 26, 2026):

Thank you for separating the scope decisions and supplying the end-to-end examples. The four proposed slices have now landed: the manifest view in #4954, streamable HTTP in #4955, replay serving in #4975, and bundle export plus agentenv verification in #4999. The serving implementation records its limits, including historical replay without application-state reconstruction. Closing this design request as completed; future extensions or different replay semantics can be discussed separately.

<!-- gh-comment-id:6427794592 --> @morluto commented on GitHub (Oct 26, 2026): Thank you for separating the scope decisions and supplying the end-to-end examples. The four proposed slices have now landed: the manifest view in #4954, streamable HTTP in #4955, replay serving in #4975, and bundle export plus agentenv verification in #4999. The serving implementation records its limits, including historical replay without application-state reconstruction. Closing this design request as completed; future extensions or different replay semantics can be discussed separately.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#3060
No description provided.