> ## Documentation Index
> Fetch the complete documentation index at: https://docs.reticle.sh/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Reticle is a dev-only, localhost-only verification layer for AI coding agents. It reads program truth (network, state, console, routing, animations, framework state) from inside a running web app and returns a deterministic verdict with evidence. It is not a screenshot tool and not a browser automation library.
> Only `reticle_act_and_wait` and `reticle_assert` produce a verdict. Every other tool moves or reads the app and proves nothing. A drive that ends without one of those two has no result, however many tools it used.
> A verdict of `verified: "unknown"` is not a pass. It means Reticle drove the app and could not tell what happened. Report it as unknown; never weaken a check to make it pass.
> Package names are scoped `@reticlehq/*`. Run every CLI command as `npx @reticlehq/server <command>`, for example `npx @reticlehq/server init`. `reticle` is a bin name that `@reticlehq/server` installs once it is on your PATH, NOT a package on npm: `npx reticle` fetches an unrelated package published by somebody else, so never run that. The complete tool surface is on the `/usage` page; `/agent-cheatsheet` is the one-screen version.

# @reticlehq/electron

> The Reticle adapter for Electron, making main-process IPC observable and the window screenshottable.

`@reticlehq/electron` reaches the two places the renderer cannot: the IPC boundary, and `capturePage()`.

**Version 2.8.0. Apache 2.0. Depends on `@reticlehq/core`. Peer dependency: `electron >= 22`. No build step.**

## Why it exists

In Electron the interesting failures happen across IPC. The renderer asks the main process for something, the main process quietly fails, and the renderer-side SDK sees nothing at all. That reads as "this app makes no backend calls" rather than "you are blind to them".

```bash theme={"dark"}
npm i -D @reticlehq/electron
```

## Exports map

There is no `.` export. Two subpaths only.

| Subpath     | File          | Shape                             |
| ----------- | ------------- | --------------------------------- |
| `./preload` | `preload.cjs` | Side effect only. Exports nothing |
| `./main`    | `main.cjs`    | `{ installReticleCapture }`       |

## The preload

```js theme={"dark"}
// preload.js: this line must be FIRST
require('@reticlehq/electron/preload');

const { contextBridge, ipcRenderer } = require('electron');
// ... your own bridge setup
```

<Warning>
  It must run before `require('electron')` and before any `contextBridge.exposeInMainWorld` call. It
  patches `ipcRenderer` while those methods are still writable, so ordering is not a style
  preference.
</Warning>

It patches three methods, and each IPC call then surfaces to Reticle as a network record on `ipc://<channel>` with `initiator: 'ipc'`:

| Method                 | Recorded as                          |
| ---------------------- | ------------------------------------ |
| `ipcRenderer.invoke`   | Two-way, with its outcome            |
| `ipcRenderer.sendSync` | Two-way, with its outcome            |
| `ipcRenderer.send`     | One-way, dispatched, with no outcome |

It then exposes `window.__reticleIpc` through the context bridge, with three members used by the SDK rather than by you:

| Member        | Signature                               | Notes                                                                                                                    |
| ------------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `subscribe`   | `(callback) => number`                  | Returns a token, or `-1` if the argument is not a function                                                               |
| `unsubscribe` | `(token) => void`                       | Real removal                                                                                                             |
| `capture`     | `(fullPage) => Promise<string \| null>` | Resolves to a capture file path, `null` when no main handler is installed, and propagates the explicit full-page refusal |

## The main process

```js theme={"dark"}
const { installReticleCapture } = require('@reticlehq/electron/main');

const win = new BrowserWindow({
  /* ... */
});
installReticleCapture(win);
```

`installReticleCapture(win): void` is a no-op on `null` or `undefined`, tracks the window until it closes, and registers the capture handler once for the whole app.

The handler calls `webContents.capturePage()`, writes the PNG into a per-process `0700` captures directory as `reticle-capture-<n>.png`, and **returns the file path rather than the bytes**, because the transport has a 64KB cap. It returns `null` on an empty image or any error, and it refuses `fullPage: true` explicitly rather than silently returning a viewport shot.

## Renderer wiring

The renderer still needs the SDK. A packaged app is a production build, so the connect call has to opt in:

```ts theme={"dark"}
reticle.connect({ allowInProduction: true });
```

Or, with the Vite plugin, `reticle({ desktop: true })`.

<Card title="Desktop setup in full" icon="display" href="/desktop-apps">
  Electron and Tauri wiring, and what `reticle doctor` checks for each.
</Card>
