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

# V8 / JavaScript Probe: Chrome & Electron State Extraction

> How NSP connects to Chrome and Electron apps via CDP, runs the ASO fast-path extraction, and falls back to a full heap snapshot when needed.

The V8 probe reads live application state from any Chrome tab or Electron app by connecting to the process's **Chrome DevTools Protocol (CDP)** endpoint — the same protocol used by browser devtools. Once connected, it injects the ASO (Axon Semantic Oracle) JavaScript snippet directly into the running V8 heap and returns a fully-labeled `SubstrateState` in as little as 5 milliseconds. No browser extension, no user gesture, and no application-side code change is required.

***

## How CDP Connection Works

When `axon-daemon` detects a new process, the V8 probe checks for an accessible CDP endpoint by scanning:

1. **Command-line arguments** — looking for `--remote-debugging-port=NNNN`
2. **Process name patterns** — `chrome.exe`, `msedge.exe`, `electron.exe`, `code.exe`, `slack.exe`, and others
3. **Open port scan** — checking port 9222 and common Electron debug ports

When a matching process is found, it is classified as a V8 process and handed to the V8 probe pipeline. Electron apps each expose their own debug port, which NSP detects automatically from the process command line — no manual configuration needed for Electron.

***

## Enabling CDP on Chrome

Chrome does not expose a CDP endpoint by default. Launch it with the `--remote-debugging-port` flag to enable the V8 probe:

<Tabs>
  <Tab title="Windows">
    ```cmd theme={null}
    "C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222
    ```
  </Tab>

  <Tab title="macOS">
    ```bash theme={null}
    /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222
    ```
  </Tab>

  <Tab title="Linux">
    ```bash theme={null}
    google-chrome --remote-debugging-port=9222
    ```
  </Tab>
</Tabs>

<Note>
  Close all existing Chrome windows before launching with `--remote-debugging-port`. Chrome reuses a single browser process — if a session is already running without the flag, the new flag will have no effect until all Chrome windows are closed and the process fully exits.
</Note>

If you need to monitor multiple Chrome profiles or ports simultaneously, declare additional ports in `axon.toml`:

```toml theme={null}
# axon.toml
[v8]
debug_ports = [9222, 9223, 9224]
```

***

## Two-Tier Extraction

The V8 probe uses two extraction methods in order of preference. The fast-path handles the vast majority of polls; the heap snapshot fallback fires only when the fast-path is unavailable.

<Steps>
  <Step title="Tier 1 — ASO Fast-Path (5–50ms)">
    NSP injects a JavaScript snippet (`__axon_aso_snapshot`) into the live tab using `CDP Runtime.evaluate`. This script locates the application's data layer directly in the V8 heap and returns it as a serializable JSON object. The probe polls for the result up to 40 times within a 600ms window.

    ```
    inject_aso_now()   ← CDP Runtime.evaluate: installs __axon_aso_snapshot
          │
          ▼
    Poll (up to 40×):
      get_aso_snapshot() ← CDP Runtime.evaluate: reads __axon_aso_snapshot
          │
          ├─ Success → normalize_aso_snapshot() → SubstrateState ✓
          │
          └─ Null → fall back to Tier 2
    ```

    The ASO result includes confidence scores of **0.95–0.99** for known applications.
  </Step>

  <Step title="Tier 2 — Heap Snapshot Fallback (~47s)">
    When the ASO script returns null — typically on first contact with a new app or after a major navigation — the probe takes a full V8 heap snapshot via `CDP HeapProfiler.takeHeapSnapshot`.

    ```
    capture_snapshot()   ← CDP HeapProfiler.takeHeapSnapshot (~30–47s)
          │
          ▼
    parse_snapshot()     ← Decode flat-array node/edge binary format
          │
          ▼
    filter_snapshot()    ← Remove V8 internals, score and rank app objects
          │
          ▼
    normalize()          ← Apply rule-based labels + queue for LLM enrichment
          │
          ▼
    SubstrateState (confidence ~0.85)
    ```

    After the cold probe succeeds, the ASO script is installed permanently in the tab. Every subsequent poll uses Tier 1 at full speed.
  </Step>
</Steps>

<Tip>
  The heap snapshot fallback runs **only once per app** (or after a full-page navigation). After the first cold probe, all polls use the 5–50ms ASO fast-path. You will see `probe_tier: "heap_snapshot"` in `probe_metadata` only during initial attachment.
</Tip>

***

## Supported Applications

The V8 probe covers all Chrome tabs and Electron applications. The following apps have validated entries in the app signature database:

| Application      | App ID Pattern       | Connection Method               |
| ---------------- | -------------------- | ------------------------------- |
| Gmail            | `gmail-*`            | Chrome tab (CDP port required)  |
| Slack            | `slack-*`            | Electron — port auto-detected   |
| VS Code          | `vscode-*`           | Electron — full extension state |
| Notion           | `notion-*`           | Electron                        |
| GitHub Desktop   | `github-desktop-*`   | Electron                        |
| Salesforce       | `salesforce-*`       | Chrome tab                      |
| WhatsApp Desktop | `whatsapp-desktop-*` | Electron                        |
| Discord          | `discord-*`          | Electron                        |
| Shopify          | `shopify-*`          | Chrome tab                      |
| HubSpot          | `hubspot-*`          | Chrome tab                      |
| Any Electron app | `<exe-name>-*`       | Electron — auto-detected        |

<Info>
  Accuracy for all V8-covered applications is **>99%** once the ASO fast-path is installed. This includes Electron apps that ship obfuscated JavaScript — the heap snapshot fallback recovers semantic labels through LLM enrichment during the cold probe.
</Info>

***

## SubstrateState and probe\_metadata

Every V8 state capture includes a `probe_metadata` block that reports which extraction tier was used and the latency breakdown:

```json theme={null}
{
  "capture_id": "0196f4a2-3b5c-7d00-8e1f-9a0b2c3d4e5f",
  "app_name": "Gmail",
  "runtime": "v8",
  "confidence": 0.97,
  "objects": {
    "inbox.unread_count": 47,
    "inbox.emails[0].subject": "Q3 Performance Report",
    "inbox.emails[0].from": "alice@example.com",
    "inbox.emails[0].is_read": false
  },
  "probe_metadata": {
    "probe_tier": "aso_fast",
    "capture_latency_ms": 22,
    "total_latency_ms": 48,
    "cache_hit": false,
    "dom_tier_used": false
  }
}
```

The `probe_tier` field takes one of two values:

| Value           | Meaning                                 | Typical Latency |
| --------------- | --------------------------------------- | --------------- |
| `aso_fast`      | ASO JavaScript fast-path was used       | 5–50ms          |
| `heap_snapshot` | Full V8 heap snapshot fallback was used | \~47s           |

***

## Action Execution

V8 actions are executed by injecting a typed JavaScript call into the running tab via CDP:

```javascript theme={null}
// Dispatched internally by axon-daemon
window.__axon_dispatch_action('send_reply', {
  "thread_id": "msg_18821af3",
  "body": "Thanks — I'll review this afternoon."
})
```

CDP built-in actions such as `click`, `type`, and `navigate` are dispatched using the `Input` and `Page` CDP domains directly — no JavaScript injection is required for those.

***

## Python SDK Example

```python theme={null}
import asyncio
from nelieo_nsp import NSPClient

async def main():
    async with NSPClient() as client:
        # Connect to the Gmail substrate
        session = await client.session("gmail-chrome-12847")

        # Read inbox state (ASO fast-path — ~50ms)
        state = await session.state()
        print(f"Unread: {state.get_int('inbox.unread_count')}")
        print(f"Top subject: {state.get_str('inbox.emails[0].subject')}")

        # Execute an action (requires confidence >= 0.95 for irreversible_write)
        await session.execute(
            "send_reply",
            parameters={"thread_id": "msg_18821af3", "body": "On it!"},
            verify=True,
            verify_expression="inbox.sent_count > 0",
        )

asyncio.run(main())
```

<AccordionGroup>
  <Accordion title="What happens if the Chrome window navigates during a poll?">
    Navigation events clear the injected ASO script from the tab context. On the next poll cycle, the probe detects a null ASO result and re-injects the script. The following poll returns a fresh fast-path result. You may see one cycle with slightly elevated latency (\~600ms) immediately after navigation.
  </Accordion>

  <Accordion title="Can I probe multiple Chrome tabs simultaneously?">
    Yes. Each tab is treated as an independent substrate with its own `app_id`. NSP maintains a separate probe anchor and poll loop per tab. Electron apps with multiple windows are handled the same way.
  </Accordion>

  <Accordion title="Does the V8 probe work with headless Chrome?">
    Yes. Headless Chrome launched with `--remote-debugging-port` exposes the same CDP endpoint. Pass `--headless=new` along with `--remote-debugging-port=9222` for full compatibility.
  </Accordion>
</AccordionGroup>
