[PR #6946] [MERGED] feat(environment): build agent environments from a prompt #7466

Closed
opened 2026-11-01 21:48:03 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/6946
Author: @earakely-scale
Created: 10/24/2026
Status: ✅ Merged
Merged: 10/24/2026
Merged by: @morluto

Base: main ← Head: feat/environment-prompt


📝 Commits (10+)

  • da42a23 feat(environment): report what an environment serves with an environment-coverage view
  • cc290d9 feat(environment): build an environment bundle in one command
  • 045f14a test(environment): cover environment-build and the coverage view
  • cf7eb70 test(environment): build the real-agentenv lane's bundle with environment-build
  • 1e2c12e docs(environment): document environment-build and the coverage view
  • 093af31 fix(environment): harden environment-build after review
  • a040f01 docs(environment): state the build's conditions and record its verification
  • bc35ef3 fix(environment): dispatch a pending interrupt before each build stage check
  • 62368bd Merge remote-tracking branch 'origin/main' into eb
  • 33c37f6 feat(browser): send declared requests from a scenario page with a request step

📊 Changes

75 files changed (+7033 additions, -255 deletions)

View changed files

📝 .agents/skills/reverse-engineer-anything/SKILL.md (+8 -2)
➕ .agents/skills/reverse-engineer-anything/references/environments.md (+215 -0)
📝 .agents/skills/reverse-engineer-anything/references/evidence-workflows.md (+7 -0)
📝 docs/agent-environments.md (+232 -9)
📝 docs/browser-scenario-contract.md (+113 -3)
📝 docs/cli.md (+29 -0)
➕ docs/specs/agent-environments/environment-build/plan.md (+25 -0)
➕ docs/specs/agent-environments/environment-build/spec.md (+96 -0)
➕ docs/specs/agent-environments/environment-build/tasks.md (+13 -0)
➕ docs/specs/agent-environments/environment-build/verification.md (+102 -0)
➕ docs/specs/agent-environments/environment-prompt/plan.md (+21 -0)
➕ docs/specs/agent-environments/environment-prompt/spec.md (+83 -0)
➕ docs/specs/agent-environments/environment-prompt/tasks.md (+11 -0)
➕ docs/specs/agent-environments/environment-prompt/verification.md (+82 -0)
📝 docs/specs/agent-environments/scenario-capture/spec.md (+2 -1)
📝 docs/testing.md (+9 -7)
📝 docs/web-network-captures.md (+22 -0)
📝 package.json (+1 -0)
➕ scripts/fixtures/browser-request-site.mjs (+130 -0)
➕ scripts/lib/browser-request-e2e.mjs (+376 -0)

...and 55 more files

📄 Description

Summary

An agent asked to build an agent environment of a running web application cannot finish the job through REA's MCP
server today. A browser scenario reaches an application's API only through the UI or a goto GET, so recording the
writes an environment serves means scripting every form. No MCP tool writes a bundle, and nothing tells the agent how to
record a session the state can learn writes from, or when to stop. This PR adds:

  1. A request scenario action: one same-origin HTTP request sent through the page's own fetch, so a scenario can
    sign in through the UI and then call the application's API, writes included. Header values can be declared secrets
    or values the page holds (a CSRF cookie, a stored bearer token), and those are redacted from later records.
  2. An export_environment_bundle MCP tool: the bundle rea environment-build writes, from retained capture
    Evidence or an Evidence file, into an absent absolute directory, with the same report.
  3. A skill reference, references/environments.md: how to go from a prompt to a bundle. Map the app, record with a
    timeout on every step, read every write back, check coverage, re-record or stop by the withheld reason, export and
    hand off.

With that, Claude Code built and exported five environments from one-paragraph prompts. Each took about 2–7 minutes.
All five bundles start and answer retrieval tasks; 3 of the 5 also serve writes, and their write tasks pass with two
models.

Stacked on #6929 (feat/environment-build): the commits after eeab0bda are this PR's
(compare). Part of
#4933.

Problem and expected behavior

  • A scenario must be able to call the application's API the way its own frontend does: from the page, with the
    session's cookies and the headers the frontend sends. It must stay confined to the start URL's origin, and keep the
    values it reads out of the Evidence.
  • An agent must be able to write a bundle over MCP into a folder that did not exist, and get the coverage report.
  • An agent following the skill must end with a bundle and an honest report: what is served, what is withheld and why.
    It must never touch data the user did not offer, nor loop on gaps that re-recording cannot close.

Change and scope

  • request action (src/domain/browserScenarioValues.ts, browserScenario.ts,
    src/browser/PlaywrightScenarioRequest.ts):
    • What it sends: GET/HEAD/POST/PUT/PATCH/DELETE, a path that must resolve to the start origin, query
      entries, headers and a JSON body.
    • Header values: a literal, a declared secret, a cookie, or a local storage value (optionally at a JSON pointer),
      with an optional prefix.
    • Statuses: expected_status fails the step on any other status; 3xx statuses are refused.
    • Confinement:
      • the page's origin is checked again in the page as the request is sent;
      • redirects are not followed (a redirect fails the step);
      • nothing is sent once the step is cancelled or out of time.
    • Validation refuses: header names fetch cannot set, User-Agent, a repeated header name, and line breaks.
    • Redaction: values read from the page are redacted like declared secrets from later records, as stored and as
      sent. A value read again keeps its first marker. Values shorter than 8 characters are not redacted, so ids and ports
      survive.
    • A limitation marks captures with request steps; scenarios without them are unchanged.
  • MCP tool (src/contracts/environmentToolContracts.ts, src/domain/environmentBundleExport.ts,
    src/application/environment/environmentBundleTool.ts):
    • checks the destination the way other MCP output tools do, then runs the build with an exclusive destination;
    • serializes retained Evidence as --format json writes it, so the bundle is byte-identical to environment-build's;
    • is aliased to environment-build for CLI parity and registered in the product catalog.
  • Coverage: a capture whose records are not all timed now says that the state learns no write clock. Every browser
    scenario capture is untimed, so an update the application stamps with a modification time is withheld however often
    it is recorded.
  • Skill:
    • references/environments.md is installed by setup and routed from SKILL.md;
    • the skill description now names agent environments, so the skill loads without being asked for (version 47).
  • Docs: the request-step contract (docs/browser-scenario-contract.md), recording writes and the MCP tool
    (docs/agent-environments.md), and the spec folder docs/specs/agent-environments/environment-prompt/.
  • Lane: npm run verify:browser:request drives a real Chrome through a CSRF-and-bearer item API, builds the
    environment, and checks redaction, failure on an unexpected status, and redirect confinement.

Not included:

  • cross-origin requests, form or multipart bodies, and script actions;
  • redacting a page value retroactively (a login response recorded before the step keeps the token, as captures do
    today);
  • request timing on scenario events (the follow-up that would serve timestamped updates);
  • starting, seeding or resetting applications.

Scope decision pending: request lets a scenario change application state without a user gesture. CONTRIBUTING asks
for a maintainer decision on target mutation, and the scenario-capture spec named a fetch action as a non-goal needing
one. The step is confined to the start origin, the docs and skill require a disposable instance, and the skill asks
before any scenario that writes.

Size: about 2,500 lines (870 source, 1,200 tests and the lane, 460 docs). It splits cleanly if preferred: the
request action with its lane and contract docs, then the MCP tool, coverage line and skill.

Contract and boundary impact

  • Semantic owner and earliest changed stage:
    • browser scenario schema and Playwright actions (src/domain, src/browser);
    • environment export (src/application/environment);
    • the MCP application tools.
  • Contribution scope fit and linked maintainer decision: the MCP tool and skill fit the existing environment
    boundary. The request action needs the maintainer decision above (pending).
  • CLI and MCP/tool-catalog contract:
    • capture_browser_scenario and capture-browser-scenario accept the request action;
    • new MCP tool export_environment_bundle, the CLI alias of environment-build;
    • the capture_browser_scenario description names the action.
  • Provider, bridge, target-format, or platform compatibility: Playwright launch and connect modes. In connect mode
    the request runs in the user's page.
  • Evidence, artifact, provenance, or reconstruction contract:
    • scenario Evidence can hold request steps and their events;
    • page-read values appear as [REDACTED:page:<step>.<header>];
    • one new limitation on such captures, and one on untimed coverage.
  • Target selection, authority, upstream behavior, and cleanup details: a request step sends a declared request to the
    start origin with the session's cookies, and write methods change the application's data. Cleanup is unchanged.
  • Generated metadata, package, or installation impact: a new catalog tool, a new installed skill file, and skill
    version 47 (src/generatedPackageMetadata.ts).

Expected effects:

  • Read existing files or captured data.
  • Launch or attach to a process.
  • Inject instrumentation or run scripts/code.
  • Change process memory, registers, files, or configuration.
  • Contact network services.
  • Recover protected code or work around protections.
  • Documentation or usability only; no target interaction.
  • Not sure yet; investigation or maintainer guidance needed.

Evidence and regression coverage

Environments from a prompt. Five applications were seeded fresh on disposable Ubuntu VMs, loopback only. Claude Code
2.1.310 (claude-sonnet-5-5) had this branch's packed CLI, registered with rea setup --client claude_code. Each run got
one prompt: build an agent environment of the app at this URL covering these entities; the instance is disposable, but
leave the seeded data; the user, the password variable, the Chromium path and the output folder. The prompt did not
mention the skill. Bash and web tools were disabled.

Each bundle was then rebuilt from its own evidence.json with this branch's tarball; manifest.json and evidence.json
were byte-identical to the agent's. It then ran its smoke task, a retrieval eval generated from the bundle, and the
application's recorded write eval with fireworks_ai/gpt-oss-120b and fireworks_ai/glm-5p3-flash, one run per task.

App Agent run Recordings Records Tools (state / replayed reads) Served writes Smoke Retrieval gpt-oss / GLM Writes gpt-oss / GLM
Linkding 182 s 9 66 8 (7 / 1) 0 passed 9/9 / 8/9 0/3 / 0/3
Grocy 253 s 7 154 22 (16 / 0) 6 passed 10/11 / 10/11 3/3 / 3/3
Homebox 391 s 9 268 13 (11 / 2) 0 passed 9/9 / 9/9 0/2 / 0/2
Directus 202 s 7 100 25 (16 / 4) 5 passed 12/12 / 11/12 2/2 / 2/2 *
Grafana 143 s 4 100 15 (12 / 2) 1 passed 5/5 / 5/5 2/2 / 2/2

* The Directus eval's count check expects exactly the 2 provisions the scripted recording read. The agent read all 5,
so the raw eval is 0/2 even though every field check passes. With counts relative to the state, it is 2/2.

  • Writes: write tasks passed exactly when the build served their tool, with both models.
  • Agent behaviour: in every run the skill loaded unprompted, and the agent:
    • signed in through the form with the declared secret;
    • recorded with request steps and checked coverage;
    • stopped by the withheld reasons and exported;
    • listed the credential-named warning pointers.
  • Against the scripted recordings: the recordings the published environments came from, built with this branch,
    read more (11–39 state-backed reads) and serve 7, 3, 2, 2 and 0 writes. The prompted ones serve 0, 6, 0, 5 and 1.
  • Why Linkding and Homebox serve no updates: a scenario carries no request times, so the state learns no clock.
    Linkding's scripted HAR serves the same PATCH with a clock rule.
  • Earlier rounds:
    • Round 1: two agents hung on steps without timeout_ms. The skill now starts from a whole scenario with a timeout on
      every step.
    • Round 2, before the review fixes: 1, 6, 0, 5 and 0 writes served.

Reviews. Two independent reviews tried to refute the change; everything below is now fixed and tested.

  • Round 1 found:

    • a 302 that took a request step to another origin;
    • page values left unredacted under a repeated or colliding label;
    • short page values rewriting ids and hosts;
    • User-Agent dropped silently;
    • a request sent after its step timed out;
    • a re-encoded literal query, CR/LF in header values, and CLI wording in MCP refusals.
  • Round 2 confirmed those fixes and found:

    • query entries mishandled after ? or #, 3xx statuses that cannot match, and padded values escaping redaction
      (fixed);
    • the body cost of reading a page value and the MCP dry run's directory check (documented).
  • Tests added or updated:

    • unit: request schema refusals, execution, confinement, timeouts, query encoding and page-value redaction;
    • coverage limitation;
    • MCP boundary: byte-equality with an in-process build, dry run, destination and input refusals;
    • setup skill files;
    • the real-Chrome lane verify:browser:request.
  • Base reproduction or other evidence: see above. The redirect case is checked against the server, which never
    receives the cross-origin request.

  • User-visible CLI/MCP output:

    • a request step, as written by an agent: {"step_id": "create-1", "action": "request", "method": "POST", "path": "/api/objects/products", "json": {...}, "expected_status": [200], "timeout_ms": 15000};
    • the export's report is environment-build's (status, coverage.reads, coverage.writes.served/withheld with
      hints, warnings, next).
  • Remaining proof gaps:

    • Write coverage depends on the application.
    • Timestamped updates need scenario request timing (follow-up).
    • The registry's rea-agents@6.7.0 has no environment-serve, so a bundle exported from an unreleased build needs
      package_tarball until the next release (pre-existing).
    • Capture results are large; agents read step statuses from the client's saved copy, where bodies are base64.

For evidence-bearing changes:

  • Observed, derived, and inferred claims remain distinguishable.
  • Artifact identity, source provenance, and failed attempts remain preserved.
  • Unsupported, incomplete, unavailable, or uncertain outcomes remain visible.

Validation performed

Run on macOS with Node v24.22.1 at c67f57f8 (the merge of eeab0bda plus this PR).

  • npm run -s typecheck, lint, format:check, docs:check, mcp-catalog:check, verify:test-discovery and
    npx knip: passed.
  • npx vitest run --project domain --project services --project adapters: 16,347 passed, 1 failed ("stops Inspector
    target authorization after the current stat settles"). It fails the same way on the base fce1aba8 here (16,326
    passed, 2 failed).
  • Boundaries:
    • bundle tool, analysis view, tool schema validity, environment-build CLI, setup skill and client lifecycle: 123
      passed;
    • every browser and scenario MCP and CLI suite: 68 passed.
  • npm run -s verify:browser:request and npm run -s verify:browser:network: passed in real Chrome.
  • npm run -s verify:browser stops at "Real Chrome stable capture identities did not reconcile" (an inspect_web_page
    comparison) identically on the base.
  • End to end: five environments on Ubuntu 24.04 VMs, above.

After merging #6929 at 53a03c06 (main d87e73f2) into ac4d88aa, with no conflicts, on macOS with Node v24.22.1 and main's locked dependencies:

  • The static gates passed (npm run jscpd: 3.58%); npx vitest run --project domain --project services: 9793 passed, 6 skipped, none failed; the environment boundary projects: 107 passed.
  • The environment bundle MCP and skill-setup boundaries with the build, export, serve and analysis-view boundaries and tool schema validity: 9 files, 111 passed; src/browser/PlaywrightScenarioRequest.test.ts: 16 passed.
  • npm run verify:browser:request with Chrome: 22 request steps, 7 authenticated writes, 3 served writes (delete_items_by_id, post_items, put_items_by_id), verified.

CI on ac4d88aa found two regressions from this branch, fixed at e80e89ef:

  • b1e6652a: the environments reference makes the packaged skill eight files, so setupSkillPublication.test.ts derives its rollback counts from MANAGED_SKILL_FILES instead of fixing them at six and seven.
  • e80e89ef: an earlier merge's lint autofix had unescaped the hyphens in javaFloatValuePattern (src/domain/adb/adbDeviceAnalysis.ts), which no v-mode JS regex accepts, failing advertisedPatternsVMode; the file now matches main. No other file differs from main through a merge alone.
  • npm run -s check:fast, format:check, docs:check, mcp-catalog:check and npx knip passed; the MCP boundary project: 1386 passed; the skill boundaries: 30 passed.

At 2718c6e1: CI on e80e89ef found one more regression, fixed in a53d320e: the request step example in docs/browser-scenario-contract.md stood alone, but every JSON example there must parse as a whole capture_browser_scenario input, so it now sits in a launch scenario. #6929 at 74f7ad28 is merged with no conflicts and no file changed by the merge alone. npm run -s check:fast passes; src/application/environment, src/domain/analysisView and the request step tests: 1273 passed. Run locally against main d87e73f2, the boundary, CLI-boundary, process-boundary and acceptance projects fail no test main passes, except two release tests that read node_modules through this worktree's symlink and one worker-order timing test.

At 6fa1635e (#6929 at 98fe6dea merged): seven review findings fixed in 814ffa94 with #6929's headroom check: the page sends a request step only before its absolute deadline and within a one-second start window, so a busy page that starts it after cancellation sends nothing; local storage is read only on the start origin; the response is drained without keeping its body; an unparseable path is a field issue; retained Evidence is refused for heap headroom before serialization; and the skill says how to reach server-assigned ids. Each new test failed before the fix. Static checks (including mcp-catalog:check) pass; npx vitest run --project domain --project services (excluding javascriptSemanticAnalysis.reference_lifetimes.test.ts, whose worker crashes on main too): 9923 passed; the bundle MCP, product catalog, tool schema, v-mode pattern, skill and build boundaries pass; npm run verify:browser:request with Chrome verifies 22 request steps and 3 served writes. A request the page starts within that second of the hand-over can still be sent after cancellation; closing that needs network-level interception.

At 558ff76f (morluto's 0ad86117, then main 2250e67b): three review findings fixed. ffe82bbf runs the browser request lane under the shared verifier command owner, so a failed or timed-out run stops the CLI and the browser it launched before its private root is removed. 558ff76f scans a browser scenario's credentials by event, including a response attached mid-flight and an unattributable transaction (pointers now read event N …), and picks the form or JSON parser by the recorded media type, so valid forms such as password=x& are scanned and sentences are not. Each new test failed before its fix. On macOS with Node v24.22.1: the static checks pass, including mcp-catalog:check; npx vitest run --project domain --project services passes (9940, excluding javascriptSemanticAnalysis.reference_lifetimes.test.ts, whose worker crashes on main too); the bundle MCP, catalog, schema, v-mode, skill, build, export, headroom and verifier-ownership boundaries pass (74); verify:browser:request with Chrome verifies; and all 54 bundles stay byte-identical to the three-step path's, with unchanged warnings. CI's failing tests are packedBridgeVerification.test.ts, which main be2811e4 fails the same way.

At 378a7177, after merging main d361c53c (which carries #6897; one conflict, scripts/lib/windows-owned-command.mjs, takes main's lazy verifier source import, and no other file differs from main except this branch's own): runnerCancellation.test.ts, which failed on 558ff76f's CI and locally, passes with main's fix; npm run -s check:fast, format, knip, docs, mcp-catalog:check and test discovery pass; the environment, analysis-view, browser and CLI tests pass (2560) and the focused boundaries pass (75); verify:browser:request verifies; and all 54 bundles stay byte-identical to the three-step path's (78 served writes with main's write rules).

Compatibility, safety, and release

  • Breaking changes or migration steps: none; existing scenarios, commands and views are unchanged.
  • Real Hopper/Ghidra, browser, or OS coverage: real Chrome on macOS (lanes), snap Chromium 155 on Ubuntu 24.04
    (end to end).
  • Package or release metadata impact: a new MCP tool, skill version 47, and a new installed skill file.
  • Security, privacy, process, or containment review:
    • Request steps can change application data; the docs and skill limit them to disposable instances.
    • Page values of at least 8 characters are redacted from later records.
    • A cookie source can read HttpOnly cookies, which the page's scripts then see.
    • The bundle ships the capture, the browser executable path included.

Author readiness

Human owner: @earakely-scale

  • I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work.
  • I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps.
  • I declare this PR ready for initial maintainer review.

Before merge

  • This PR addresses a concrete problem or an agreed enhancement.
  • Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff.
  • The PR has one focused outcome and the title follows type(scope): outcome.
  • Related issue is linked, or the reason for not linking one is stated above.
  • Tests cover changed observable behavior and meaningful failure paths.
  • Owning docs, contracts, and generated metadata are updated where needed.
  • User-visible CLI/MCP changes include representative output.
  • I checked the final diff for secrets, unrelated cleanup, and unsupported claims.

🤖 Generated with Claude Code


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/6946 **Author:** [@earakely-scale](https://github.com/earakely-scale) **Created:** 10/24/2026 **Status:** ✅ Merged **Merged:** 10/24/2026 **Merged by:** [@morluto](https://github.com/morluto) **Base:** `main` ← **Head:** `feat/environment-prompt` --- ### 📝 Commits (10+) - [`da42a23`](https://github.com/morluto/rea/commit/da42a23ceec4b82d836eb298b2bff930bc6c0b5f) feat(environment): report what an environment serves with an environment-coverage view - [`cc290d9`](https://github.com/morluto/rea/commit/cc290d9f7770126dfb7eca74e081309417db5515) feat(environment): build an environment bundle in one command - [`045f14a`](https://github.com/morluto/rea/commit/045f14a3ae907df9878ea060413377b4cd4111de) test(environment): cover environment-build and the coverage view - [`cf7eb70`](https://github.com/morluto/rea/commit/cf7eb709e19f61bc5e1b23a2b905f2c31b2c3305) test(environment): build the real-agentenv lane's bundle with environment-build - [`1e2c12e`](https://github.com/morluto/rea/commit/1e2c12e5c3bda69a952e33f3c4eeddc90d1deb11) docs(environment): document environment-build and the coverage view - [`093af31`](https://github.com/morluto/rea/commit/093af3144853d28fec554b1c0d507c8bca00574b) fix(environment): harden environment-build after review - [`a040f01`](https://github.com/morluto/rea/commit/a040f01e34351cc7de25e2757e580273e27fe674) docs(environment): state the build's conditions and record its verification - [`bc35ef3`](https://github.com/morluto/rea/commit/bc35ef3cc095213ce8adeaf4cabcab3c945aee66) fix(environment): dispatch a pending interrupt before each build stage check - [`62368bd`](https://github.com/morluto/rea/commit/62368bdae95311dccb1d3b538103d17089965c4b) Merge remote-tracking branch 'origin/main' into eb - [`33c37f6`](https://github.com/morluto/rea/commit/33c37f6c91448cccf550c5144891fc516c529d56) feat(browser): send declared requests from a scenario page with a request step ### 📊 Changes **75 files changed** (+7033 additions, -255 deletions) <details> <summary>View changed files</summary> 📝 `.agents/skills/reverse-engineer-anything/SKILL.md` (+8 -2) ➕ `.agents/skills/reverse-engineer-anything/references/environments.md` (+215 -0) 📝 `.agents/skills/reverse-engineer-anything/references/evidence-workflows.md` (+7 -0) 📝 `docs/agent-environments.md` (+232 -9) 📝 `docs/browser-scenario-contract.md` (+113 -3) 📝 `docs/cli.md` (+29 -0) ➕ `docs/specs/agent-environments/environment-build/plan.md` (+25 -0) ➕ `docs/specs/agent-environments/environment-build/spec.md` (+96 -0) ➕ `docs/specs/agent-environments/environment-build/tasks.md` (+13 -0) ➕ `docs/specs/agent-environments/environment-build/verification.md` (+102 -0) ➕ `docs/specs/agent-environments/environment-prompt/plan.md` (+21 -0) ➕ `docs/specs/agent-environments/environment-prompt/spec.md` (+83 -0) ➕ `docs/specs/agent-environments/environment-prompt/tasks.md` (+11 -0) ➕ `docs/specs/agent-environments/environment-prompt/verification.md` (+82 -0) 📝 `docs/specs/agent-environments/scenario-capture/spec.md` (+2 -1) 📝 `docs/testing.md` (+9 -7) 📝 `docs/web-network-captures.md` (+22 -0) 📝 `package.json` (+1 -0) ➕ `scripts/fixtures/browser-request-site.mjs` (+130 -0) ➕ `scripts/lib/browser-request-e2e.mjs` (+376 -0) _...and 55 more files_ </details> ### 📄 Description ## Summary An agent asked to build an agent environment of a running web application cannot finish the job through REA's MCP server today. A browser scenario reaches an application's API only through the UI or a `goto` GET, so recording the writes an environment serves means scripting every form. No MCP tool writes a bundle, and nothing tells the agent how to record a session the state can learn writes from, or when to stop. This PR adds: 1. **A `request` scenario action**: one same-origin HTTP request sent through the page's own `fetch`, so a scenario can sign in through the UI and then call the application's API, writes included. Header values can be declared secrets or values the page holds (a CSRF cookie, a stored bearer token), and those are redacted from later records. 2. **An `export_environment_bundle` MCP tool**: the bundle `rea environment-build` writes, from retained capture Evidence or an Evidence file, into an absent absolute directory, with the same report. 3. **A skill reference, `references/environments.md`**: how to go from a prompt to a bundle. Map the app, record with a timeout on every step, read every write back, check coverage, re-record or stop by the withheld reason, export and hand off. With that, Claude Code built and exported five environments from one-paragraph prompts. Each took about 2–7 minutes. All five bundles start and answer retrieval tasks; 3 of the 5 also serve writes, and their write tasks pass with two models. Stacked on #6929 (`feat/environment-build`): the commits after `eeab0bda` are this PR's ([compare](https://github.com/earakely-scale/rea/compare/feat/environment-build...feat/environment-prompt)). Part of #4933. ## Problem and expected behavior - A scenario must be able to call the application's API the way its own frontend does: from the page, with the session's cookies and the headers the frontend sends. It must stay confined to the start URL's origin, and keep the values it reads out of the Evidence. - An agent must be able to write a bundle over MCP into a folder that did not exist, and get the coverage report. - An agent following the skill must end with a bundle and an honest report: what is served, what is withheld and why. It must never touch data the user did not offer, nor loop on gaps that re-recording cannot close. ## Change and scope - **`request` action** (`src/domain/browserScenarioValues.ts`, `browserScenario.ts`, `src/browser/PlaywrightScenarioRequest.ts`): - **What it sends:** `GET`/`HEAD`/`POST`/`PUT`/`PATCH`/`DELETE`, a path that must resolve to the start origin, query entries, headers and a JSON body. - **Header values:** a literal, a declared secret, a cookie, or a local storage value (optionally at a JSON pointer), with an optional prefix. - **Statuses:** `expected_status` fails the step on any other status; 3xx statuses are refused. - **Confinement:** - the page's origin is checked again in the page as the request is sent; - redirects are not followed (a redirect fails the step); - nothing is sent once the step is cancelled or out of time. - **Validation refuses:** header names `fetch` cannot set, `User-Agent`, a repeated header name, and line breaks. - **Redaction:** values read from the page are redacted like declared secrets from later records, as stored and as sent. A value read again keeps its first marker. Values shorter than 8 characters are not redacted, so ids and ports survive. - A limitation marks captures with request steps; scenarios without them are unchanged. - **MCP tool** (`src/contracts/environmentToolContracts.ts`, `src/domain/environmentBundleExport.ts`, `src/application/environment/environmentBundleTool.ts`): - checks the destination the way other MCP output tools do, then runs the build with an exclusive destination; - serializes retained Evidence as `--format json` writes it, so the bundle is byte-identical to `environment-build`'s; - is aliased to `environment-build` for CLI parity and registered in the product catalog. - **Coverage:** a capture whose records are not all timed now says that the state learns no write clock. Every browser scenario capture is untimed, so an update the application stamps with a modification time is withheld however often it is recorded. - **Skill:** - `references/environments.md` is installed by setup and routed from SKILL.md; - the skill description now names agent environments, so the skill loads without being asked for (version 47). - **Docs:** the request-step contract (`docs/browser-scenario-contract.md`), recording writes and the MCP tool (`docs/agent-environments.md`), and the spec folder `docs/specs/agent-environments/environment-prompt/`. - **Lane:** `npm run verify:browser:request` drives a real Chrome through a CSRF-and-bearer item API, builds the environment, and checks redaction, failure on an unexpected status, and redirect confinement. **Not included:** - cross-origin requests, form or multipart bodies, and script actions; - redacting a page value retroactively (a login response recorded before the step keeps the token, as captures do today); - request timing on scenario events (the follow-up that would serve timestamped updates); - starting, seeding or resetting applications. **Scope decision pending:** `request` lets a scenario change application state without a user gesture. CONTRIBUTING asks for a maintainer decision on target mutation, and the scenario-capture spec named a fetch action as a non-goal needing one. The step is confined to the start origin, the docs and skill require a disposable instance, and the skill asks before any scenario that writes. **Size:** about 2,500 lines (870 source, 1,200 tests and the lane, 460 docs). It splits cleanly if preferred: the `request` action with its lane and contract docs, then the MCP tool, coverage line and skill. ## Contract and boundary impact - **Semantic owner and earliest changed stage:** - browser scenario schema and Playwright actions (`src/domain`, `src/browser`); - environment export (`src/application/environment`); - the MCP application tools. - **Contribution scope fit and linked maintainer decision:** the MCP tool and skill fit the existing environment boundary. The `request` action needs the maintainer decision above (pending). - **CLI and MCP/tool-catalog contract:** - `capture_browser_scenario` and `capture-browser-scenario` accept the `request` action; - new MCP tool `export_environment_bundle`, the CLI alias of `environment-build`; - the `capture_browser_scenario` description names the action. - **Provider, bridge, target-format, or platform compatibility:** Playwright launch and connect modes. In connect mode the request runs in the user's page. - **Evidence, artifact, provenance, or reconstruction contract:** - scenario Evidence can hold `request` steps and their events; - page-read values appear as `[REDACTED:page:<step>.<header>]`; - one new limitation on such captures, and one on untimed coverage. - **Target selection, authority, upstream behavior, and cleanup details:** a request step sends a declared request to the start origin with the session's cookies, and write methods change the application's data. Cleanup is unchanged. - **Generated metadata, package, or installation impact:** a new catalog tool, a new installed skill file, and skill version 47 (`src/generatedPackageMetadata.ts`). Expected effects: - [x] Read existing files or captured data. - [x] Launch or attach to a process. - [ ] Inject instrumentation or run scripts/code. - [x] Change process memory, registers, files, or configuration. - [x] Contact network services. - [ ] Recover protected code or work around protections. - [ ] Documentation or usability only; no target interaction. - [x] Not sure yet; investigation or maintainer guidance needed. ## Evidence and regression coverage **Environments from a prompt.** Five applications were seeded fresh on disposable Ubuntu VMs, loopback only. Claude Code 2.1.310 (`claude-sonnet-5-5`) had this branch's packed CLI, registered with `rea setup --client claude_code`. Each run got one prompt: build an agent environment of the app at this URL covering these entities; the instance is disposable, but leave the seeded data; the user, the password variable, the Chromium path and the output folder. The prompt did not mention the skill. Bash and web tools were disabled. Each bundle was then rebuilt from its own `evidence.json` with this branch's tarball; `manifest.json` and `evidence.json` were byte-identical to the agent's. It then ran its smoke task, a retrieval eval generated from the bundle, and the application's recorded write eval with `fireworks_ai/gpt-oss-120b` and `fireworks_ai/glm-5p3-flash`, one run per task. | App | Agent run | Recordings | Records | Tools (state / replayed reads) | Served writes | Smoke | Retrieval gpt-oss / GLM | Writes gpt-oss / GLM | | -------- | --------- | ---------- | ------- | ------------------------------ | ------------- | ------ | ----------------------- | -------------------- | | Linkding | 182 s | 9 | 66 | 8 (7 / 1) | 0 | passed | 9/9 / 8/9 | 0/3 / 0/3 | | Grocy | 253 s | 7 | 154 | 22 (16 / 0) | 6 | passed | 10/11 / 10/11 | 3/3 / 3/3 | | Homebox | 391 s | 9 | 268 | 13 (11 / 2) | 0 | passed | 9/9 / 9/9 | 0/2 / 0/2 | | Directus | 202 s | 7 | 100 | 25 (16 / 4) | 5 | passed | 12/12 / 11/12 | 2/2 / 2/2 \* | | Grafana | 143 s | 4 | 100 | 15 (12 / 2) | 1 | passed | 5/5 / 5/5 | 2/2 / 2/2 | \* The Directus eval's count check expects exactly the 2 provisions the scripted recording read. The agent read all 5, so the raw eval is 0/2 even though every field check passes. With counts relative to the state, it is 2/2. - **Writes:** write tasks passed exactly when the build served their tool, with both models. - **Agent behaviour:** in every run the skill loaded unprompted, and the agent: - signed in through the form with the declared secret; - recorded with request steps and checked coverage; - stopped by the withheld reasons and exported; - listed the credential-named warning pointers. - **Against the scripted recordings:** the recordings the published environments came from, built with this branch, read more (11–39 state-backed reads) and serve 7, 3, 2, 2 and 0 writes. The prompted ones serve 0, 6, 0, 5 and 1. - **Why Linkding and Homebox serve no updates:** a scenario carries no request times, so the state learns no clock. Linkding's scripted HAR serves the same PATCH with a clock rule. - **Earlier rounds:** - Round 1: two agents hung on steps without `timeout_ms`. The skill now starts from a whole scenario with a timeout on every step. - Round 2, before the review fixes: 1, 6, 0, 5 and 0 writes served. **Reviews.** Two independent reviews tried to refute the change; everything below is now fixed and tested. - **Round 1 found:** - a 302 that took a request step to another origin; - page values left unredacted under a repeated or colliding label; - short page values rewriting ids and hosts; - `User-Agent` dropped silently; - a request sent after its step timed out; - a re-encoded literal query, CR/LF in header values, and CLI wording in MCP refusals. - **Round 2** confirmed those fixes and found: - query entries mishandled after `?` or `#`, 3xx statuses that cannot match, and padded values escaping redaction (fixed); - the body cost of reading a page value and the MCP dry run's directory check (documented). - **Tests added or updated:** - unit: request schema refusals, execution, confinement, timeouts, query encoding and page-value redaction; - coverage limitation; - MCP boundary: byte-equality with an in-process build, dry run, destination and input refusals; - setup skill files; - the real-Chrome lane `verify:browser:request`. - **Base reproduction or other evidence:** see above. The redirect case is checked against the server, which never receives the cross-origin request. - **User-visible CLI/MCP output:** - a request step, as written by an agent: `{"step_id": "create-1", "action": "request", "method": "POST", "path": "/api/objects/products", "json": {...}, "expected_status": [200], "timeout_ms": 15000}`; - the export's report is `environment-build`'s (`status`, `coverage.reads`, `coverage.writes.served`/`withheld` with hints, `warnings`, `next`). - **Remaining proof gaps:** - Write coverage depends on the application. - Timestamped updates need scenario request timing (follow-up). - The registry's `rea-agents@6.7.0` has no `environment-serve`, so a bundle exported from an unreleased build needs `package_tarball` until the next release (pre-existing). - Capture results are large; agents read step statuses from the client's saved copy, where bodies are base64. For evidence-bearing changes: - [ ] Observed, derived, and inferred claims remain distinguishable. - [ ] Artifact identity, source provenance, and failed attempts remain preserved. - [ ] Unsupported, incomplete, unavailable, or uncertain outcomes remain visible. ## Validation performed Run on macOS with Node v24.22.1 at `c67f57f8` (the merge of `eeab0bda` plus this PR). - `npm run -s typecheck`, `lint`, `format:check`, `docs:check`, `mcp-catalog:check`, `verify:test-discovery` and `npx knip`: passed. - `npx vitest run --project domain --project services --project adapters`: 16,347 passed, 1 failed ("stops Inspector target authorization after the current stat settles"). It fails the same way on the base `fce1aba8` here (16,326 passed, 2 failed). - Boundaries: - bundle tool, analysis view, tool schema validity, environment-build CLI, setup skill and client lifecycle: 123 passed; - every browser and scenario MCP and CLI suite: 68 passed. - `npm run -s verify:browser:request` and `npm run -s verify:browser:network`: passed in real Chrome. - `npm run -s verify:browser` stops at "Real Chrome stable capture identities did not reconcile" (an `inspect_web_page` comparison) identically on the base. - End to end: five environments on Ubuntu 24.04 VMs, above. After merging #6929 at `53a03c06` (main `d87e73f2`) into `ac4d88aa`, with no conflicts, on macOS with Node v24.22.1 and main's locked dependencies: - The static gates passed (`npm run jscpd`: 3.58%); `npx vitest run --project domain --project services`: 9793 passed, 6 skipped, none failed; the environment boundary projects: 107 passed. - The environment bundle MCP and skill-setup boundaries with the build, export, serve and analysis-view boundaries and tool schema validity: 9 files, 111 passed; `src/browser/PlaywrightScenarioRequest.test.ts`: 16 passed. - `npm run verify:browser:request` with Chrome: 22 request steps, 7 authenticated writes, 3 served writes (`delete_items_by_id`, `post_items`, `put_items_by_id`), verified. CI on `ac4d88aa` found two regressions from this branch, fixed at `e80e89ef`: - `b1e6652a`: the environments reference makes the packaged skill eight files, so `setupSkillPublication.test.ts` derives its rollback counts from `MANAGED_SKILL_FILES` instead of fixing them at six and seven. - `e80e89ef`: an earlier merge's lint autofix had unescaped the hyphens in `javaFloatValuePattern` (`src/domain/adb/adbDeviceAnalysis.ts`), which no v-mode JS regex accepts, failing `advertisedPatternsVMode`; the file now matches main. No other file differs from main through a merge alone. - `npm run -s check:fast`, `format:check`, `docs:check`, `mcp-catalog:check` and `npx knip` passed; the MCP boundary project: 1386 passed; the skill boundaries: 30 passed. At `2718c6e1`: CI on `e80e89ef` found one more regression, fixed in `a53d320e`: the request step example in `docs/browser-scenario-contract.md` stood alone, but every JSON example there must parse as a whole `capture_browser_scenario` input, so it now sits in a launch scenario. #6929 at `74f7ad28` is merged with no conflicts and no file changed by the merge alone. `npm run -s check:fast` passes; `src/application/environment`, `src/domain/analysisView` and the request step tests: 1273 passed. Run locally against main `d87e73f2`, the boundary, CLI-boundary, process-boundary and acceptance projects fail no test main passes, except two release tests that read `node_modules` through this worktree's symlink and one worker-order timing test. At `6fa1635e` (#6929 at `98fe6dea` merged): seven review findings fixed in `814ffa94` with #6929's headroom check: the page sends a request step only before its absolute deadline and within a one-second start window, so a busy page that starts it after cancellation sends nothing; local storage is read only on the start origin; the response is drained without keeping its body; an unparseable path is a field issue; retained Evidence is refused for heap headroom before serialization; and the skill says how to reach server-assigned ids. Each new test failed before the fix. Static checks (including `mcp-catalog:check`) pass; `npx vitest run --project domain --project services` (excluding `javascriptSemanticAnalysis.reference_lifetimes.test.ts`, whose worker crashes on main too): 9923 passed; the bundle MCP, product catalog, tool schema, v-mode pattern, skill and build boundaries pass; `npm run verify:browser:request` with Chrome verifies 22 request steps and 3 served writes. A request the page starts within that second of the hand-over can still be sent after cancellation; closing that needs network-level interception. At `558ff76f` (morluto's `0ad86117`, then main `2250e67b`): three review findings fixed. `ffe82bbf` runs the browser request lane under the shared verifier command owner, so a failed or timed-out run stops the CLI and the browser it launched before its private root is removed. `558ff76f` scans a browser scenario's credentials by event, including a response attached mid-flight and an unattributable transaction (pointers now read `event N …`), and picks the form or JSON parser by the recorded media type, so valid forms such as `password=x&` are scanned and sentences are not. Each new test failed before its fix. On macOS with Node v24.22.1: the static checks pass, including `mcp-catalog:check`; `npx vitest run --project domain --project services` passes (9940, excluding `javascriptSemanticAnalysis.reference_lifetimes.test.ts`, whose worker crashes on main too); the bundle MCP, catalog, schema, v-mode, skill, build, export, headroom and verifier-ownership boundaries pass (74); `verify:browser:request` with Chrome verifies; and all 54 bundles stay byte-identical to the three-step path's, with unchanged warnings. CI's failing tests are `packedBridgeVerification.test.ts`, which main `be2811e4` fails the same way. At `378a7177`, after merging main `d361c53c` (which carries #6897; one conflict, `scripts/lib/windows-owned-command.mjs`, takes main's lazy verifier source import, and no other file differs from main except this branch's own): `runnerCancellation.test.ts`, which failed on `558ff76f`'s CI and locally, passes with main's fix; `npm run -s check:fast`, format, knip, docs, `mcp-catalog:check` and test discovery pass; the environment, analysis-view, browser and CLI tests pass (2560) and the focused boundaries pass (75); `verify:browser:request` verifies; and all 54 bundles stay byte-identical to the three-step path's (78 served writes with main's write rules). ## Compatibility, safety, and release - **Breaking changes or migration steps:** none; existing scenarios, commands and views are unchanged. - **Real Hopper/Ghidra, browser, or OS coverage:** real Chrome on macOS (lanes), snap Chromium 155 on Ubuntu 24.04 (end to end). - **Package or release metadata impact:** a new MCP tool, skill version 47, and a new installed skill file. - **Security, privacy, process, or containment review:** - Request steps can change application data; the docs and skill limit them to disposable instances. - Page values of at least 8 characters are redacted from later records. - A cookie source can read HttpOnly cookies, which the page's scripts then see. - The bundle ships the capture, the browser executable path included. ## Author readiness Human owner: @earakely-scale - [x] I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work. - [x] I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps. - [x] I declare this PR ready for initial maintainer review. ## Before merge - [x] This PR addresses a concrete problem or an agreed enhancement. - [x] Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff. - [x] The PR has one focused outcome and the title follows `type(scope): outcome`. - [x] Related issue is linked, or the reason for not linking one is stated above. - [x] Tests cover changed observable behavior and meaningful failure paths. - [x] Owning docs, contracts, and generated metadata are updated where needed. - [x] User-visible CLI/MCP changes include representative output. - [x] I checked the final diff for secrets, unrelated cleanup, and unsupported claims. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-11-01 21:48:03 +00:00
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#7466
No description provided.