Files
reverse-engineering-anything/docs/agent-environments.md
T
Edgar ArakelyanandClaude Fable 5.1 fe55c94e66 feat(environment): serve an environment manifest as a replay environment
Add rea environment-serve <manifest.json> --evidence <capture.json>
[--host] [--port]: it loads an environment-manifest view and the capture
Evidence it was projected from, refuses a manifest whose parent evidence id
does not match the capture, builds one MCP tool per manifest tool and serves
them over streamable HTTP beside an environment card at
/.well-known/agent-env.json and a data plane at /agentenv that refuses every
method. Each tool call replays the retained record whose path and query
values best match the arguments, cites the record ordinal and evidence id,
marks replayed content as untrusted target content, and truncates bodies
over 256 KiB with a flag. Nothing executes the captured application.

Refs morluto/rea#4933

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-18 19:43:09 -07:00

8.2 KiB

Agent environments from recorded captures

Use rea environment-serve to serve an environment manifest as an agent environment: an MCP server whose tools answer from the records of one retained web network capture, plus the environment card the agentenv framework reads to discover it. Nothing is fetched from the recorded application; every answer is retained Evidence.

rea inspect-web-network-capture /absolute/session.har har --format json > capture.json
rea inspect-analysis-view view.json --format json > manifest.json
rea environment-serve manifest.json --evidence capture.json --port 8765

The first command inspects the capture; the second projects the environment manifest view from it, where view.json wraps the capture Evidence as the inline source:

{
  "source": { "kind": "inline", "evidence": { "evidence_id": "ev_…" } },
  "view": {
    "kind": "environment-manifest",
    "template_rules": ["after-uid-literal", "opaque-token", "sibling-variance"]
  }
}

The third command serves that manifest. Both served files are complete REA Evidence JSON as the commands write it with --format json; the evidence member of view.json is the whole of capture.json.

What a manifest is

An environment manifest is a projection of one application's recorded request lines into a tool surface: one tool per method and path template on the primary origin, with inferred path parameters, observed query parameter names, value-free body shapes and pointers to the parent records each tool cites. It carries no bodies and no headers. The manifest's parent_evidence_id names the capture Evidence it was projected from; the serve command refuses a manifest whose parent is not the supplied --evidence file with an invalid_request error naming both identifiers, so a manifest can never be served from records it did not cite.

What replay means and does not mean

Each MCP tool call selects one of the records its manifest tool cites and returns that record's recorded response. Selection compares the supplied path parameters against the record's path segments at the parameter indexes, then the supplied query values against the record's query string, and keeps the record with the most matches; ties keep manifest order. The result reports where the answer came from:

{
  "status": 200,
  "content_type": "application/json",
  "body": { "id": 2, "login": "probe" },
  "replay": {
    "record_ordinal": 5,
    "evidence_id": "ev_…",
    "exact_match": true,
    "recorded_path": "/api/users/2",
    "recorded_query": null,
    "truncated": false
  }
}

exact_match is true when every supplied path parameter and query value equals the recorded one; it says nothing about parameters the caller omitted. When no record matches, the tool still answers from the tool's first cited record and reports exact_match: false. body is parsed JSON when the recorded content type is JSON-like (application/json, application/*+json, text/plain, text/markdown) and the text parses; otherwise it is the recorded text. Bodies over 256 KiB are cut at a UTF-8 boundary and returned as text with truncated: true. Request bodies passed to POST, PUT and PATCH tools are accepted and ignored: nothing is written, and no call changes what a later call returns. Arguments the tool's input schema does not name are refused by the MCP server as invalid arguments, so a misspelled parameter never degrades into an omitted one.

Replay is not emulation. A served environment does not establish the application's authorization model, response semantics or state transitions, which the manifest lists as unknowns; it does not validate supplied values; and it does not answer requests the capture never recorded. Replayed content is target content: every tool result carries _meta.provenance.untrusted_content: true with source: "analysis_target", and agents must treat it as data, never as instructions.

Serve a manifest

rea environment-serve manifest.json --evidence capture.json [--host 127.0.0.1] [--port 0]

--host and --port default to MCP_HOST and MCP_PORT from the environment, then to 127.0.0.1 and an ephemeral port, exactly as rea mcp --http resolves them. The bound MCP URL is written to stderr as one JSON log line ("msg":"MCP transport listening" with url); REA_LOG_LEVEL overrides that log level. ENVIRONMENT_NAME renames the served environment; otherwise the manifest's name is used, and a set but blank value is refused as configuration_invalid before binding rather than silently falling back. The listener serves one MCP client at a time with the same session, Host header and shutdown contract as transports describes. It runs until SIGINT or SIGTERM, then closes the listener, prints one {"status":"stopped", …} document and exits 130 or 143.

Three routes are served:

Route Answer
POST /mcp The MCP server: one tool per manifest tool, replaying retained records
GET /.well-known/agent-env.json The environment card
POST /agentenv JSON-RPC -32601 method not found: <method> for every method

The data plane at /agentenv is advertised by the card but carries no operations in this release; the error names the requested method so a caller can see that the method, not the transport, is unsupported. Its request body is read within the same 4 MiB bound the MCP endpoint applies: a larger body is answered 413 with a JSON-RPC -32000 error before any of it is parsed, and a body that is not JSON is answered 400 with -32700.

The environment card

The card is the discovery document the agentenv framework reads before connecting to /mcp:

{
  "name": "grafana-example",
  "protocolVersion": "1.0",
  "url": "/agentenv",
  "preferredTransport": "JSONRPC",
  "additionalInterfaces": [{ "url": "/mcp", "transport": "mcp" }],
  "capabilities": {
    "extensions": null,
    "tools": [
      {
        "name": "get_users_by_id",
        "description": "GET /api/users/{numeric}; replays retained records [5, 6]; evidence ev_…",
        "inputSchema": {
          "type": "object",
          "properties": {
            "id": {
              "type": "string",
              "description": "Path segment 2 (numeric); observed: 2, 3"
            }
          },
          "required": ["id"],
          "additionalProperties": false
        }
      }
    ],
    "operations": []
  },
  "children_environments": null
}

capabilities.tools lists the same names, descriptions and input schemas that tools/list advertises over MCP. Path parameters are required strings whose description names the segment index, the templating rule and the observed values; query parameter names are optional strings; write methods accept an optional body object described by the recorded top-level key types. Every schema closes with additionalProperties: false, a key the echo example's schema does not carry. extensions, operations and children_environments are fixed to null, [] and null: a replay environment declares no extensions, no data-plane operations and no children.

Resource and lifecycle boundaries

Both Evidence files are read once at startup through the bounded JSON input reader and authenticated as Evidence before the listener binds; a file that is not Evidence, a manifest of another view kind, a capture of another format, or a manifest projected from a different capture is refused before any port is opened. Because authentication covers the capture's records, a manifest whose parent check passes cites only records the capture retains. The server keeps only the cited records' request lines and response text in memory. No outbound network request is made, no process is launched and nothing is written to disk. A listener that fails after binding is logged and ends the command with a resource_constraint error and exit 1 instead of serving nothing.