# Debugger — Full Documentation

## Introduction

### Introduction

![Install, configure, and debug a React Router app with debugger and coding agents](/media/full-flow.gif)

debugger is a dev-only observability layer for debugging applications.
It instruments your dev server, captures runtime data (console output,
errors, network requests, browser state), stores it in memory, and
exposes it through a CLI. There are no config files, no dashboards,
and no external services.

## How it works

debugger has three components that work together to give you
visibility into your running application.

- **Server instrumentation** patches console methods and starts an
  IPC bridge that holds captured data in memory.
- **Browser client** is an IIFE script injected into pages that
  captures client-side data and sends it back to the server.
- **CLI** connects to the bridge over IPC and queries stored data
  on demand.

```mermaid
graph LR
  A[Dev server] -->|patches console| B[Log store]
  C[Browser] -->|POST /_/d| B
  B -->|IPC socket| D[CLI]
```

## What's captured

debugger captures data from both the server and the browser
automatically once instrumentation is active.

### Server

Server-side instrumentation captures the following:

- Console output (`log`, `warn`, `error`, `debug`, `info`)
- Unhandled errors
- HTTP request metadata (method, path, status, duration)

### Browser

The browser client captures a wider range of data:

- Console output
- JavaScript errors and unhandled rejections
- Network requests (fetch, XHR, WebSocket)
- Cookies, localStorage, and sessionStorage
- Service workers, cache storage, permissions, and storage quota

The browser client detects 50+ browser types.

## Design principles

debugger follows a strict set of design principles that keep it
lightweight and out of your way.

- **Dev-only** — no-ops in production, zero runtime cost
- **Zero config** — works out of the box with one import
- **Zero dependencies** — no external packages in core
- **In-memory** — ring buffers, no disk writes, no persistent state
- **Language-agnostic** — same IPC protocol across Node.js, Go,
  Python, and Rust

```cards
# Installation
Install debugger and set up your framework.
/docs/introduction/installation

# Usage
Learn how to query logs and inspect your application.
/docs/introduction/usage

# CLI reference
Complete command and flag reference.
/docs/reference/cli
```

---

### Installation

debugger has packages for four languages. Install the one that
matches your stack, then follow the framework-specific guide to wire
it into your dev server.

## Node.js

Install the Node.js package with your preferred package manager.

```install
@ephem-sh/debugger
```

Each framework has a dedicated adapter import. Pick yours from the
table below.

| Framework | Adapter import | Guide |
|-----------|---------------|-------|
| Next.js | `@ephem-sh/debugger/nextjs` | [Setup guide](/docs/examples/node/nextjs) |
| Vite + React | `@ephem-sh/debugger/vite` | [Setup guide](/docs/examples/node/vite-react) |
| Vite + Vue | `@ephem-sh/debugger/vite` | [Setup guide](/docs/examples/node/vite-vue) |
| SvelteKit | `@ephem-sh/debugger/vite/sveltekit` | [Setup guide](/docs/examples/node/sveltekit) |
| React Router | `@ephem-sh/debugger/vite/react-router` | [Setup guide](/docs/examples/node/react-router) |
| Astro | `@ephem-sh/debugger/vite/astro` | [Setup guide](/docs/examples/node/astro) |
| Nuxt | `@ephem-sh/debugger/nitro` | [Setup guide](/docs/examples/node/nuxt) |
| Qwik | `@ephem-sh/debugger/vite` | [Setup guide](/docs/examples/node/qwik) |
| TanStack Start | `@ephem-sh/debugger/vite/tanstack-start` | [Setup guide](/docs/examples/node/tanstack-start) |
| Waku | `@ephem-sh/debugger/vite` | [Setup guide](/docs/examples/node/waku) |
| Angular | `@ephem-sh/debugger/angular` | [Setup guide](/docs/examples/node/angular) |
| Express | `@ephem-sh/debugger/express` | [Setup guide](/docs/examples/node/expressjs) |
| Hono | `@ephem-sh/debugger/hono` | [Setup guide](/docs/examples/node/hono) |
| Elysia | `@ephem-sh/debugger/elysia` | [Setup guide](/docs/examples/node/elysia) |
| Fastify | `@ephem-sh/debugger/fastify` | [Setup guide](/docs/examples/node/fastify) |
| NestJS | `@ephem-sh/debugger/nest` | [Setup guide](/docs/examples/node/nest) |
| AdonisJS | `@ephem-sh/debugger/adonis` | [Setup guide](/docs/examples/node/adonis) |
| Nitro | `@ephem-sh/debugger/nitro` | [Setup guide](/docs/examples/node/nitro) |

## Go

