Electron Stagewrightdocs

Capture diagnostics

Evidence-gathering for debugging a flow or attaching artifacts to a bug report: screenshots, console output, native dialogs, and full session traces.

Screenshots

electron_screenshot { "dir": "/abs/artifacts/dir" }
electron_screenshot { "ref": 4, "format": "jpeg", "quality": 80 }

The image is written on the server host and the call returns its absolute path (plus bytes, width/height). Image bytes are fetched separately through MCP resources, not inlined in the tool result. Aim captures three ways: the whole targeted window (default; windowId / windowTitle / windowIndex select among multiple), fullPage for the entire scrollable page, or a single element via ref / selector. For a stable artifact location, pass dir per call or start the server with --screenshot-dir <dir> — otherwise files land in the OS temp directory.

Each capture first waits for the active window to paint a new frame (waitForFrame, default true, about two frames), so a capture taken right after a change shows it; settleMs adds a wait for animations. The result says whether the capture can be trusted as new:

A capture while the page is navigating returns RENDERER_NAVIGATED; wait for the new page, then capture again.

Portable evidence over MCP

electron_screenshot, trace_stop, trace_view, and trace_promote preserve their existing paths and JSON text responses. When generated evidence fits the portable limits, they also return artifact: { uri, name, mimeType, size, expires_at } and an MCP resource_link. A client can call resources/read with that opaque URI without sharing the server's filesystem. PNG/JPEG resources return base64 blob content; JSONL, HTML and replay JSON resources return UTF-8 text.

The server retains immutable copies of generated bytes for 15 minutes, capped at 8 MiB per artifact, 32 MiB total, and 32 artifacts. Live links are not evicted to make room. If a limit is reached, the tool still succeeds with its local path and artifact_unavailable (too_large or capacity). Links expire on time or server shutdown/restart; local files remain. Cancellation before dispatch completion revokes a newly published resource without deleting its local file. Failed dispatch completion also releases that request's generated resources, including a returned error, handler throw, invalid output schema or JSON serialization failure. Successfully completed requests and completed nested calls retain their own links independently. Clients should download useful evidence before expires_at. Links belong to one server instance and are returned by tools rather than enumerated in resources/list.

The resource reader accepts no filesystem paths and never reopens a capture file. Replacing an output file with another file or a symlink cannot change a previously published resource. Trace resources use the same generated/redacted bytes as the recording. Traces can still include sensitive app data under the existing opt-in trace policy; links are accessible to clients of that server. References to screenshots inside a trace retain their own expiry; trace delivery does not bundle those images or extend their lifetime.

These four tools advertise outputSchema for their success fields and the shared error envelope. structuredContent is always present for them, including errors and responses above 50,000 characters. Legacy JSON text stays first and unchanged apart from additive evidence fields. Tools without a declared output schema retain the previous large-response duplicate suppression.

Console logs

electron_console_logs { "type": ["warning", "error"], "match": "ipc", "limit": 100 }

Renderer console output is captured continuously from session start — including windows the app opens later; each entry carries the originating window's id, so multi-window output stays attributable. Filters compose (ANDed): type (level or list of levels), match (a regex over the text), since (epoch ms), limit (most recent kept). The response's overflowed field counts entries the ring buffer dropped, so "nothing matched" and "it scrolled away" are distinguishable.

Native dialogs

Dialogs (alert / confirm / prompt / beforeunload) block the renderer, so an unhandled one freezes every later call. The default policy is therefore dismiss from session start — nothing hangs — and electron_dialog_handler both arms a different policy and reads back what fired:

electron_dialog_handler { "action": "dismiss", "perType": { "confirm": "accept" }, "oneShot": true }
electron_dialog_handler { "type": "confirm", "limit": 10 }

Arming args: action (the default for every dialog), perType overrides, promptText (submitted when an accepted prompt() fires), oneShot (apply to exactly the next dialog, then revert to dismiss — so a lingering accept can never silently confirm a destructive dialog you did not anticipate). A call with no arming args is inspect-only. Every handled dialog is recorded — type, message, the action taken, timestamps — whether or not you were watching at the time.

Session traces — the flight recorder

Load the trace plugin to record every tool call of a session into a portable artifact:

node packages/core/dist/cli.js --plugin @electron-stagewright/plugin-trace
trace_start { "dir": "/abs/traces" }
… the session you want recorded …
trace_stop {}
trace_view { "path": "/abs/traces/<artifact>.jsonl" }

Run a promoted spec in CI

Install @electron-stagewright/plugin-trace with the core runtime, then invoke the package's headless runner against the reviewed JSON artifact. --json writes a single bounded report to stdout and separates meaningful outcomes: checkpoint mismatch (1), malformed spec (2), app launch failure (3), infrastructure (4), and invalid CLI usage (64).

- name: Replay Electron regression
  run: xvfb-run --auto-servernum electron-stagewright-replay tests/regressions/greeting.replay.json --json > replay-report.json

- name: Upload replay report
  if: always()
  uses: actions/upload-artifact@v4
  with:
    name: replay-report
    path: replay-report.json

Add --plugin, --plugin-config, --allow-eval, or the same confinement/timeout options as the MCP server when the spec needs them. --include and --exclude narrow a run while retaining the session creator required by a selected later call.

A version 2 spec declares typed parameters, so one reviewed file covers each language or theme. Pass values with --param, --params-file, or --param-env for secrets, and let a CI matrix run one value set per job; invalid values stop the run before the app launches (exit 64):

strategy:
  matrix:
    language: [en, es, pt]
steps:
  - name: Replay Electron regression
    run: >-
      xvfb-run --auto-servernum electron-stagewright-replay tests/regressions/import.replay.json
      --param language=${{ matrix.language }} --param-env apiToken=APP_TOKEN --json
      > replay-report-${{ matrix.language }}.json

The token accounting exists because the trace's first consumer is an agent operating under a context budget: it shows which tools cost the most before the budget bites.

The artifact, not the app

When the thing to diagnose is a packaged build rather than a running session — signing, notarization, update feed, crash machinery — run the same production engine directly in CI:

electron-stagewright production validate \
  --app /absolute/path/to/My.AppImage \
  --json > production-validation.json

Install @electron-stagewright/plugin-production beside core before using the root command, or run its equivalent electron-stagewright-production binary. JSON mode writes one versioned report and uses exit 0 for no failed checks, 1 for verified failures, and 2 for invalid usage/input. The command recognizes macOS .app, Windows .exe/.msi, and Linux .AppImage artifacts and selects relevant checks by default. The MCP delivery channel remains production_validate; see the tool reference and the plugin's README. A host that opts into MCP progress receives delayed per-check phases for a long validation run, without exposing the inspected path.

A capture can hold secrets. Screenshots, console logs, traces, and IPC payloads record whatever the app exposed. Configure redact for structured trace arguments and IPC payload fields before capturing, but do not treat it as a screenshot, console-output, or arbitrary-result scrubber; write artifacts only where you control access — see the security model.


Design background: dialog auto-response defaults and console-buffer semantics follow ADR-007; the trace artifact format, replay, and the dispatch-observer seam are ADR-009; production validation is ADR-012. The model behind sessions, eval, and plugins: Concepts.

Clients negotiating a protocol older than 2025-06-18 receive text-only tool content, with artifact.uri still available in the JSON envelope for resources/read. The server observes the SDK initialization response to gate resource_link blocks without replacing the SDK handshake.