Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Typical Workflow — Build, Deposit, Review

This is the standard end-to-end flow your AI assistant runs when you ask it to build firmware. Read it once and the rest of the manual makes a lot more sense.

The first 8 steps are the build loop. Steps 9–10 are the sovereignty loop: every build becomes a signed triple in ~/maker-assets/, and a browser-driving agent pushes weekly stats to the local /ops/funnel-review page so you can copy out a Markdown work report.

─── build ────────────────────────────────────────────────────────────
1. Assistant reads install://overview              → confirms your setup
2. Assistant runs doctor                           → checks everything is healthy
3. Assistant runs store_versions                   → sees IDF v5.3.1 is available
4. Assistant runs project.init (target: esp32s3)   → writes .espctl.toml
5. Assistant runs build (target: esp32s3)          → returns task_id / build_id
6. Assistant watches build.status until succeeded  → tracks progress
7. Assistant runs logs.tail to show build output   → shows you what happened
8. Assistant runs artifacts.manifest               → shows firmware size + flashable files

─── deposit ──────────────────────────────────────────────────────────
9. Assistant runs `espctl deposit add <build_id>`  → signs a triple into ~/maker-assets/

─── review (weekly, browser-driving agent) ───────────────────────────
10. Agent aggregates `espctl deposit list --since/--until --json` →
    pushes the snapshot via window.aegis.importMakerStats(...) →
    /ops/funnel-review renders metric tiles + work-report Markdown.

Here’s what each step does and why.


1. Read install://overview

Assistant → espctl: read("install://overview")
espctl → Assistant: env-var table, modes, basic setup

espctl ships its own setup guide as a resource. Reading it once at the start of a session gives the assistant an immediate picture of:

  • Which env vars you’ve set (and which you haven’t).
  • Whether it’s in remote-build mode (the default) or plan-only mode.
  • The list of AI tools and their config snippet URLs.

This is also a good first move when troubleshooting — if the resource is unreachable, espctl itself isn’t running, which is the kind of “obvious in hindsight” detail an assistant might miss without checking.

2. Run doctor

Assistant → espctl: doctor
espctl → Assistant: { status: "healthy", checks: [...], errors: [] }

doctor runs a handful of health checks (build server reachable, access key valid, project settings parse, IDF versions match). If anything is wrong, it fails fast with a structured error pointing at the offending check.

Run this every time you start a new session, even if it worked yesterday. Catches the most common “wait, why isn’t it working?” failures before you try to do real work.

3. List build server versions

Assistant → espctl: store_versions
espctl → Assistant: { versions: ["v5.2.2", "v5.3.1"], default: "v5.3.1" }

Confirms which IDF version a build will use by default and shows the alternatives. If your project pins a specific version in .espctl.toml, the assistant will note any mismatch and either use the pin or fall back to the default depending on what idf_select_version decides.

4. Initialize the project

Assistant → espctl: project.init { target: "esp32s3" }
espctl → Assistant: { project_root: "...", config_path: ".espctl.toml", ... }

Creates .espctl.toml and the build subfolder. Safe to run twice — if the project is already set up, this does nothing.

If you’re working on an existing project, skip this step. The assistant will still run validate_config against the existing .espctl.toml to make sure nothing’s broken.

5. Start the build

Assistant → espctl: build { target: "esp32s3", profile: "release" }
espctl → Assistant: { task_id: "0abf...e2", status: "pending" }

The build is sent to the build server and starts running in a sandbox. You get a task_id right away — the build itself runs in the background.

6. Watch until done

loop:
  Assistant → espctl: build.status { task_id: "0abf...e2" }
  espctl → Assistant: { status: "running", phase: "compiling", progress: 0.42 }
  wait 2s
until status == "succeeded" or "failed"

Most assistants check every 1–3 seconds. A more efficient pattern is to subscribe to the build://log/{task_id} resource and get pushed updates instead — but checking is simple and works everywhere.

7. Read the logs

Assistant → espctl: logs.tail { task_id: "0abf...e2", lines: 100 }
espctl → Assistant: { lines: [{ seq, ts, stream, text }, ...] }

Once the build finishes, pull the last N lines of output. This is what your assistant shows you as “the build log”.

If the build failed, your assistant will also run parse_build_errors to extract structured error messages — much more useful than dumping 500 lines of raw output.

8. Read the manifest

Assistant → espctl: artifacts.manifest { task_id: "0abf...e2" }
espctl → Assistant: { artifacts: [...], flash_size, flash_freq, ... }

The manifest is the official record of what the build produced and how to flash it. Your assistant can stream individual .bin files to your local disk for flashing, or hand them straight to the esphome.cloud web flasher.

Security note: Your compiled firmware may contain embedded secrets (Wi-Fi credentials, API keys). Treat .bin files as sensitive.

9. Deposit the triple

Assistant → CLI: espctl deposit add 0abf...e2
deposit-flow → ~/maker-assets/: requirement + code + verification triple, signed

Once the build manifest is in hand, espctl deposit add <build_id> converts that build into a signed (requirement, code, physical verification) triple in ~/maker-assets/. All builds — failed too — are worth depositing; failure data is part of the asset.

The MCP mirror deposit.add lets an AI agent call this directly after the build succeeds, prompting the maker only for the three fields it can’t derive (outcome, evidence, notes). Triples never leave your disk unless you explicitly run espctl deposit attest to publish to Zenodo + OpenTimestamps.

See espctl deposit for the full eight-subcommand surface.

10. Push to /ops/funnel-review for weekly review

Agent → espctl deposit list --since 2026-05-17 --until 2026-05-24 --json
Agent → chrome-mcp evaluate_script:
        window.aegis.importMakerStats({ ...aggregated snapshot... })
Agent → opens /ops/funnel-review → reads the rendered Markdown report

The same chrome-mcp / playwright-mcp agent that drove the build can aggregate this week’s espctl deposit list --json (plus tool-call counts from agent telemetry) and push the result as a MakerStatsSnapshot into the browser via window.aegis.importMakerStats.

/ops/funnel-review then renders 6 metric tiles, hardware + tool charts, 5 health checks, and a copy-paste Markdown work report — all locally, no upload.

See Weekly Maker Asset Review for the snapshot schema and the browser API contract.


Variations

This is the happy path. Real workflows often diverge:

  • Build fails at step 6 → Assistant runs parse_build_errors against the log, then the diagnose-build-error prompt. You get a structured “this is what’s wrong, here’s the fix” instead of a wall of text.
  • You change the chip target → Insert a set_target call between steps 4 and 5. The assistant warns you that this clears the build cache.
  • You need an interactive serial monitor after the build → Assistant uses the Monitor tab or espctl monitor --port /dev/ttyUSB0.
  • You want to know what the build would do without running it → Replace step 5 (build) with generate_build_plan. No side effects.

See Browser Wizard for the same flow when you’re clicking through a web page instead of chatting with an assistant, or MCP Console if you want to call the tools by hand.