Install the Go module with `go get`.

```bash
go get github.com/ephem-sh/debugger/packages/ephem-debugger-go
```

Each framework has a dedicated middleware package.

| Framework | Middleware import | Guide |
|-----------|-----------------|-------|
| Gin | `middleware/gin` | [Setup guide](/docs/examples/go/gin) |
| Echo | `middleware/echo` | [Setup guide](/docs/examples/go/echo) |
| Chi | `middleware/chi` | [Setup guide](/docs/examples/go/chi) |

## Python

Install the Python package with your preferred tool.

```tabs
# pip
pip install ephem-debugger-py


# uv
uv add ephem-debugger-py

```

Each framework requires an extras install for its adapter.

| Framework | Extra | Guide |
|-----------|-------|-------|
| FastAPI | `ephem-debugger-py[fastapi]` | [Setup guide](/docs/examples/python/fastapi) |
| Flask | `ephem-debugger-py[flask]` | [Setup guide](/docs/examples/python/flask) |
| Django | `ephem-debugger-py[django]` | [Setup guide](/docs/examples/python/django) |

## Rust

Add the crate to your `Cargo.toml` with the appropriate feature
flag for your framework.

```toml
[dependencies]
ephem-debugger-rs = { version = "0.3", features = ["axum"] }
```

| Framework | Feature flag | Guide |
|-----------|-------------|-------|
| Axum | `axum` | [Setup guide](/docs/examples/rust/axum) |
| Actix | `actix` | [Setup guide](/docs/examples/rust/actix) |
| Rocket | `rocket` | [Setup guide](/docs/examples/rust/rocket) |
| Poem | `poem` | [Setup guide](/docs/examples/rust/poem) |

> [!NOTE]
> The `dbg` CLI is included with the `@ephem-sh/debugger` npm
> package. Since it's installed as a dev dependency, run it with
> `npx dbg` (or `pnpm exec dbg`, `bunx dbg`). For Go, Python,
> and Rust projects, install the Node.js package alongside your
> language-specific package to get access to the CLI.

## Verify the installation

Once you have debugger installed, confirm that everything is wired
up correctly.

```steps
# Start your dev server
Run your application as you normally would. debugger activates
automatically in development mode.

# Check the connection
Open a new terminal in the same project directory and run:
```command npm pnpm bun yarn live
dbg status
```
You see session information including the framework name, port,
and process ID.

# View logs
```command npm pnpm bun yarn live
dbg all
```

This shows the most recent console output from both server and
browser.

---

### Usage

Once debugger is instrumented and your dev server is running, use the
`dbg` CLI to query captured data. This guide walks through common
workflows with real output from a Vite + React session. For the
complete flag reference, see the [CLI reference](/docs/reference/cli).

## Check session status

You can verify that debugger is running and see session metadata with
the `status` command.

```command npm pnpm bun yarn live
dbg status
```

```text
Session:   dev-9183f9
Framework: vite
Port:      5173
PID:       280288
Uptime:    3m 32s
```

The output confirms the bridge is active and tells you which framework
adapter is in use, what port the dev server listens on, the process
ID, and how long the session has been running.

## View server logs

The `server console` command shows console output captured from your
server-side code. Each line includes a timestamp, a short entry ID, the
log level, the source label, and the message.

```command npm pnpm bun yarn live
dbg server console
```

```text
15:00:05 cbcdb6 LOG   [server] VITE v8.0.0 ready in 234 ms
15:00:05 109f7e LOG   [server] ➜ Local: http://localhost:5173/
15:00:28 372c17 WARN  [server] [console.warn] [debugger:test] warn ...
15:00:28 cd727b ERROR [server] [console.error] [debugger:test] error ...
```

You can filter by log level to narrow the output:

```bash
npx dbg server console --level warn
```

Or filter by time window to see only recent entries:

```bash
npx dbg server console --last 5m
```

## View browser logs

The `browser console` command shows console output captured from the
browser client. Entries cover all log levels and include Vite HMR
messages alongside your application output.

```command npm pnpm bun yarn live
dbg browser console
```

```text
15:03:11 9c9047 LOG   [browser] [debugger:test] log {"id":"d6d9aff7","ts":"2026-03-19T18:03:11.566Z"}
15:03:11 8eae90 WARN  [browser] [debugger:test] warn {"id":"e6b8e8e1","ts":"2026-03-19T18:03:11.828Z"}
15:03:12 f76480 ERROR [browser] [debugger:test] error {"id":"20d8e9f5",...}
15:03:12 5f59b4 DEBUG [browser] [vite] hot updated: /src/App.tsx
```

The same filtering flags work here. Use `--level error` to show only
errors, or `--last 30s` to restrict to recent entries.

## Inspect network requests

The `browser network` command shows fetch, XHR, and WebSocket activity
captured from the browser. Each line shows the HTTP status, method,
URL, and duration.

```command npm pnpm bun yarn live
dbg browser network
```

```text
15:03:14 cc636e 200  GET    https://jsonplaceholder.typicode.com/posts/1 (125ms)
15:03:15 b92adf 201  POST   https://jsonplaceholder.typicode.com/posts (320ms)
15:03:15 eb3291 200  GET    /api/nonexistent-2fe46bf3 (8ms)
15:03:16 889159 0    WS     wss://echo.websocket.org (0ms)
15:03:16 2fa6c7 1005 WS     wss://echo.websocket.org (3044ms)
```

WebSocket connections appear with a `WS` method and their close code
as the status. You can filter to show only failed requests or a
specific status code:

```bash
npx dbg browser network --failed
npx dbg browser network --status 201
```

To inspect a single request in detail, pass its ID along with the
`--headers` and `--body` flags:

```bash
npx dbg browser network --id b92adf --headers --body
```

```text
ID:       b92adf
URL:      https://jsonplaceholder.typicode.com/posts
Method:   POST
Status:   201
Duration: 320ms
Failed:   false
Kind:     fetch
Time:     15:03:15

