Skip to main content
Glama

flashgate

flashgate answers one specific question: the firmware you just built — does it actually run on the board?

It automates the whole chain: compile, flash over ST-Link, wait for the board to report its own identity, then drive the actual feature over the console and assert on hardware register readbacks. Any broken step ends with a non-zero exit code and a reason.

build → flash over ST-Link → board boots → evidence → probes → exit code

A remote agent driving the bench over the network (Wi-Fi laptop → wired bench, OpenOCD backend) — real output:

$ flashgate --board apollo-openocd.yaml verify --all-probes
[verify] apollo-h743: build -> flash -> boot banner -> probes
[build] OK in 1.3s, 0 warning(s)
[flash] Apollo.bin @ 0x08000000 via openocd:port=SWD
[flash] OK (written, verified, started)
FLASHGATE-BOOT board=apollo-h743 git=e87efd8-dirty build=2026-09-16T02:48:14Z rtos=FreeRTOS
[probe] led-demo: LED state-machine set/readback + PWM CCR sanity
    step 1: led-demo> led0 breath
    board: OK led0 state=BREATH
    step 2: led-demo> led0?
    board: OK led0 state=BREATH ccr=691          <- hardware register readback
    ...
[probe] led-demo: PASS (5 steps)
[record] 20260916T024814701-0-035e45ea.json  (succeeded exit=0 [6/6 checks])

中文说明 | 使用说明(推荐先读这份)

How the board testifies

Two evidence channels, picked per bench (evidence.mode: uart / swd / auto):

The firmware prints its identity over the console UART, and also publishes a 64-byte signature (magic + git sha + build time + CRC32) at a fixed RAM address that the host reads through the ST-Link alone — no serial cable needed for boot verification:

FLASHGATE-BOOT board=apollo-h743 git=2c58bd3 build=2026-08-28T07:26:35Z rtos=FreeRTOS

