docs(skill): build agent environments from a prompt with request steps and the bundle tool

Add the environments reference to the skill and install it with setup: record
against a disposable instance, sign in through the UI, write with request
steps and read each write back, check coverage, re-record by withheld reason
and export the bundle. Route it from SKILL.md, name agent environments in the
skill description, and document the request step, the export tool and
recording writes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Edgar ArakelyanandClaude Opus 5.5 committed 2026-10-23 19:53:42 -07:00
1 parent 51723daab9
commit f7213a4c08
12 files changed
+360 -7

No files matched your search

+43
View File
@@ -187,6 +187,20 @@ Evidence also records the capture file's absolute path (`subject.local_path`,
`parameters.capture_path`, `locations`, `artifact.path`), and the bundle
carries it: build from a neutral folder when that path should not ship.
Over MCP, `export_environment_bundle` builds the same bundle and returns the
same report. Its `source` is capture Evidence the session retained
(`{"kind": "retained-evidence", "evidence_id"}`), such as a
`capture_browser_scenario` or `inspect_web_network_capture` result, or a
capture Evidence file (`{"kind": "evidence-file", "path"}`); inspect a HAR with
`inspect_web_network_capture` first. Retained Evidence is written into the
bundle as `--format json` writes it, so the bundle is the one
`environment-build` writes from that file. `output_directory` must be an
absolute path that does not exist yet, whose parent does; the tool creates it
and refuses an existing directory, empty or not. `name`, `template_rules`,
`package_tarball` and `dry_run` work as `--name`, `--template-rule`,
`--package-tarball` and `--dry-run` do, and retained Evidence has no file to
name the environment after, so a loopback or IP origin needs `name`.
## From a browser scenario
The capture can also come from REA itself: a
@@ -275,6 +289,35 @@ the replayed body is the bytes the browser exposes for each response, with any
declared secret replaced by its redaction marker (a body that redaction had to
empty replays no body).
To record writes, sign in through the UI and then send the application's API
calls with [request steps](browser-scenario-contract.md#request-steps): each
sends one request to the start origin through the page's own `fetch`, with the
session's cookies, and a header can carry the CSRF cookie or stored token the
application's own requests send. A write is served only when the capture shows
its effect, so read each collection before writing, read every written entity
back by id and in its list right after the write, and leave more than a second
between a create and its first edit. The environment coverage view names each
write it withholds and what to record next. A scenario with write requests
changes the application's data: record against an instance whose data may
change.
```json
{
"step_id": "create-folder-1",
"action": "request",
"method": "POST",
"path": "/api/folders",
"headers": [
{
"name": "X-CSRFToken",
"value": { "source": "cookie", "name": "csrftoken" }
}
],
"json": { "title": "Scratch folder 1" },
"expected_status": [200, 201]
}
```
## What a manifest is
An environment manifest is a projection of one application's recorded request
+74 -2
View File
@@ -10,7 +10,8 @@ liveness deadlines. `INPUT_JSON` may be inline JSON or a JSON file path.
The minimal request contains only browser launch/connect selection, `start_url`,
and at least one `actions` entry. Launch `headless` defaults to `true` and can
be set to `false` where the host supports a visible browser. Navigations follow
the destinations named by the scenario and the page's ordinary browser requests;
the destinations named by the scenario and the page's ordinary browser requests,
and [request steps](#request-steps) send only to the start URL's origin;
there is no separate origin allowlist or request-interception layer. Environment
settings (including service workers blocked by default), empty storage, and a
final sanitized URL capture are supplied by default. Set
@@ -204,7 +205,8 @@ language environments.
HTTP(S) URLs may include ordinary query values and fragments directly. Use
ordered structured query entries when a value needs to reference a declared
environment-backed secret. Form, storage, and cookie values are either literal
strings or declared secret references. Raw URL userinfo credentials are rejected.
strings or declared secret references; request step headers can also read a
cookie or local storage value from the page. Raw URL userinfo credentials are rejected.
Captured credential-header
values are not retained, and declared secret values are redacted automatically.
A secret may be declared solely to
@@ -315,6 +317,76 @@ external browser without closing it. The request itself defines the operation;
there is no additional REA grant step. The browser and host still enforce their
own access and process rules.
## Request steps
A `request` step sends one HTTP request from the page with the page's own
`fetch`, so the browser attaches the session's cookies and the request is
recorded in the step's network events like any request the application makes.
Use it to record an application's API, including writes, when driving the UI
for each call would be slower or less exact than calling the endpoint the UI
calls. It is the only action that changes application state without a user
gesture, so run scenarios with write requests only against an instance whose
data you may change.
```json
{
"step_id": "create-item",
"action": "request",
"method": "POST",
"path": "/api/items",
"query": [
{ "name": "notify", "value": { "source": "literal", "value": "false" } }
],
"headers": [
{
"name": "X-CSRFToken",
"value": { "source": "cookie", "name": "csrftoken" }
},
{
"name": "Authorization",
"value": {
"source": "local_storage",
"key": "auth",
"json_pointer": "/token"
},
"prefix": "Bearer "
}
],
"json": { "title": "Scratch item 1" },
"expected_status": [201],
"timeout_ms": 10000
}
```
- `method` is `GET`, `HEAD`, `POST`, `PUT`, `PATCH` or `DELETE`. `json` is the
body, sent with `Content-Type: application/json` unless a header sets one; a
`GET` or `HEAD` step cannot carry it.
- `path` starts with one `/` and must resolve to the start URL's origin, which
validation checks before the browser starts. When the step runs, the page must
be on that origin; add a `goto` step first if an earlier action left it.
`query` entries are appended in order and may reference declared secrets.
- Header values are literals, declared secrets, a cookie the browser holds for
the request URL (`{"source": "cookie", "name"}`), or a local storage entry on
the start origin (`{"source": "local_storage", "key"}`, with an optional
`json_pointer` into a stored JSON value). `prefix` is sent before the value.
Values read from the page are redacted like declared secrets, as
`[REDACTED:page:<step_id>.<header>]`, from records made after the step reads
them; a response recorded earlier, such as the login response that returned
a token, keeps the value. A missing cookie, key or
pointer fails the step. Header names a page's `fetch` cannot set, such as
`Cookie`, `Origin`, `Host` or `Sec-*`, are refused at validation.
- The step completes when the whole response has been read. With
`expected_status`, any other status fails the step and the later actions are
recorded as `cancelled`; without it, any response completes the step. A
network error, or `timeout_ms` passing, fails the step.
The request runs in the page's main world, so an application that wraps
`fetch` sees it, and it goes through the same network observation as other
page requests: select `network` events and network content to record it.
Captures with request steps state in `limitations` that the steps sent their
declared requests through the page's fetch. A scenario without request steps
is unchanged.
## Network evidence
`capture.events: ["network"]` retains request, response, completion, failure,
@@ -0,0 +1,21 @@
# Plan
1. Add the `request` action to the scenario schema: methods, path, query,
headers with page value sources, JSON body and expected statuses; validate
the origin and the body against the start URL; include query and header
secrets in the declared-secret check.
2. Add `PlaywrightScenarioRequest.ts`: check the page's origin, build the URL,
resolve header values (admitting values read from the page to the scenario's
redaction), fetch in the page with a timeout and read the whole response,
then check the status. Dispatch it from the action runner with the start
origin, and add the limitation when a scenario has a request step.
3. Add a real-browser lane, `verify:browser:request`: a fixture item API that
requires a CSRF cookie header and a stored bearer token for writes, a write
session recorded through the CLI, the build's served writes, and a failing
expected status.
4. Add the `export_environment_bundle` contract, effects, CLI alias, catalog
family and handler: check the destination as other MCP output tools do,
resolve the capture bytes, and call the build with an exclusive destination.
5. Write the skill reference, route it from SKILL.md and install it with setup.
6. Document the request step, the MCP tool and recording writes.
7. Tests: request step unit tests, the MCP tool boundary, setup's skill files.
@@ -0,0 +1,63 @@
# Build an environment from a prompt
## Outcome
`rea environment-build` builds a bundle from one capture, but an agent asked to
"make an environment of this app" still cannot finish the job through REA's MCP
server. A browser scenario can only reach an application's API through the UI or
a `goto` GET, so recording the writes an environment serves means scripting every
form, and there is no MCP tool that writes a bundle. Nothing tells the agent how
to record a session the state can learn writes from, or when to stop recording.
A `request` scenario action sends one same-origin request through the page's own
`fetch`, so a scenario can sign in through the UI and then call the application's
API, writes included, with the session's cookies and the CSRF or bearer values
the application's own requests send. An `export_environment_bundle` MCP tool
builds the bundle from capture Evidence, as `environment-build` does. A skill
reference walks an agent from the prompt to a bundle: map, record, check
coverage, re-record by reason, export and hand off.
## Requirements
- A `request` step names a method (`GET`, `HEAD`, `POST`, `PUT`, `PATCH`,
`DELETE`), a path on the start URL's origin, ordered query entries, headers,
an optional JSON body and optional expected statuses. Validation refuses a
path that resolves to another origin, a body on `GET` or `HEAD`, and header
names a page's `fetch` cannot set.
- Header values are literals, declared secrets, a cookie the browser holds for
the request URL, or a local storage value on the start origin, optionally
read at a JSON pointer, with an optional prefix. Values read from the page are
redacted like declared secrets from records made after they are read.
- The request runs through the page's `fetch` with same-origin credentials, from
a page on the start origin, and completes when the response is read. A status
outside `expected_status`, a network error or the step timeout fails the step;
later steps are cancelled as for other actions. Its network events are
attributed to the step.
- Captures with request steps say so in a limitation. A scenario without one
validates, runs and records exactly as before.
- `export_environment_bundle` takes retained capture Evidence or a capture
Evidence file, an absolute output directory that does not exist and whose
parent does, and the build's name, template rules, package tarball and dry
run. It writes the bundle `environment-build` writes from the same Evidence
bytes (retained Evidence serialized as `--format json` writes it) and returns
the same report, validated by its output schema. It refuses an existing
directory, empty or not, a parentless or relative one, unknown Evidence, an
unnamed loopback capture and repeated rules, and writes nothing when it
refuses. `environment-build` is its CLI command.
- The skill reference `references/environments.md` is installed with the skill
and routed from SKILL.md. It covers disposable instances only, credentials
from environment variables, the recording rules the state needs, coverage,
the stop rule and the hand-off.
- Stop rule: re-record a withheld write at most twice for a recording gap
(`no-state-target`, `no-observation`, `unconfirmed`, `incomplete-entities`),
once for `unexplained-change` and `no-call`, and stop at once for application
behaviour (`side-effect`, `contradicted`, `body-unusable`).
## Non-goals
- No cross-origin requests, form or multipart bodies, or arbitrary script
actions.
- No retroactive redaction of values a request step reads: a login response
recorded before the step keeps the token it returned, as captures do today.
- No application start, seed or reset, and no publishing of bundles.
- No change to what any view derives or any environment serves.
@@ -0,0 +1,11 @@
# Tasks
- [x] Record the outcome, requirements and non-goals.
- [x] Add the request action, its validation and its Playwright runner.
- [x] Add the real-browser request lane.
- [x] Add the export_environment_bundle tool.
- [x] Write and install the skill reference.
- [x] Document the request step, the tool and recording writes.
- [ ] Run static, formatting, documentation and test gates, and the existing browser lanes.
- [ ] Build environments from prompts with an agent against live applications on Linux VMs.
- [ ] Address the independent review.
@@ -59,7 +59,8 @@ change.
- No new browser action: scenarios still cover what the UI requests plus GET
reads through `goto`. A fetch or script action would be a new effect and
needs its own scope decision.
needs its own scope decision. (The `request` action was later scoped and
added by [environment-prompt](../environment-prompt/spec.md).)
- No change to what the scenario redacts. Values the application returns in
response bodies are retained, as they are in HAR captures.
- The api-surface view keeps HAR parents only.