Request Headers:
  Content-Type: application/json
  X-Debug-Id: 56b98420

Response Headers:
  cache-control: no-cache
  content-length: 97
  content-type: application/json; charset=utf-8
  expires: -1
  location: https://jsonplaceholder.typicode.com/posts/101
  pragma: no-cache
```

## Check errors

The `browser errors` command shows runtime errors and unhandled
promise rejections from the browser. Each entry includes the error
message and a stack trace.

```command npm pnpm bun yarn live
dbg browser errors
```

```text
15:03:12 265521 ERROR [browser] Uncaught Error: unhandled 8e58bfab
  Error: unhandled 8e58bfab
  at http://localhost:5173/src/App.tsx:108:16
15:03:13 f45519 ERROR [browser] rejection 899ebe9d
  Error: rejection 899ebe9d
  at onClick (http://localhost:5173/src/App.tsx:118:39)
  at executeDispatch (react-dom-client.js:9140:5)
  at runWithFiberInDEV (react-dom-client.js:850:66)
  at processDispatchQueue (react-dom-client.js:9166:27)
```

You can also check server-side errors:

```bash
npx dbg server errors
```

Server errors include SSR failures, unhandled exceptions, and any
errors your framework surfaces during request handling.

## Inspect browser state

debugger captures periodic snapshots of browser application state. You
can query cookies, storage, permissions, and quota individually.

```accordion
# Cookies

`npx dbg browser cookies`

```text
Cookies (3)
  debugger_fetch_f3442ea0=true
  dbg_secure_mmxs3phg=secret_u6zb
  debugger_test_mmxs3ptk=value_l0nd
```

# Storage

`npx dbg browser storage`

```text
localStorage (7)
  dbg_local_mmxs3o9g = {"created":"2026-03-19T18:03:25.972Z","random":0.688575170773545}
  test key = test value
  ...

sessionStorage (1)
  dbg_session_mmxs3q9w = 2026-03-19T18:03:28.580Z
```

# Permissions

`npx dbg browser permissions`

```text
Permissions
  geolocation          denied
  notifications        prompt
  camera               prompt
  microphone           prompt
  clipboard-read       granted
  clipboard-write      granted
```

# Storage quota

`npx dbg browser quota`

```text
Storage Quota
  Usage: 482.8 KB
  Quota: 10.0 GB
  Used:  0.0%
```
```

## View all logs

The `all` command merges server and browser entries into a single
chronological view. It combines console output, errors, network
requests, and application state snapshots from both scopes.

```command npm pnpm bun yarn live
dbg all --limit 10
```

```text
15:03:14 cc636e 200  GET    https://jsonplaceholder.typicode.com/posts/1 (125ms)
15:03:15 b92adf 201  POST   https://jsonplaceholder.typicode.com/posts (320ms)
15:03:15 eb3291 200  GET    /api/nonexistent-2fe46bf3 (8ms)
15:03:16 889159 0    WS     wss://echo.websocket.org (0ms)
15:03:16 2fa6c7 1005 WS     wss://echo.websocket.org (3044ms)
15:03:18 688428 APP  [browser] 8 cookies, 23 local, 1 session, 0 workers
15:03:21 e381c7 APP  [browser] 0 cookies, 6 local, 0 session, 0 workers
15:03:25 d365ec 200  GET    /api/test?id=f3442ea0 (5ms)
15:03:26 877a83 APP  [browser] 1 cookies, 7 local, 0 session, 0 workers
15:03:28 6b6770 APP  [browser] 3 cookies, 7 local, 1 session, 0 workers
```

Use `--limit` to cap the number of entries returned. The `APP` entries
are periodic browser state snapshots showing cookie, storage, and
worker counts at a glance.

## Multiple sessions

When you run multiple dev servers at the same time, each one registers
its own debugger session. The `sessions` command lists all active
sessions.

```command npm pnpm bun yarn live
dbg sessions
```

```text
  ID             Framework    Port    PID      Dir
  ────────────── ──────────── ─────── ──────── ────────────────────
  dev-9183f9     vite         5173    280288   F:\...\react-vite
```

You can target a specific session by port or session ID:

```bash
npx dbg server console --port 5173
npx dbg browser network --session dev-9183f9
```

This works across languages. You can run a Node.js frontend, a Go
API, and a Python service, then query each one independently with
the same CLI.

## JSON output

Every command supports the `--json` flag for structured output. This
is useful for piping to other tools like `jq` or for consumption by
AI agents that parse structured data.

```command npm pnpm bun yarn live
dbg browser console --json --limit 1
```

```json
[
  {
    "type": "console",
    "level": "warn",
    "args": [
      "[debugger:test] warn",
      { "id": "e6b8e8e1", "ts": "2026-03-19T18:03:11.828Z" }
    ],
    "timestamp": 1773943391828,
    "source": "browser",
    "browser": "Chrome",
    "id": "8eae90"
  }
]
```

For example, to extract only error-level browser logs as JSON:

```bash
npx dbg browser console --level error --json | jq '.[].args'
```

---

### SKILL.md

debugger ships with a agent skill that teaches AI agents how
to use it. When the skill is installed, any coding agent working in
your project can query server logs, browser errors, network requests,
and application state through the `dbg` CLI without manual guidance.

## What's included

The skill lives in your project at `.claude/skills/debugger/` or `.agents/skills/debugger` and
contains three files:

| File | Purpose |
|------|---------|
| `SKILL.md` | Entry point with a symptom-to-command diagnosis table and a step-by-step debugging workflow |
| `setup.md` | How to install and instrument debugger for all supported languages and frameworks |
| `cli.md` | Complete CLI reference with every command, flag, output format, and JSON parsing examples |

## How it works

Agents automatically loads skills from the `.claude/skills/` or `.agents/skills`
directory. When an agent encounters a runtime error, a failing API
call, or unexpected behavior, it matches the symptom to the right
`dbg` command using the diagnosis table:

| Symptom | Command the agent runs |
|---------|----------------------|
| Server returning 500 | `npx dbg server errors` |
| Browser blank page | `npx dbg browser errors` |
| API request failing | `npx dbg browser network --failed` |
| Cookie not being set | `npx dbg browser cookies --name session` |
| Need all recent output | `npx dbg all` |

The agent uses `--json` for structured output it can parse
programmatically, then acts on the results to fix the issue.

## Adding the skill to your project

If you're using the debugger monorepo, the skill is already at
`.claude/skills/debugger/` or `.agents/skills/debugger`. For other projects, copy the skill
directory into your own `.claude/skills/` or `.agents/skills` folder after installing
debugger as a dependency.

```steps
# Install debugger
Follow the [installation guide](/docs/introduction/installation) for
your language and framework.

# Copy the skill
Copy the `.claude/skills/debugger/` or `.agents/skills/debugger` directory from the debugger
repository into your project's `.claude/skills/` or `.agents/skills/` directory.

# Verify
Start your dev server and ask your coding agent to "check the logs"
or "debug the server error." It will automatically use the skill.
```

## Agent workflow

The skill teaches agents a six-step workflow:

1. **Check status** — run `npx dbg status` to confirm debugger is
   active
2. **Identify scope** — determine if the problem is server-side or
   browser-side
3. **Query** — run the matching command from the diagnosis table
4. **Filter** — narrow results with `--last`, `--level`, `--status`,
   `--failed`, or `--limit`
5. **Inspect details** — for network requests, use
   `--id <id> --headers --body`
6. **Act** — fix the code and re-query to verify the fix

> [!TIP]
> The skill works best when debugger is already instrumented and
> the dev server is running. If the agent runs `npx dbg status`
> and gets no session, it falls back to the setup guide
> automatically.

---

## Examples

## Reference

### CLI reference

# CLI reference

The `dbg` CLI queries a running debugger session over IPC. It connects
to the dev server's log store via Unix sockets (macOS/Linux) or
Windows named pipes.

## Usage

```
npx dbg <scope> <command> [flags]
npx dbg <command> [flags]
```

## Scopes

### `browser`

Query browser-side data. All browser commands filter entries where
`source` is `browser`.

| Command | Description |
|---------|-------------|
| `npx dbg browser console` | Console logs (log, warn, error, debug, info) |
| `npx dbg browser errors` | Runtime errors and unhandled rejections |
| `npx dbg browser network` | Network requests (fetch, XHR, WebSocket) |
| `npx dbg browser cookies` | Document cookies |
| `npx dbg browser storage` | localStorage and sessionStorage |
| `npx dbg browser workers` | Service worker registrations |
| `npx dbg browser cache` | Cache Storage names and entry counts |
| `npx dbg browser permissions` | Browser permission states |
| `npx dbg browser quota` | Storage usage and quota |

### `server`

Query server-side data. All server commands filter entries where
`source` is `server`.

| Command | Description |
|---------|-------------|
| `npx dbg server console` | Server console logs |
| `npx dbg server errors` | SSR and runtime errors |

## Top-level commands

| Command | Description |
|---------|-------------|
| `npx dbg status` | Display session metadata (ID, framework, port, uptime) |
| `npx dbg all` | Display all entries merged by timestamp (default) |
| `npx dbg sessions` | List all active debugger sessions |

## Flags

All flags are optional and can be combined with any command.

### Output

| Flag | Description |
|------|-------------|
| `--json` | Output as JSON instead of formatted text |
| `--limit <n>` | Maximum number of entries to return (default: 50) |

### Filtering

| Flag | Description |
|------|-------------|
| `--last <duration>` | Time window filter. Accepts `30s`, `5m`, `1h` |
| `--level <level>` | Filter console entries by level (`log`, `warn`, `error`, `debug`, `info`) |
| `--status <code>` | Filter network entries by HTTP status code |
| `--failed` | Show only failed network requests |

### Detail view

| Flag | Description |
|------|-------------|
| `--id <id>` | Show detail view for a single entry |
| `--ids <id1> <id2>` | Show detail view for multiple entries |
| `--headers` | Include request/response headers in network detail |
| `--body` | Include response body in network detail |

### Application state filters

| Flag | Description |
|------|-------------|
| `--name <name>` | Filter cookies by name |
| `--key <key>` | Filter storage entries by key |
| `--type <type>` | Filter storage by type (`local` or `session`) |

### Session targeting

| Flag | Description |
|------|-------------|
| `--port <port>` | Target a specific session by port number |
| `--session <id>` | Target a specific session by session ID |

### Other

| Flag | Description |
|------|-------------|
| `--cwd <path>` | Override working directory for session discovery |
| `--help` | Display help text |

## Examples

View the last 30 seconds of browser console warnings:

```command npm pnpm bun yarn live
dbg browser console --level warn --last 30s
```

Get failed network requests as JSON:

```command npm pnpm bun yarn live
dbg browser network --failed --json
```

Inspect a specific network request with headers:

```command npm pnpm bun yarn live
dbg browser network --id a1b2c3 --headers --body
```

Find a specific cookie:

```command npm pnpm bun yarn live
dbg browser cookies --name session_token
```

View only localStorage:

```command npm pnpm bun yarn live
dbg browser storage --type local
```

Look up a specific storage key:

```command npm pnpm bun yarn live
dbg browser storage --key user_preferences
```

Get everything from the last 5 minutes as JSON:

```command npm pnpm bun yarn live
dbg all --last 5m --json
```

## Multi-session support

When you run multiple dev servers (for example, a frontend, an API,
and a docs site), each one gets its own debugger session. You can
list all active sessions and target a specific one by port or ID.

### List active sessions

```command npm pnpm bun yarn live
dbg sessions
```

```
  ID             Framework    Port    PID      Dir
  ────────────── ──────────── ─────── ──────── ────────────────────
  dev-a1b2c3     vite         5173    12345    /project/apps/web
  dev-d4e5f6     hono         3000    12346    /project/apps/api
  dev-g7h8i9     fastapi      8000    12347    /project/apps/py-api
```

### Target by port

```command npm pnpm bun yarn live
dbg --port 3000 browser console
```

```command npm pnpm bun yarn live
dbg --port 5173 browser network
```

```command npm pnpm bun yarn live
dbg --port 8000 server console
```

### Target by session ID

```command npm pnpm bun yarn live
dbg --session dev-a1b2c3 status
```

```command npm pnpm bun yarn live
dbg --session dev-d4e5f6 browser errors
```

### Default behavior

Without `--port` or `--session`, the CLI finds the active session
by walking parent directories from the current working directory:

- **macOS/Linux:** looks for `.debugger/bridge.sock`
- **Windows:** probes named pipes matching `\\.\pipe\debugger-<hash>`
  where `<hash>` is derived from the directory path

If your dev server runs in a subdirectory, use `--cwd` to point
to it:

```command npm pnpm bun yarn live
dbg status --cwd ./apps/web
```

## JSON output

When using `--json`, the CLI outputs structured JSON that AI agents
can parse directly:

```command npm pnpm bun yarn live
dbg browser console --json --limit 5
```

```json
[
  {
    "type": "console",
    "level": "log",
    "args": ["User clicked button"],
    "timestamp": 1710000000000,
    "source": "browser",
    "browser": "Chrome",
    "id": "a1b2c3"
  }
]
```

The `browser` field identifies which browser generated the entry
(Chrome, Edge, Brave, Firefox, Safari, Arc, and 40+ others).

---

### Architecture

debugger is a three-part system: framework adapters capture runtime
data, an in-memory store holds it in ring buffers, and an IPC bridge
exposes it to the CLI. All communication uses NDJSON over Unix sockets
(macOS and Linux) or Windows named pipes.

## Data flow

```mermaid
graph TD
  A[Framework adapter] -->|patches console, intercepts HTTP| B[Log store]
  C[Browser client] -->|POST /_/d| A
  A -->|routes to buffer| B
  B -->|ring buffers| D{IPC bridge}
  D -->|NDJSON over socket| E[CLI]
```

The adapter instruments the dev server on startup. It patches console
methods to capture server-side output and registers HTTP middleware
to capture request metadata. The browser client sends data to the
adapter's ingest endpoint. Everything flows into the log store, which
the IPC bridge exposes for CLI queries.

## Components

debugger is composed of four main components. Each one has a single
responsibility and communicates through well-defined boundaries.

### Framework adapters

Framework adapters are language-specific integrations that hook into
each framework's dev server. Node.js adapters use Vite plugins,
Next.js instrumentation hooks, or Express-style middleware. Go,
Python, and Rust adapters use their native middleware patterns. Each
adapter creates a log store, patches logging, and starts the IPC
bridge.

### Log store

The log store routes entries into four ring buffers by type. Each
buffer has a fixed capacity and evicts the oldest entry when full.

| Buffer | Capacity | Entry type |
|--------|----------|------------|
| Console | 500 | `console` |
| Errors | 100 | `error` |
| Network | 300 | `network` |
| App state | 50 | `app` |

Ring buffers keep memory usage constant regardless of how long the
dev server runs. No entries are written to disk.

### IPC bridge

The bridge is a socket server that listens for NDJSON requests. Each
CLI invocation opens a connection, sends one request, receives one
response, and disconnects.

- **Unix/macOS**: `{project}/.debugger/bridge.sock`
- **Windows**: `\\.\pipe\debugger-{hash}` (first 8 characters of the
  MD5 hash of the working directory)

On startup, the bridge writes a `session.json` file to `.debugger/`
containing the session ID, framework name, port, and PID. The CLI
uses this file for session discovery. On shutdown, the socket and
session file are cleaned up.

### CLI

The CLI is a stateless query tool. It discovers the session by
reading `.debugger/session.json`, connects to the socket, sends a
query, formats the response, and exits. It doesn't run a background
process or maintain state between invocations.

## Session management

Each instrumented dev server creates a session with a unique ID
(format: `dev-{6 hex chars}`). The session tracks the framework
name, port, process ID, start time, and socket path.

When multiple dev servers run in the same project, the CLI discovers
all sessions by scanning for `.debugger/session.json` files up to
three directory levels deep. You can target a specific session with
`--port` or `--session`.

## Multi-language protocol

All language packages (Node.js, Go, Python, Rust) implement the same
NDJSON protocol. The CLI doesn't know or care what language the
server runs — it speaks the same protocol to all of them. See the
[protocol reference](/docs/reference/protocol) for the full specification.

---

### Protocol

debugger uses a line-delimited JSON (NDJSON) protocol for
communication between the IPC bridge and the CLI. Each message is a
single JSON object terminated by a newline. This protocol is
language-agnostic — all four language packages implement it
identically.

## Entry types

Four entry types flow into the log store. Each type is a
discriminated union member keyed by the `type` field.

### Console entry

```type-table
# ConsoleEntry
type | "console" | - | Entry type discriminator
id | string | - | 6-character hex ID, assigned by the store (optional on input)
level | "log" \| "warn" \| "error" \| "debug" \| "info" | - | Console method that produced the entry
args | unknown[] | - | Serialized arguments passed to console
timestamp | number | - | Unix epoch in milliseconds
source | "browser" \| "server" | - | Where the entry originated
```

### Error entry

```type-table
# ErrorEntry
type | "error" | - | Entry type discriminator
id | string | - | 6-character hex ID (optional on input)
message | string | - | Error message
stack | string | - | Stack trace (optional)
timestamp | number | - | Unix epoch in milliseconds
source | "browser" \| "server" | - | Where the error occurred
url | string | - | Page URL, browser only (optional)
component | string | - | Framework component name (optional)
```

### Network entry

```type-table
# NetworkEntry
type | "network" | - | Entry type discriminator
id | string | - | 6-character hex ID (optional on input)
url | string | - | Request URL
method | string | - | HTTP method or "WS" for WebSocket
status | number | - | HTTP status code
duration | number | - | Round-trip time in milliseconds
timestamp | number | - | Unix epoch in milliseconds
failed | boolean | - | Whether the request failed
source | "browser" | - | Always "browser"
kind | "fetch" \| "xhr" \| "ws" | - | Request API used (optional)
requestHeaders | Record<string, string> | - | Request headers (optional)
responseHeaders | Record<string, string> | - | Response headers (optional)
responseBody | string | - | Response body, capped at 4 KB (optional)
connectionId | string | - | WebSocket connection ID (optional)
messageCount | number | - | WebSocket message count (optional)
wsReadyState | number | - | WebSocket ready state (optional)
```

### App entry

```type-table
# AppEntry
type | "app" | - | Entry type discriminator
id | string | - | 6-character hex ID (optional on input)
timestamp | number | - | Unix epoch in milliseconds
source | "browser" | - | Always "browser"
cookies | CookieInfo[] | - | Browser cookies (optional)
localStorage | Record<string, string> | - | Local storage key-value pairs (optional)
sessionStorage | Record<string, string> | - | Session storage key-value pairs (optional)
serviceWorkers | ServiceWorkerInfo[] | - | Registered service workers (optional)
cacheStorage | CacheInfo[] | - | Cache storage entries (optional)
permissions | PermissionInfo[] | - | Browser permission states (optional)
storageEstimate | object | - | Storage usage and quota in bytes (optional)
```

## Request format

The CLI sends a single request per connection. The `command` field
determines which buffer to query, and `filters` narrow the results.

```type-table
# QueryRequest
id | string | - | Unique request identifier
command | string | - | One of: "console", "errors", "network", "app", "status", "all", "push"
filters.last | number | - | Time window in milliseconds
filters.level | string | - | Console level filter
filters.status | number | - | HTTP status code filter
filters.failed | boolean | - | Failed requests only
filters.limit | number | 50 | Maximum entries to return
filters.source | "browser" \| "server" | - | Source filter
filters.id | string | - | Single entry ID lookup
filters.ids | string[] | - | Multiple entry ID lookup
filters.subcommand | string | - | App subcommand (cookies, storage, etc.)
filters.name | string | - | Cookie name filter
filters.key | string | - | Storage key filter
filters.storageType | "local" \| "session" | - | Storage type filter
```

## Response format

```type-table
# QueryResponse
id | string | - | Matches the request ID
ok | boolean | - | Whether the query succeeded
data | LogEntry[] | [] | Array of matching entries
session | SessionInfo | - | Session metadata (included with status)
error | string | - | Error message if ok is false
```

## Transport

Each CLI invocation opens a new socket connection, writes one NDJSON
line (the request), reads one NDJSON line (the response), and closes
the connection. There is no persistent connection or streaming.

---

### Configuration

debugger requires zero configuration for development use. This page
documents the internal configuration details: how socket paths are
computed, how production environments are detected, and where session
metadata is stored.

## Socket paths

The IPC socket path depends on your operating system.

```tabs
# Unix and macOS
The IPC socket is created inside the project directory:
```
{project}/.debugger/bridge.sock
```
The `.debugger/` directory is created on startup and cleaned up
on shutdown.

# Windows
Windows uses a named pipe:
```
\\.\pipe\debugger-{hash}
```
The `{hash}` is the first 8 characters of the MD5 hash of the
current working directory. Named pipes are managed by the OS and
don't require manual cleanup.
```

## Session file

On startup, the bridge writes `.debugger/session.json` containing
metadata about the running dev server.

```json
{
  "sessionId": "dev-a1b2c3",
  "framework": "next",
  "port": 3000,
  "pid": 12345,
  "startedAt": 1710700982000,
  "socketPath": "/path/to/.debugger/bridge.sock"
}
```

The CLI reads this file to discover active sessions. On shutdown,
the file is deleted.

## Production guards

debugger is designed for development only. Each language has a
different mechanism for ensuring it doesn't run in production.

```tabs
# Node.js
Node.js adapters check `process.env.NODE_ENV`. When set to
`"production"`, all debugger functions return no-ops. The Vite
plugin uses `apply: 'serve'` which strips it entirely from
production builds.

# Go
Go doesn't have a built-in environment mode. Guard the debugger
initialization with an environment variable check:
```go
if os.Getenv("ENV") != "production" {
    dbg := debugger.New(debugger.Options{...})
    defer dbg.Close()
}
```

# Python
Python middleware runs unconditionally. Guard with an environment
variable:
```python
import os
if os.getenv("ENV") != "production":
    app.add_middleware(Middleware, port=8000)
```

# Rust
Rust middleware runs unconditionally. Guard with a feature flag
or environment variable:
```rust
if std::env::var("ENV").unwrap_or_default() != "production" {
    // add middleware layers
}
```
```

## Ingest endpoint

The browser client sends captured data to `/_/d` on the same origin
via POST. The client script is served from `/_/d.js` via GET. These
endpoints are registered by the framework adapter and don't conflict
with application routes.

## Ring buffer sizes

Each buffer has a fixed capacity. You cannot change these sizes at
runtime.

| Buffer | Capacity | Description |
|--------|----------|-------------|
| Console | 500 entries | Server and browser console output |
| Errors | 100 entries | JavaScript errors and unhandled exceptions |
| Network | 300 entries | HTTP requests and WebSocket connections |
| App state | 50 entries | Browser state snapshots |

These sizes are fixed and not configurable. When a buffer is full,
the oldest entry is evicted.

---

### Browser client

The browser client is a lightweight script that captures runtime data
from the browser. It intercepts console output, JavaScript errors,
network requests, and periodically snapshots application state like
cookies and storage. All captured data is sent to the dev server for
querying through the CLI.

## How it gets loaded

The browser client is loaded in one of two ways depending on your
framework.

- **Automatic injection.** Frameworks with HTML rendering inject the
  script automatically. This includes Vite, Next.js, SvelteKit,
  Astro, Nuxt, React Router, Angular, FastAPI, Flask, and Django. No
  additional setup is needed.
- **Manual injection.** For frameworks that do not render HTML (for
  example, Express, Hono, Fastify, Go, and Rust), you add a script
  tag to your HTML template:

```html
<script src="/_/d.js"></script>
```

The script self-guards against double initialization. If it detects
that it has already been loaded, it no-ops silently.

## What's captured

The browser client intercepts several categories of runtime data and
sends each entry to the dev server with a timestamp and detected
browser name.

### Console output

The client intercepts all console methods: `log`, `warn`, `error`,
`debug`, and `info`. It captures arguments with safe serialization
that handles circular references, functions, and symbols. Each entry
includes the detected browser name so you can distinguish output
from different browsers during testing.

### Errors

The client captures `window.onerror` and `unhandledrejection` events.
Each error entry includes the error message, stack trace, and source
URL when available.

### Network requests

The client patches `fetch()` and `XMLHttpRequest` to capture the
method, URL, status code, duration, request and response headers,
and response body (capped at 4 KB for failed requests). It also
tracks WebSocket connections, including message count and ready
state.

### Application state

The client periodically snapshots application state every 10 seconds
and on storage change events. The following data is captured:

- **Cookies** — name, value, domain, path, expiry, secure flag, and
  SameSite attribute
- **localStorage and sessionStorage** — key-value pairs from both
  storage types
- **Service workers** — scope, script URL, and registration state
- **Cache storage** — cache names and entry counts
- **Permissions** — geolocation, notifications, camera, microphone,
  and clipboard
- **Storage quota** — current usage and total quota in bytes

## Data transport

Captured entries are batched before being sent to the dev server.
The client accumulates up to 10 entries or waits 100 milliseconds,
whichever comes first, then sends the batch.

Batches are sent via `sendBeacon()` when available, with a fallback
to `fetch()` using the `keepalive` option. All data is posted to
`/_/d` on the same origin. When the page is hidden or the visibility
state changes, any remaining entries in the buffer are flushed
immediately.

## Browser detection

The client detects 50+ browser types by parsing the user agent
string. Detected browsers include Chrome, Firefox, Safari, Edge,
Brave, Arc, Opera, and many others. The detected browser name appears
in CLI output alongside each browser entry, making it straightforward
to distinguish data from different browsers during cross-browser
testing.

---
