# Projects

Create an esp-hal project with espx new, pick its chip, board and options, and read its dependencies.

`espx new` creates a bare-metal Rust project with esp-generate, the esp-rs project generator, and adds the files espx and coding agents read. Everything else espx does works on any directory that holds a `Cargo.toml`, so projects you made another way work too.

## Create a project

```sh
espx new blinky
```

This creates `./blinky` for the ESP32-C6. Underneath it runs:

```sh
esp-generate --chip esp32c6 --skip-update-check --option log --headless --output-path . blinky
```

Pass `--dir` to create the project somewhere else. espx creates that folder if it is missing and refuses to touch a project folder that already exists.

```sh
espx new blinky --dir ~/code      # creates ~/code/blinky
```

The name must work as a cargo package name: ASCII letters, digits, `-` and `_`, starting with a letter, at most 64 characters. espx also refuses Rust keywords (`fn`, `Self`), crates built into Rust (`std`, `core`, `alloc`, `test`), cargo's own folder names (`build`, `deps`, `examples`, `incremental`) and Windows device names (`con`, `nul`, `com1`). If esp-generate fails, espx removes the half-made folder.

## Pick a chip

```sh
espx new blinky --chip esp32c3
```

The default is `esp32c6`. `espx chips` lists every id. The RISC-V chips build with the stable toolchain and the targets `espx setup` added. An Xtensa chip (esp32, esp32s2, esp32s3) needs Espressif's Rust fork first; without it `espx new` stops with `xtensa_toolchain_missing` and names the `espx setup --chip` command to run. See [Xtensa chips](https://www.espx.dev/docs/reference/xtensa).

## Pick a dev board

```sh
espx new blinky --board xiao-esp32c6
```

`--board` takes an id from `espx boards`. It selects the board's chip, so you do not pass `--chip`. Passing a `--chip` that differs from the board's chip is an error (`board_chip_mismatch`).

The board id is recorded as a `Board:` line in the generated `README.md` and `AGENTS.md`, together with the board's LED, BOOT button and UART pins and a link to its documentation. espx does not generate pin code from it. The facts are there for you and for agents to read before they drive a GPIO. `espx board xiao-esp32c6` prints the same facts. [Chips and boards](https://www.espx.dev/docs/reference/chips) lists every board espx knows.

## esp-generate options

`-o` (or `--option`) passes an option straight to esp-generate. Repeat it for several:

```sh
espx new sensor -o embassy -o unstable-hal -o alloc
espx new radio -o wifi
espx new crashy -o esp-backtrace
```

espx turns on `log` by default. `-o defmt` replaces it, because esp-generate refuses the two together. espx validates none of the options; esp-generate reports a name it does not know. Some options worth knowing:

| Option          | What it adds                                                                                                                                     |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `esp-backtrace` | A panic handler that prints the panic message and a backtrace. Without it a panic prints no addresses, so espx cannot resolve it to source lines |
| `defmt`         | Compact log frames that espx decodes on the host against the release binary                                                                      |
| `embassy`       | Async tasks on the embassy executor; pair it with `unstable-hal`                                                                                 |
| `alloc`         | A global allocator from esp-alloc, for `Vec`, `String` and `Box`                                                                                 |
| `wifi`          | esp-generate's Wi-Fi setup                                                                                                                       |
| `probe-rs`      | esp-generate's probe-rs setup                                                                                                                    |

To pick options in esp-generate's own terminal UI, pass `-i`. It needs a terminal; without one espx stops with `not_a_tty`.

## Bind a port or a board

Two flags tie a new project to the hardware on your desk:

```sh
espx new blinky --port /dev/cu.usbmodem101
espx new blinky --board-id 58:8C:81:53:AD:2C
```

| Flag            | Writes                                                 | Effect                                                                           |
| --------------- | ------------------------------------------------------ | -------------------------------------------------------------------------------- |
| `--port P`      | `espflash_ports.toml` with `[connection] serial = "P"` | espx and espflash use that port for this project                                 |
| `--board-id ID` | `espx.toml` with `[board] id = "ID"`                   | `flash`, `run` and `monitor` use that physical board, and AI agents may flash it |

A board id is the board's USB serial number (on native-USB chips that is its MAC address), or the port path when the board reports no serial number. `--board-id` also takes a port or a name from `~/.espx/boards.toml`. `espx devices` prints the ids. [Boards and ports](https://www.espx.dev/docs/cli/boards) explains how espx picks a board and why binding one matters.

## What espx new writes

esp-generate writes the cargo project: `Cargo.toml`, `.cargo/config.toml` with the target and the espflash runner, `rust-toolchain.toml`, and the firmware under `src/` (the entry point is `src/bin/main.rs`). It also runs `git init`. espx then adds:

| File                  | Contents                                                                                                                                                                                          |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `README.md`           | The espx commands for this project, how to pin a port, and how to use plain `cargo run --release`. With `--board`, the `Board:` line                                                              |
| `AGENTS.md`           | The espx loop for coding agents, the chip and target, the board's pins, the bound board, the esp-hal version and the examples link. See [Agent context](https://www.espx.dev/docs/agents/context) |
| `espx.toml`           | Only with `--board-id`: the `[board]` section                                                                                                                                                     |
| `espflash_ports.toml` | Only with `--port`: the pinned serial port                                                                                                                                                        |

## What the project depends on

```sh
espx deps
```

`deps` reads `Cargo.lock` (or the lockfile of an enclosing workspace) and prints every resolved version of esp-hal, esp-radio, esp-rtos, esp-println, esp-backtrace, esp-alloc, embassy-executor and defmt. A crate that resolves to two versions is listed twice. `--json` adds each crate's `source`. A fresh project has no `Cargo.lock` until the first build, so run `espx build` first.

`espx context` prints the same versions together with the chip, the board's pins and the link to the esp-hal examples of the exact release in `Cargo.lock`. It is the text `espx new` writes to `AGENTS.md`, plus the boards attached right now.

```sh
espx context
espx context --board xiao-esp32c6   # when the project does not record its board
```

## Projects from elsewhere

A project is a directory with a `Cargo.toml`. espx reads the target from `.cargo/config.toml`, the toolchain channel from `rust-toolchain.toml` and the binary name from `Cargo.toml`, and derives the chip from the target. cargo stays the authority on how to build it. Pass `--dir` to any project command to point at it without changing directory.

## Related

- [Build and flash](https://www.espx.dev/docs/cli/build-and-flash)
- [Agent context](https://www.espx.dev/docs/agents/context)
- [`espx new` in the command reference](https://www.espx.dev/docs/cli/commands#espx-new)
