Plan-only vs Remote Build
espctl can run in either of two modes. Same program, same set of features — only what they actually do is different.
Remote build is the default. When you run espctl build, it sends
your project to a build server and compiles it. You only get plan-only
mode when you explicitly ask for it.
Remote build mode (the default)
This is what you’ll use most of the time.
espctl sends your project to the build server, the build server compiles it (in a safe sandbox), and the finished firmware comes back to you.
What you get:
- “Build it” actually builds it.
- You see the live build log.
- The compiled firmware file shows up and you can download or flash it.
- You can open an interactive serial monitor on the build server.
Where does espctl send the build? It checks in this order:
- The
--remote <url>flag, if you passed one. - The server URL saved by
espctl login(in~/.config/espctl/credentials.json). https://esphome.cloud(the built-in default).
So if you’ve run espctl login --token <your-token> once, every
espctl build after that goes to your saved server automatically.
Plan-only mode
You have to ask for it — pass the --local flag:
espctl build --local --target esp32s3
In this mode, espctl can:
- Look at your project files and check that the settings are valid
- Tell you what a build would do, step by step
- Read existing build output (logs, firmware files) that you already have on disk
- Show you what ESP-IDF versions and tools the build server would use, if it were online
In this mode, espctl cannot actually compile anything. There’s no building going on.
When this is useful:
- You’re offline (airplane, train, conference WiFi).
- You’re reviewing a build before running it.
- You’re learning what the tool can do without committing to anything.
Logging in
The simplest way to set up remote builds:
espctl login --token <your-access-key>
This saves your token and the server URL to
~/.config/espctl/credentials.json. From then on, every espctl build
uses those credentials.
The credential file is restricted to owner-only permissions (0600). If espctl detects insecure permissions, it warns you.
HTTPS required. espctl rejects non-HTTPS server URLs by default. For local development only, you can override this with
ESPCTL_ALLOW_INSECURE=1in your environment.
MCP server mode (for AI tools)
When espctl runs as an MCP server (espctl mcp serve), mode detection
works differently — it uses environment variables instead of CLI
flags:
| What’s set in the environment | Mode |
|---|---|
CONTROL_BASE_URL + MCP_AUTH_SECRET both set | Remote build |
| Either variable missing | Plan-only |
This is what your AI tool’s config file controls. When you edit
.claude/settings.json, .cursor/mcp.json, etc., you’re setting these
env vars for the MCP server process.
Switching between modes
CLI users: Just pass --local when you want plan-only, or omit it
for remote. No config changes needed.
MCP server users: Edit your AI tool’s config to add or remove
CONTROL_BASE_URL and MCP_AUTH_SECRET from the env block, then
restart the AI tool. You can’t switch mid-session.
If you want both at once, configure two espctl entries with different
names (e.g. espctl-local and espctl-remote). Most AI tools let you
have several MCP services side by side.
How does espctl know which mode it’s in?
CLI (espctl build)
| What you do | Mode |
|---|---|
espctl build (logged in via espctl login) | Remote build (uses saved server) |
espctl build (not logged in) | Remote build → https://esphome.cloud |
espctl build --remote https://my-server.com | Remote build to that URL |
espctl build --local | Plan-only |
MCP server (espctl mcp serve)
| What you set | Mode |
|---|---|
CONTROL_BASE_URL + MCP_AUTH_SECRET | Remote build |
| Either env var missing | Plan-only |
You can confirm the mode any time by asking your assistant to “run doctor” — the report includes whether you’re logged in and whether the build server is reachable.
See also
- Prerequisites — what you need on your computer.
- Quick Start — a 5-minute walkthrough that uses remote-build mode.
- System Overview — what happens to a build after it leaves your computer.