Both carry the git sha plus -dirty when the tree differs from HEAD, so a passing verify proves the board is running a build of your current HEAD (-dirty marks uncommitted changes; it does not fingerprint their content — the Stop hook's tree fingerprint covers that side: tracked diffs in full, untracked files and the board profile by path + size + first 4 MiB, plus the flashgate version itself, so tightening probe expectations or upgrading the tool invalidates a cached PASS. Files ignored by git and nested git repositories are outside the gate). Functional probes then send real commands and assert on the answers, including register readbacks (TIM3 CCR), not firmware self-reports:

- send: "led0?"
  expect: "OK led0 state={state} ccr={ccr:d}"   # mirror of the firmware's printf
  assert: "state == BREATH and ccr <= 1000"

Related MCP server: firmforge

Quick start

pip install -e .                 # Python 3.11+
pip install -e "."                # MCP server included since 0.10.0
pip install -e ".[bench]"        # optional remote bench (device-connect)

flashgate doctor                 # ST-Link / serial / toolchain sanity
flashgate doctor --export checkup.md --redact   # a sendable checkup page
flashgate verify --all-probes    # build → flash → evidence → sha → probes
echo $?                          # 0 = the board confirms it works

Requires an ST-Link; a USB-TTL adapter on the console UART adds probes. The repo ships a complete buildable example for the ALIENTEK Apollo STM32H743 (examples/apollo-h743/) with the Stop hook pre-wired, so a fresh clone verifies out of the box once wired up.

Exit codes

code

meaning

0

verified

1

build failed

2

flash failed

3

board stayed silent (no banner / no signature within timeout)

4

error string seen on serial (HardFault, assertion)

5

on-board identity ≠ repo state (git sha or board name) — or the identity evidence channel could not be reset: a failed pre-start signature wipe, or a readback that ANSWERED wrongly — nonzero, or a truncated rc-0 dump (the wipe is read back and verified; a backend silently lying about it is caught) — fails closed (exit 5, start withheld); a readback that cannot RUN at all is an environment failure (exit 6). A surviving old-boot signature must never count as a pass

6

environment error (no ST-Link / serial / tools) — including probes explicitly required via --probe/--all-probes but the console UART is unavailable: a check that cannot run never counts as a pass; also doctor --export / records --export when the file cannot be written

7

functional probe failed

Contributing

Board profiles, probes, fixes and docs are welcome — see CONTRIBUTING.md for the setup and contribution terms. For a release gate that does not depend on the Stop hook (the board signs off in CI before a tag publishes), see the official GitHub Actions recipes in docs/ci-recipes.md.

The Stop hook

hooks/flashgate_stop.py is a Claude Code Stop hook (any harness implementing the same hook contract works). When the agent tries to finish after touching watched firmware files, the hook fingerprints the tree (plus the board profile — editing verification semantics must not reuse a cached green) and allows instantly if that exact state already passed hardware verify (~0.7 s cached). Otherwise it runs the full verify on the real board and blocks the stop on failure, feeding the agent the board's testimony:

[flashgate] BLOCKED (attempt 1/2): firmware changes are not verified on hardware (verify rc=7).
[flashgate] last verify output:
    step 1: led-demo> led0 breath
    board: OK led0 state=OFF          ← readback exposes the silent no-op

The same broken tree is blocked at most twice, then released with a loud warning — the session can never wedge, and a failure is never silently swallowed.

One verify at a time per bench: concurrent verifies (a user-level and a session-level Stop hook firing on the same stop, or a manual run racing the hook) serialize on an OS-owned lock file under the firmware's .flashgate/ instead of fighting over the console serial port — the second one waits (default 300 s, FLASHGATE_VERIFY_LOCK_WAIT), and a timed-out wait is a truthful exit 6 ("bench busy"), never a misleading serial error. Register the hook at ONE level only: in the common case stacking now just costs a redundant second verify; on a very slow bench it can still exhaust the hook's own subprocess timeout, so it is a crutch, not a supported setup.

Verification records

Every verify — passing or failing — leaves an evidence record at <firmware>/.flashgate/records/<ts>-<exit>-<fingerprint8>.json: the per-check verdicts (build/flash/boot/identity/probe:*, with skipped meaning never executed, never a silent absence), the raw evidence behind them (banner line, SWD signature fields, console tails, failing probe transcripts), the artifact sha256, and the exact tree+profile+tool-version identity the verdict applies to. Every record also carries a coverage block — the "what this PASS proves" statement: what was verified, what was NOT (physical effects, everything outside the listed probes, environmental conditions), plus the board profile's own caveats (coverage.notes) — a green record never reads as "all functionality passed". The MCP verify tool returns the same record inline as data.record. Format: docs/record-schema.md. Keep .flashgate/ in your firmware repo's .gitignore (the shipped example does), or every record write churns the fingerprint. A record that cannot be written is a warning, never a changed exit code — and a crashed run still leaves one. The newest ~500 records are kept (best-effort pruning). flashgate verify --json prints this run's record as pure-ASCII JSON on stdout (human logs move to stderr) for scripting — safe on any console codepage.

To hand a record to vendor support, export the archive as one sendable page: flashgate records lists what is retained, flashgate records --export case.md [--all] [--redact] writes it (.json for JSON). The export re-renders what the record already holds — coverage block and raw evidence included — and --redact scrubs the workstation's identity through the same util doctor --export --redact uses (paths keep only their basename). A record that cannot be parsed is named, never silently dropped; an empty selection or an unwritable target exits 6 rather than leaving a file that was never written.

Remote bench (device-connect, Stage 2)

Expose this bench to any agent on the network over Arm's device-connect protocol — four named RPCs over a BenchDriver core, nothing else (no arbitrary shell, no path arguments; the board a bench serves is fixed by its profile):

pip install "flashgate[bench]"          # optional extra -> device-connect-edge
DEVICE_CONNECT_ALLOW_INSECURE=true DEVICE_CONNECT_DISCOVERY_MODE=d2d   flashgate --board boards/apollo-h743.yaml bench-serve

Remote callers discover device_type=flashgate-bench and use describe_bench / start_verify / get_operation / cancel_operation, plus a verify_completed event per operation at its terminal state (an operation drained during server shutdown does not emit one — polling remains the authoritative contract). start_verify returns an op_id immediately (single verify at a time — a client retrying over a flaky network can never trigger a second flash); poll get_operation to the terminal snapshot, which carries the exit code and the run's full evidence record. Stop the server without hunting PIDs: flashgate --board <profile> bench-serve --stop (it drains the in-flight operation, then exits).

The red line for every consumer: the mesh wraps any normally-delivered reply as success: true — including a busy bench answering {"error": "busy"}. Judge verification ONLY by the operation payload (state / exit_code / the record's checks), never by transport success. Acceptance on the Apollo bench: the same firmware input produces identical local and remote domain results (tree fingerprint and per-check verdicts equal; artifact_sha256 differs by design — it identifies the BUILD, which embeds its timestamp, while the tree fingerprint identifies the SOURCE).

Deployment notes (from the first real cross-host test, wired host

  • Wi-Fi laptop, 2026-09-15):

  • Multicast discovery does not cross all wired↔wireless routers. If discovery finds nothing across machines but ping works, switch to unicast: on the bench host set ZENOH_LISTEN=tcp/0.0.0.0:7447 before bench-serve; on the client set MESSAGING_URLS=tcp/<host-ip>:7447.

  • Open UDP 7446 (multicast scouting) or TCP 7447 (unicast) inbound on the host's firewall; a Wi-Fi client set to "Public network" blocks the announcements it needs to receive.

  • One bench-serve per bench: a second instance for the same firmware dir is refused at startup (a loopback lock socket, released automatically when the process dies). Before the lock existed, two same-named servers split-brained the mesh and raced each other for the board's serial port.

Third-party licensing: the bench extra depends on device-connect-edge (Apache-2.0) as a pip dependency only — flashgate stays MIT, and no device-connect source is vendored into this repository (fixes go upstream as PRs). Commercial distributions that bundle the dependency must include its LICENSE and NOTICE files.

Security posture, stated plainly: D2D mode is zero-authentication — anyone on the same LAN can discover the bench and start_verify, which FLASHES THE BOARD. Descriptions and records also carry local paths. Fine for a home bench; for anything shared, put the mesh behind authenticated infrastructure (device-connect server mode) — Stage 4 work.

Install as a Claude Code plugin

The repo doubles as a Claude Code plugin: the Stop hook, an MCP server, a board-integration skill and /flashgate commands, all at once:

pip install git+https://github.com/Lion-1209/flashgate        # CLI + hook runtime
pip install "flashgate @ git+https://github.com/Lion-1209/flashgate"        # MCP included

Then inside Claude Code:

/plugin marketplace add Lion-1209/flashgate
/plugin install flashgate@flashgate

The hook needs to know your board profile: set FLASHGATE_BOARD to your board yaml (or a repo boards/ default is used when present). Without a profile the gate stays idle and says so.

MCP server

{ "mcpServers": { "flashgate": {
    "command": "flashgate-mcp",
    "args": ["--board", "/path/to/boards/apollo-h743.yaml"] } } }

board_info, doctor, build, flash, verify, probe, console_send, console_read. Any MCP-capable agent can drive the board directly. Every tool returns a structured result envelope (status, stable code, summary, CLI exit_code, log) — never a bare log to parse. mcp 1.x and 2.x supported.

Demos

Real-hardware recordings, indexed in demo/: doctor, green-path verify, boot-timeout catch, probe catching a silent no-op, Stop-hook escalation — plus the full session of a real agent (Claude Code harness; recorded with GLM-5.2 behind the Anthropic-compatible endpoint) getting blocked, diagnosing the firmware↔profile contract, fixing both sides, and passing on hardware (24 MB GIF, release asset).

Debug backends (Phase 2)

The verify pipeline is backend-agnostic: flash.adapter: in the board profile picks the probe tool — cubeprogrammer (default, the original implementation), openocd (same ST-Link, no ST toolchain needed, and the standard route to Linux/ARM64 bench hosts like a Raspberry Pi), or fake (scripted, for tests). Validated on the same Apollo board: swapping to openocd is a one-line profile change — verify stays green with identical records, zero upper-layer edits, and runs slightly faster. OpenOCD is discovered via PATH or $OPENOCD_BIN; the target script maps from the MCU family (STM32H7* -> stm32h7x, override with flash.openocd_target).

Board profiles

One yaml per board (boards/): build command, artifact, flash address (flash.adapter: picks the debug backend), serial adapter hints, banner template, probes, watch globs. The console-side USB adapter is a property of your bench, not the board — port resolution goes explicit serial.port / FLASHGATE_SERIAL_PORT, then VID/PID hint, then the sole serial port, with the banner match as the final identity proof. See the guide for the firmware-side integration recipe (three levels, with code) and the full profile field reference.

Status

Boot gate, probe gate, Stop hook, MCP server, SWD signature channel, verification records (per-check evidence with artifact hashes), the remote bench over device-connect (validated cross-host), and a second debug backend (OpenOCD, validated on the same board) — all on real hardware. Windows-first; Linux/macOS untested.

License

MIT


中文说明

flashgate 回答一个很具体的问题:刚编译出来的固件,烧到板子上到底能 不能跑。它把整条链路自动化:编译、ST-Link 烧录、等板子报告身份、经 串口实际调用功能并断言,任何一步断了就以非零退出码结束。

完整的使用说明在 docs/GUIDE.md:接线、安装、第一次 验证、给自己的板子写档案、探针写法、Stop hook 和 MCP 的配置、排错。

要点:

  • 板子有两种方式自证:串口 banner,或者在固定 RAM 地址发布 64 字节 签名(后者只靠 ST-Link 就能验证,不用串口线)

  • 版本身份带 -dirty 语义,验证通过意味着板上跑的就是当前工作区

  • 探针下真命令、断言硬件寄存器读回值;响应报的是实际状态不是回声, 静默失效的设置第一步就会露馅

  • 每次验证(无论成败)都留一份证据记录:逐项检查结论、板子的原话、 产物哈希——事后可审计"当时验证的是什么、板子说了什么"

  • bench-serve 可以把整个台架挂上局域网:远程 agent 用 device-connect 协议发现它、请求真机验证、拿回带证据的结论(跨机实测通过)

  • Stop hook 挂进 Claude Code:agent 改了固件没过真机验证就说"完成", 会被拦下并收到板子的失败证词;同一棵坏树最多拦两次,之后放行但 打警告,会话不会被卡死

  • 仓库带完整的示例固件(examples/apollo-h743),接好线 clone 下来 就能跑通第一次验证

pip install -e "."
flashgate doctor                  # 体检
flashgate doctor --export checkup.md --redact   # 可发送的体检单(脱敏)
flashgate verify --all-probes     # 完整验证
echo $?

六个真机演示 GIF 在 demo/,包括一段完整的 Claude Code 会话: agent 改固件、被拦、自己定位到固件与板卡档案的契约不一致、两侧改齐、 真机通过后放行。

MIT License

Available Tools

8 tools
board_infoA
Read-only

Discover what hardware you are working with: the active board profile.

Call this FIRST in any session — it tells you the board identity
(name, MCU), where the firmware builds (firmware_dir, artifact), how
it flashes (flash connection), and — most importantly — which
functional probes exist (the "probes" list holds the names the probe
tool accepts). Read-only; touches neither host nor board.

Result: data carries the full profile; warnings flag an unloadable
probes section (fix the board YAML before relying on probes).
ParametersJSON Schema
NameRequiredDescriptionDefault
boardNoPath to the board profile YAML (e.g. boards/apollo-h743.yaml). Omit to use the server's --board argument, else the default search path.

Output Schema

ParametersJSON Schema
NameRequiredDescription
codeYes
dataNo
policyNo
statusYes
summaryYes
evidenceNo
warningsNo
exit_codeNo
schema_versionNo

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only supply readOnlyHint, and the description reinforces that with 'Read-only; touches neither host nor board.' More valuably, it discloses failure semantics that annotations cannot express: warnings flag an unloadable probes section and the caller must fix the board YAML before trusting probes. That is real behavioral context beyond the structured fields.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the purpose and the call-first directive, and the result paragraph is tightly packed. The parenthetical emphasis ('most importantly') is slightly editorializing, but no sentence is wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, the description need not enumerate return fields, yet it still summarizes the data/warnings split so the agent knows how to interpret results. Purpose, ordering, safety, and failure handling are all covered for a single-parameter read tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the single 'board' parameter is fully documented there, including the omit-to-use-server-argument fallback. The description adds no syntax, format, or precedence detail for the parameter, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Discover what hardware you are working with: the active board profile') and enumerates the concrete payload (name, MCU, firmware_dir, artifact, flash connection, probes). An agent can distinguish it from siblings like doctor, build, and flash without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit ordering guidance ('Call this FIRST in any session') and cross-references the probe tool by noting the probes list holds the names probe accepts. It does not, however, state any condition under which you should skip it or name an alternative to use instead, so it stops short of full when/when-not coverage.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

buildA
Idempotent

Compile the board's firmware (incremental — recompiles only what changed). No hardware is touched.

Mostly useful on its own for a fast failure loop; verify runs the
same build internally, so you don't need this before verify. Result:
succeeded + exit_code 0 = clean build; failed + BUILD_FAILED = the
compiler output in data.log names the offending file and line. The
binary lands at the profile's artifact path, ready for flash.
ParametersJSON Schema
NameRequiredDescriptionDefault
boardNoPath to the board profile YAML (e.g. boards/apollo-h743.yaml). Omit to use the server's --board argument, else the default search path.

Output Schema

ParametersJSON Schema
NameRequiredDescription
codeYes
dataNo
policyNo
statusYes
summaryYes
evidenceNo
warningsNo
exit_codeNo
schema_versionNo

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With only idempotentHint available, the description carries the behavioral load fully: it discloses incrementality, that no hardware I/O occurs, the two result shapes (succeeded/exit_code 0 vs failed/BUILD_FAILED), where diagnostics surface (data.log naming file and line), and where the artifact lands. These are traits the annotations do not cover.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the operation and its incremental/non-hardware nature, then moves to routing and outcome semantics. Every sentence is functional — the result-code and artifact-path sentences directly support post-call interpretation.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite an output schema existing, the description adds interpretive value (log file naming the offending line, artifact path readiness for flash) rather than repeating return structure, and the parameter gap is covered by the schema. Nothing needed to call or interpret this tool is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the single 'board' parameter is fully documented with default and fallback behavior, so the schema does the work. The description adds no parameter-level detail beyond what is already structured, which is the expected baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Compile the board's firmware') and immediately scopes it with 'incremental — recompiles only what changed' and 'No hardware is touched', which cleanly separates it from flash and probe. An agent can identify the operation without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly frames when to use it ('a fast failure loop') and when it is unnecessary ('verify runs the same build internally, so you don't need this before verify'), naming the sibling that subsumes it. This is precisely the kind of routing guidance that prevents redundant calls.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

console_readA
Read-only

Listen passively: capture everything the firmware prints on the console for the given number of seconds, sending nothing.

Use it to watch boot banners, self-test prints, or fault dumps
(HardFault traces appear here). Output lands in data.text; a fully
silent window is reported as "(console silent)" in the summary —
which for a just-reset board usually means wiring or baud-rate
trouble rather than a healthy quiet firmware. Read-only.
ParametersJSON Schema
NameRequiredDescriptionDefault
boardNoPath to the board profile YAML (e.g. boards/apollo-h743.yaml). Omit to use the server's --board argument, else the default search path.
secondsNoSeconds to listen passively, sending nothing; below 0.1 it is clamped up (typical 2.0). Large values block for that long.

Output Schema

ParametersJSON Schema
NameRequiredDescription
codeYes
dataNo
policyNo
statusYes
summaryYes
evidenceNo
warningsNo
exit_codeNo
schema_versionNo

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare readOnlyHint=true, and the description agrees ('Read-only') rather than contradicting. It adds real context beyond the annotation: large values block for that long, silent windows are reported as '(console silent)', and silence after reset usually indicates wiring or baud trouble. It stops short of describing the return shape in detail, relying on the output schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose is front-loaded in the first clause, and the diagostic aside on '(console silent)' earns its place. It is slightly verbose across three segments but no sentence is pure filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return-value documentation is not required, and the description covers timing, blocking, and failure interpretation adequately. The only minor gap is that it leans on the output schema for the exact data.text contract, which is acceptable here.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so both parameters are already documented with defaults and clamping behavior. The description only loosely restates the 'seconds' semantics ('for the given number of seconds') and adds nothing new about 'board', so baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('capture everything the firmware prints on the console') and pins the passive/silent scope ('sending nothing'). This clearly separates it from the sibling console_send, which an agent can distinguish without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete usage contexts: watch boot banners, self-test prints, or fault dumps. It implies the alternative ('sending nothing') but never names console_send explicitly, so the routing guidance is clear rather than exhaustive.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

console_sendA

Talk to the firmware directly: send ONE command line on the console UART and collect its answer.

Example: line "led0?" — the firmware replies with its LED state and
the live PWM register value (a hardware readback, not a cached
variable). The command set is board-specific — board_info and the
board's probe definitions show the known commands; unknown commands
typically answer "ERR unknown-cmd". The reply lands in
data.response within wait_s seconds; silence is reported as
"(no response)" in the summary + a warning — check wiring before
concluding the firmware is dead.
ParametersJSON Schema
NameRequiredDescriptionDefault
lineYesOne console command line to send, e.g. "led0?". Written verbatim — embedded newlines dispatch multiple commands, and over-long lines are dropped by the firmware console buffer. The command set is board-specific; board_info and the board's probe definitions list the known commands.
boardNoPath to the board profile YAML (e.g. boards/apollo-h743.yaml). Omit to use the server's --board argument, else the default search path.
wait_sNoSeconds to wait for the firmware's answer after sending; below 0.1 it is clamped up (typical 1.0). Large values block for that long.

Output Schema

ParametersJSON Schema
NameRequiredDescription
codeYes
dataNo
policyNo
statusYes
summaryYes
evidenceNo
warningsNo
exit_codeNo
schema_versionNo

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations (readOnlyHint=false, openWorldHint=true) only signal that this mutates device state; the description goes much further by disclosing the response channel (data.response), the wait_s timing window, the '(no response)' plus warning behavior on silence, the 'ERR unknown-cmd' fallback, and that replies are live hardware readbacks rather than cached values. That is exactly the extra behavioral context annotations cannot carry.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action and example, and every sentence carries at least some operational value. The board-specific command guidance is however repeated in the description and again in the line parameter, which is mild redundancy rather than wasted content.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, yet the description still usefully names the response field, the timing window, and the failure signals, leaving nothing an agent needs in order to invoke and interpret this tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so line, board, and wait_s are already fully documented including the verbatim-writing and buffer-overflow behavior. The description reinforces the 'led0?' example and board-specific command set but adds no parameter syntax or constraints beyond the schema, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('send ONE command line on the console UART and collect its answer') with an explicit cardinality constraint that separates it from passive read siblings like console_read. An agent can tell this is the active command-dispatch tool without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear context for use — direct firmware interrogation, board-specific command set discoverable via board_info and probe definitions — and tells the agent how to interpret 'ERR unknown-cmd'. It does not explicitly say when to prefer console_read or another sibling over this tool, so it falls short of a full when/when-not/alternatives statement.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

doctorA
Read-only

Diagnose the bench: is the ST-Link probe visible, is the console serial port resolvable, is the cross toolchain installed?

Run this before anything else when a board operation fails — and
ALWAYS when a tool returns status "incomplete" or code
CAPABILITY_UNAVAILABLE; the report names the exact missing link.
Read-only. Findings are listed in data.log under "issues:"; an empty
problems list with exit_code 0 means every prerequisite is healthy.
ParametersJSON Schema
NameRequiredDescriptionDefault
boardNoPath to the board profile YAML (e.g. boards/apollo-h743.yaml). Omit to use the server's --board argument, else the default search path.

Output Schema

ParametersJSON Schema
NameRequiredDescription
codeYes
dataNo
policyNo
statusYes
summaryYes
evidenceNo
warningsNo
exit_codeNo
schema_versionNo

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare readOnlyHint=true, and the description adds useful context about what the report contains (data.log with 'issues:' list, empty problems + exit_code 0 means healthy). It doesn't cover whether findings are re-runnable, timing, or side effects, but for a read-only diagnostic the disclosure is strong.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences that are front-loaded with purpose, then usage conditions, then output interpretation. No filler, every clause carries information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers purpose, preconditions, and output semantics (issues list, exit code). With an output schema present and annotations covering safety, this is nearly complete. Could mention board profile precedence more clearly, but that's in the schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and the parameter itself has a detailed description in the schema. The tool description adds no parameter-level information beyond what's in the schema, so baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (diagnose) and a precise set of checks (ST-Link probe visibility, console serial resolvability, cross toolchain installed). This is clearly distinguishable from siblings like probe or board_info, which perform operations rather than environment diagnostics.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states when to run it: 'before anything else when a board operation fails' and 'ALWAYS when a tool returns status "incomplete" or code CAPABILITY_UNAVAILABLE'. It routes the agent to this tool in specific failure conditions, which is exactly what usage guidance should do.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

flashA
Destructive

Write the built firmware to the board's flash over ST-Link, verify the write, then start the application. DESTRUCTIVE: whatever runs on the MCU is replaced.

Flashes the artifact from the last build — call build first if
sources changed since. Tries up to 3 times on transient probe
errors. Any failure — including a missing ST-Link or CubeProgrammer —
surfaces as failed + FLASH_FAILED, exit_code 2; data.log carries the
programmer output. Run doctor to tell an environment problem (no
probe / no tools) apart from a write failure.
ParametersJSON Schema
NameRequiredDescriptionDefault
boardNoPath to the board profile YAML (e.g. boards/apollo-h743.yaml). Omit to use the server's --board argument, else the default search path.

Output Schema

ParametersJSON Schema
NameRequiredDescription
codeYes
dataNo
policyNo
statusYes
summaryYes
evidenceNo
warningsNo
exit_codeNo
schema_versionNo

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already flag destructiveHint=true, and the description reinforces with concrete consequences ('whatever runs on the MCU is replaced'). Beyond that it discloses retry policy (up to 3 attempts on transient errors), failure semantics (FLASH_FAILED, exit_code 2), and where output lands (data.log), all of which go beyond the annotation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the destructive warning and primary action, followed by dependency, retry, and failure-handling detail. Every sentence carries distinct, actionable information with no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists so return values need not be explained, yet the description still covers dependencies, retries, and failure routing. Combined with the destructive annotation, an agent has everything needed to call it safely and interpret failures.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Only one optional parameter and schema description coverage is 100%, so the schema fully documents the board profile path including fallback behavior. The description adds no additional parameter meaning, which matches the baseline 3 when the schema does the work.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('write the built firmware to the board's flash over ST-Link'), plus the follow-on actions (verify, start application). It is clearly distinguishable from siblings like build, verify, and probe.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly routes the agent: 'call build first if sources changed since' and 'Run doctor to tell an environment problem apart from a write failure.' It names both the dependency and the diagnostic alternative with the condition that selects each.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

probeA

Exercise the firmware ALREADY RUNNING on the board with its defined probes: each probe sends console commands and asserts on the board's answers — including live register readbacks (e.g. the timer value actually driving an LED). No rebuild, no reflash.

names picks specific probes (valid names are in board_info's
"probes" list); omit it or pass [] to run all. Probes need the
console UART: without it the result is incomplete +
CAPABILITY_UNAVAILABLE — never a pass. failed + PROBE_FAILED means an
assertion did not hold; data.log shows the exact step, the board's
last response, and which value was off.
ParametersJSON Schema
NameRequiredDescriptionDefault
boardNoPath to the board profile YAML (e.g. boards/apollo-h743.yaml). Omit to use the server's --board argument, else the default search path.
namesNoProbe names to run, taken from board_info's "probes" list. Omit or pass [] to run every defined probe.

Output Schema

ParametersJSON Schema
NameRequiredDescription
codeYes
dataNo
policyNo
statusYes
summaryYes
evidenceNo
warningsNo
exit_codeNo
schema_versionNo

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With only readOnlyHint=false to go on, the description carries the burden well: it discloses the console UART dependency, states that missing UART yields CAPABILITY_UNAVAILABLE and 'never a pass,' decodes failed + PROBE_FAILED as a failed assertion, and points to data.log for the exact step and board response. It even discloses that live register readbacks occur.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Densely front-loaded: capability first, parameter behavior second, failure semantics last. Every sentence is informative, though the names/omit-[] sentence partly duplicates the schema and could be trimmed.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need no prose, yet the description still covers the ambiguous outcome cases (CAPABILITY_UNAVAILABLE, PROBE_FAILED) that an agent must interpret. Nothing needed to call this tool correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the schema description for 'names' already says it draws from board_info's probes list and that omit/[] runs all, so the description largely restates structured data. The cross-reference to board_info is mildly useful but adds little beyond the schema baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('exercise the firmware ALREADY RUNNING ... with its defined probes') and immediately distinguishes itself from build/flash siblings via 'No rebuild, no reflash.' It also names the mechanism (sends console commands, asserts on answers) so an agent knows exactly what class of operation this is.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear context for use: probes run against already-flashed firmware, names selects subsets from board_info's "probes" list, and omit/[] runs all. It does not explicitly contrast with the closest siblings (verify, console_send/console_read), leaving some routing to inference, but the when-to-use picture is solid.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

verifyA
Destructive

The hardware gate — the authoritative answer to "does this firmware actually work on the board?".

status=succeeded means the BOARD ITSELF booted the exact tree you are
on (its reported git sha matches the working tree) and every
functional probe passed. Trust no other signal; a clean build is not
a pass.

What it does: rebuild the tree, flash over ST-Link, start the app,
then require boot evidence proving WHICH build is running (UART
banner; or, without a serial cable, an SWD RAM signature — a stale
signature is wiped and read-back verified before start; a wipe that
fails, or whose readback answers wrong or cannot run at all, fails
closed), then run every defined probe, asserting on the board's
answers, including live register readbacks. DESTRUCTIVE: rewrites the
board's flash.

The failure code names the broken stage: BUILD_FAILED, FLASH_FAILED,
BOOT_EVIDENCE_TIMEOUT, BOOT_ERROR, IDENTITY_MISMATCH (the board runs
a different tree, or the signature wipe failed or its readback
answered wrongly — check the debug probe, not the build),
CAPABILITY_UNAVAILABLE (a required check could not run — most often
the console UART, or a readback that cannot run at all: environment
failure, check named, start withheld), PROBE_FAILED. Full transcript
in data.log; data.record is this run's persisted evidence record,
data.record_dir where the audit trail accumulates.

Report the status and code verbatim; never claim success from the
build step alone.
ParametersJSON Schema
NameRequiredDescriptionDefault
boardNoPath to the board profile YAML (e.g. boards/apollo-h743.yaml). Omit to use the server's --board argument, else the default search path.

Output Schema

ParametersJSON Schema
NameRequiredDescription
codeYes
dataNo
policyNo
statusYes
summaryYes
evidenceNo
warningsNo
exit_codeNo
schema_versionNo

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes far beyond the single destructiveHint annotation: discloses that it rebuilds, flashes over ST-Link, starts the app, requires boot evidence (UART banner or SWD RAM signature with fail-closed wipe/readback), and enumerates all failure codes with their meanings. Explicitly flags DESTRUCTIVE flash rewrite and the persisted output files.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core identity before the operational detail, and uses 'What it does:' style structure. Dense and long, but almost every clause carries behavioral meaning for a complex destructive operation, with minimal filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers the full lifecycle, the success/failure semantics, the destructive impact, and where transcript/record artifacts land (data.log, data.record, data.record_dir). With the output schema present, no return-value detail is missing for an agent to call and interpret this tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Only one optional parameter (board) with full schema description coverage and a clear default/fallback stated in the schema. The description adds no board-path syntax or precedence detail beyond the schema, so the baseline 3 for high coverage applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a precise verb+resource ('the hardware gate', 'does this firmware actually work on the board') and defines success concretely (board booted the exact tree, probes passed). Explicitly distinguishes itself from siblings: 'a clean build is not a pass' separates it from build/flash/probe.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Strongly routes the agent away from weaker signals ('Trust no other signal; a clean build is not a pass') and frames itself as the authoritative final gate. It stops short of an explicit when-not-to-use statement or naming a specific alternative tool to run first.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 8 tool updatesv0.1.0
    • First observedboard_info
    • First observedbuild
    • First observedconsole_read
    • First observedconsole_send
    • First observeddoctor
    • First observedflash
    • First observedprobe
    • First observedverify

TDQS

A4.3/5.0

Scored across 8 tools

Disambiguation4/5

board_info, doctor, build, and flash each target a distinct stage of the embedded workflow, and the console tools split cleanly into active (console_send) vs passive (console_read). The one area of potential confusion is verify vs. build/flash/probe, since verify internally does all three, but the descriptions explicitly clarify the relationship and when to use each.

Naming Consistency4/5

build, flash, verify, probe, and doctor form a coherent set of single-word action verbs, and the console_ prefix groups the two UART tools. board_info and doctor are the mild deviations (noun/noun-ish vs. pure verb), but the convention is largely readable and predictable.

Tool Count5/5

Eight tools is well-scoped for an embedded build/flash/test server, with each tool earning its place across the discover-diagnose-build-flash-verify-probe lifecycle. Nothing is redundant or trivial.

Completeness4/5

The surface covers the full firmware lifecycle: discovery, environment diagnostics, build, flash, hardware verification, probe execution, and direct console interaction. A minor gap is the lack of an explicit reset/erase tool, though verify and console_read implicitly handle reset-adjacent scenarios.

Maintenance

ActivityActive
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    A
    maintenance
    Agentic Hardware-in-the-Loop (Agentic HIL) lets coding agents develop firmware on real embedded boards: flash, reset, read UART and exchange CAN traffic, diagnose and fix. Local, policy-gated MCP tools support OpenOCD, pyOCD and STM32CubeProgrammer, with pytest for CI.
    44
    890 PyPI
    18
    Apache 2.0
  • A
    license
    Not graded
    quality
    B
    maintenance
    MCP server for firmware verification in MCU development, exposing a five-stage pipeline (Detect, Review, Build, Flash, Verify) as tools for AI agents to compile, flash, and verify firmware on Arduino boards.
    1
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Enables MCP-capable agents to drive a real FPGA toolchain end to end—simulating, asserting, synthesizing, scanning JTAG, capturing on-chip waveforms, and configuring real silicon behind confirmation gates.
    45
    Apache 2.0