# Monitor and replay

Serial output with decoded defmt logs, named boot reasons and symbolized panics. Record it, play it back.

`espx monitor` shows a board's serial output. `espx run` and `espx flash --monitor` end in the same monitor. It works inside a project and outside one; inside, the project's release binary lets espx decode logs and resolve panics.

## Two monitors

espx has two ways to watch a board, and picks one for you.

|           | espflash's monitor                                                                | espx's own monitor                                                                                                                                                 |
| --------- | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| When      | In a terminal, with none of the flags below                                       | With `--until`, `--expect`, `--reject`, `--timeout`, `--json`, `--record` or `--input`, when stdin is not a terminal, or when another espx process holds the board |
| What runs | `espflash monitor` with `--elf` and `--log-format defmt` as the project calls for | espx reads the port itself                                                                                                                                         |
| Keys      | `Ctrl+R` resets, `Ctrl+C` exits                                                   | `Ctrl+C` exits                                                                                                                                                     |
| Output    | espflash's                                                                        | Typed events: lines, boots, panics, exceptions, resets, plugs and unplugs                                                                                          |

The interactive path keeps espflash's key handling, which espx's monitor does not have. Everything else on this page is about espx's own monitor. Arguments after `--` are for `espflash monitor`, so combining them with the flags above stops with `monitor_extra_args`.

```sh
espx monitor                         # espflash monitor in your terminal
espx monitor --timeout 10s           # espx reads the port for 10 seconds
espx monitor | grep -i error         # piped, so espx reads the port
espx monitor --dir ~/code/blinky     # decode against that project's binary
```

## Speed

The monitor reads at 115200 baud. `MONITOR_BAUD` changes the default and `--baud` overrides both. A board on native USB ignores the setting.

## What espx's monitor does

### Resets the board

Opening the port resets the board through the serial lines, so the log starts at boot. The first event is `reset`.

### Names each boot

Every ROM banner line such as `rst:0x15 (USB_UART_HPSYS),boot:0x6c (SPI_FAST_FLASH_BOOT)` becomes a `boot` event with a `reason` and the ROM's `code`:

| `reason`     | Printed as                                                              |
| ------------ | ----------------------------------------------------------------------- |
| `power_on`   | power-on                                                                |
| `software`   | software reset                                                          |
| `watchdog`   | watchdog reset                                                          |
| `brownout`   | brownout reset                                                          |
| `panic`      | reset after a panic (a software reset right after a panic or exception) |
| `deep_sleep` | wake from deep sleep                                                    |
| `external`   | external reset                                                          |
| `usb`        | reset over USB                                                          |
| `unknown`    | unknown reset                                                           |

The codes mean different things on the original ESP32 and on the later chips; espx reads the banner to tell which. The reset espx does when it opens a native-USB port shows as `usb`. In the terminal a watchdog, panic or brownout boot prints as a warning:

```text
warn: board booted: watchdog reset (rst:0x7 (TG0_WDT_HPSYS),boot:0x6c (SPI_FAST_FLASH_BOOT))
```

### Decodes defmt

When the project has `defmt` in `[dependencies]` and a release binary in `target/`, espx cuts esp-println's defmt frames out of the byte stream and decodes them against the binary. Each decoded line carries its `level`, `module` and `location`:

```text
[INFO ] Hello world! (src/bin/main.rs:39)
```

Without the binary, the bytes pass through unchanged and one `warning` event says so. A defmt board monitored without `--dir` pointing at its project shows the boot log, then raw frame bytes. Build first and pass `--dir`.

### Resolves panics

A panic printed by esp-backtrace becomes a `panic` event with the message and one frame per address, resolved against the release binary to a function, file and line. Without the binary the frames carry only addresses.

esp-generate's template has no esp-backtrace unless you ask for it, and its default panic handler prints no backtrace. Create the project with `espx new <name> -o esp-backtrace` to get symbolized panics.

### Reports CPU exceptions

A CPU exception (a load from an invalid address, an illegal instruction) is an `exception` event instead, with its `kind`, the faulting `address` when the kind has one, and the faulting instruction as the first frame.

### Follows the board

When the board drops off USB (deep sleep, a replug, a flash from another process), the monitor reports `detached`, waits, then reports `reconnected` and keeps going. It follows the board by its USB serial number, so a new port path does not lose it.

> **Note**
>
> An ESP32-C6 on native USB loses its USB port in deep sleep and starts printing before the host has enumerated it again, so the first half second or so after a wake is lost. In a tight deep-sleep loop the monitor sees only resets. A board behind a USB serial bridge keeps its port through sleep.

## Talk to the board

```sh
espx monitor --input
```

`--input` sends each line you type on stdin to the board, followed by a newline. The board's output keeps printing as before.

## Record and replay

```sh
espx monitor --record crash.jsonl --until 'PANIC' --timeout 5m
espx replay crash.jsonl
espx replay crash.jsonl --fast --json
```

`--record PATH` writes every event, plus the raw bytes as `bytes` events in hex, to a newline-delimited JSON file. `espx replay PATH` plays it back with its original timing, or as fast as it can with `--fast`. Replay sends the events through the same code path as a live board, so `--until`, `--expect`, `--reject`, `--timeout`, `--json` and the exit codes behave as they do on `monitor`.

Replay does not decode again, so it needs no ELF: a defmt recording plays back decoded on any machine. That makes a recording a bug report, a test fixture and a demo in one file. The [MCP server](https://www.espx.dev/docs/agents/mcp) plays the same files through `monitor_start` with `replay`, and the [desktop app](https://www.espx.dev/docs/desktop) records and plays them from its Recordings page.

## Sharing a board

A serial port can be open in only one process at a time. espx shares boards between its own processes through a board hub on a Unix socket, `~/.espx/hub.sock`, readable and writable by your user only.

- A running `espx monitor`, `espx run` or `espx flash --monitor` serves the hub while it runs, when nothing else does. So do `espx mcp` and the desktop app.
- Every other espx command that needs a board goes through the process that serves it, and says so:

```text
=> espx monitor holds the boards; going through it
```

What that allows:

- `espx flash` in a second terminal flashes the board a monitor is watching, and the monitor shows the new boot.
- A second `espx monitor` reads the same stream as the first.
- `espx erase`, `espx info` and `espx devices --probe` borrow the board for espflash and give it back.
- An agent and a terminal, or two agents, share one board.

While a board is in use, `espx devices --probe` and agents see who holds it, for example `espx flash` or `espx mcp (claude-code)`. When the serving process quits, the next command opens the board itself again.

## Related

- [Scripts and CI](https://www.espx.dev/docs/cli/scripting): `--until`, `--expect`, `--reject` and `--timeout`.
- [JSON events](https://www.espx.dev/docs/reference/events): every event the monitor emits.
- [`espx monitor` in the command reference](https://www.espx.dev/docs/cli/commands#espx-monitor)
