agentic-hil
Provides tools for flashing and debugging STM32 microcontrollers via STM32CubeProgrammer, enabling hardware-in-the-loop firmware development.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@agentic-hilflash the current build to the dev board and run the regression tests"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Agentic HIL
Your AI agent writes the firmware, flashes it to the board on your desk, drives UART and CAN against it, reads back what the hardware actually did, and fixes what it got wrong; the run on the real board is what decides whether the work is done, and you review the pull request with that run's evidence in it.
https://github.com/user-attachments/assets/8d39ba93-beeb-484e-b9e9-d9ce79538523
Nothing in that run is staged. One restart after the install line, in a freshly created firmware project, the first sentence makes the agent set the bench up itself and the second makes the board say Hello World and prove it said it: the configuration is created over MCP with the permissions reported out loud, the firmware is written on the spot, flash_firmware and com_read go through the gate, the twelve bytes come back off the wire, and the plan it pins is run once green and once against a wrong expectation, because a test that cannot fail proves nothing. What remains in the project afterwards is the plan as a reviewable file and the run's own report: lease released, safe state confirmed, nothing quarantined.
Install
Linux / macOS (any shell):
curl -LsSf https://agentic-hil.github.io/install.sh | shWindows, in PowerShell:
irm https://agentic-hil.github.io/install.ps1 | iexThe command lands in the user bin directory of the package manager that installed it, and the installer asks that manager where it went rather than assuming: uv tool dir --bin for a uv install, and the selected interpreter itself for a pip --user one. When that directory is not on your PATH already, the installer puts it there and says so: one line in each startup file your shell reads, or on Windows the directory in front of your own Path. Open a new shell and the command is there. Pass --no-path (-NoPath in PowerShell) to keep that edit for yourself, and the installer prints the exact line instead.
One line installs the package user-local and registers the agent skill and the MCP server for every agent CLI it finds on your PATH. No admin rights required, ever, and it touches nothing inside any repository. Finding no claude, codex or opencode CLI there, it says so and writes nothing of any agent's: install the agent CLI, then run agentic-hil agent-install --agent <claude-code|codex|opencode> yourself, which is the line the installer prints for that case. Then restart your agent once, and after that one restart your agent sets this project up itself, at the first hardware question you ask it.
The line above and the checksummed route in installation run the same installer, and on a machine with nothing here yet both install the same thing, the release from PyPI: the script resolves agentic-hil[can] against the package index and carries no branch or git reference at all, and --version <x.y.z> pins one exact release instead. On a rerun it repairs what is already installed rather than forcing the public release over it: an installation reporting a .devN version (an editable checkout of this repository) is kept untouched, and a uv-managed tool installed from a path, URL or git reference is refreshed from that same recorded source rather than switched to the index. What the checksummed route adds is the script itself, read before it runs: install.sh and its install.sh.sha256 come from the same release, one is checked against the other, and the file that runs is the file you checked.
The STM32 starter is the shortest way to watch that happen on hardware: three steps on a Nucleo-F446RE, with the firmware, the test plans and one planted defect already in place.
Claude Code can also take the skill from the plugin marketplace:
/plugin marketplace add agentic-hil/agentic-hil, then /plugin install agentic-hil@agentic-hil.
The plugin carries the skill and nothing else; the MCP server itself still comes from the install line above, which registers a verified absolute executable path outside your repository.
Installation has every other path: the cmd.exe spelling, the repair run (the same line again, which reinstalls in place when agentic-hil upgrade itself fails), that checksummed route in full, registering one agent instead of all of them, driving your own package manager, setup for a bench that is already attached, the optional extras, upgrading, and every platform and debugger backend. TROUBLESHOOTING.md covers what to do when something does not start.
A first command that needs no board, in a clone of this repository: agentic-hil check-plan examples/nucleo-f446re_demo/testconfig.yaml answers All 1 test plan(s) load through the reactor's loader. and exits 0, having loaded no configuration and touched no hardware.
Agentic Hardware-in-the-Loop (Agentic HIL) is a Python package that lets a coding agent develop firmware on the real board. It exposes bounded MCP tools for probing, flashing, resetting, artifact validation, serial and CAN stimulus/feedback, reports, and logs, all without giving an agent arbitrary host or debugger access. The run on the board is the gate: the work is done when the hardware behaved, and the report that run writes is the evidence a reviewer reads. What it supports is the debug probe with its backend rather than a board, ST-Link through OpenOCD or the STM32CubeProgrammer CLI and CMSIS-DAP probes through pyOCD, so any board behind such a probe runs the same software. Each project has exactly one authoritative configuration stored outside the repository, out of reach of the agent's own file tools.
Related MCP server: Chiplab
Why
A green build is not enough in embedded development: firmware has to behave correctly on the real board, so the run on that board is the gate the work has to pass before it is done. Classic tools automate single steps (flash here, read a log there), but the moment real hardware has to respond, a human is back in the loop, which is what stops an agent from developing firmware through to that gate. Handing an agent a raw debugger shell or direct serial access instead is neither safe nor reproducible, and leaves a reviewer nothing to read.
Agentic HIL closes the gap with a small, auditable gate:
Every hardware action is validated against the selected authoritative configuration, executed with timeouts, logged to .agentic-hil/logs/, and answered with a structured JSON result (ok, error_type, summary, likely_causes, report_path, log_path) that an agent can act on and a reviewer can read afterwards. What the agent may do at all is per device and per permission, and reaching for a debugger escape hatch is what takes flashing away.
What it drives
The unit it drives is the probe with its backend, not one board: four debugger backends (OpenOCD, pyOCD, the STM32CubeProgrammer CLI, and esptool, which flashes and resets an ESP32 through the board's USB-UART bridge and opens no debug session), plus serial ports and CAN (PCAN, SocketCAN, or a custom bridge; several runs can share one bus), on Linux, macOS, and Windows, Python 3.10 or newer, all CI-tested. The worked example in examples/nucleo-f446re_demo/ runs the whole loop on an ST Nucleo-F446RE, the board this repository proves the path on rather than the boundary of what runs; installation has every backend and platform in detail.
The test reactor
A plan is how the gate is written down, and one YAML plan drives the whole bench: flash, reset, write, read with a comparator (exact text, a pattern, or a numeric range over a captured value), delays, and sessions that close themselves. Plans name logical devices; the bench configuration binds them to real hardware, so the same plan runs unchanged on every machine that has one. A failing step aborts the run, and the bench recovers itself: reap, reset into halt, probe, all attested in the run result. How plans work.
Security by construction
A device does not exist on this bench until your configuration declares it, and a call naming any other one is refused before a driver is opened: unknown_device where a run declares it, and com_port_not_configured or can_bus_not_configured where a port tool or a bus tool names it, each of those two naming the ones the configuration does declare. On a device it does declare, a generated configuration grants every permission that has a tool behind it and holds allow_raw_debugger_commands and allow_mass_erase false, the interlocked pair that refuses flashing while either is true, false by construction when MCP project_config_create generates with no loaded configuration, and the default agentic-hil init writes unless your agentic-hil.config.example.yaml opens one; a project_config_create regenerating an existing bench carries the loaded permissions back instead, either interlock included, keyed on the entry name and not on whether a probe was found before, so a pair an operator opened on a named dut placeholder survives the very call that first binds a probe to it and only a logical entry whose name the loaded configuration did not carry comes back false. agentic-hil revoke <key> takes any single grant back and agentic-hil grant <key> reopens it, from your own shell; over MCP an agent narrows its own authority and never widens it. Every hardware action is validated, leased machine-wide, and written to a SHA-256 audit chain. The authoritative configuration lives outside the workspace, where the agent cannot edit it. Enforcement sits in the tool rather than in the agent host on purpose: a host's permission system judges shell strings and differs per host, while the bench's permissions judge the hardware action itself and travel with the bench, so the CLI, pytest, CI and the test reactor all walk the same gate. A failed run still gives the bench back: it aborts with its verdict, the recovery action resets and re-reads the target, and the standing quarantine is kept for the one state no later contact can rebuild, a broken audit trail. The safety model is the short version, the security design the long one.
Quickstart: one real run
The worked example is a firmware project of its own. Plug the board in, build it, and point Agentic HIL at it from that directory:
cd examples/nucleo-f446re_demo
cmake --preset Debug && cmake --build --preset Debug # → build/Debug/nucleo-f446re_demo.elf
agentic-hil setup --agent claude-code # or: codex / opencode
agentic-hil doctordoctor checks the configuration against the attached bench and names what it finds (a missing toolchain, an unreachable probe, a target type this host cannot resolve) before anything is flashed. If the board arrived after setup ran, agentic-hil adopt-hardware fills in the probe serial, the backend executable and the COM device it left unset (--dry-run shows the plan first). On a host with OpenOCD and no STM32CubeProgrammer the probe is read from the host's own USB serial inventory, so a lone attached ST-Link binds without anybody retyping its serial; --probe-id <serial> names the board where a second probe that publishes no virtual COM port is attached beside it.
With the MCP host started from that directory, the agent drives four calls:
flash_firmware {"image_path": "build/Debug/nucleo-f446re_demo.elf"}
com_session_start {"port_id": "dut_uart"}
reset_target {"mode": "run"}
com_read {"port_id": "dut_uart", "wait_timeout_s": 5}
→ feedback contains "Hello World"The same loop runs headless as a pytest regression: pytest tests/ in that directory flashes the ELF, resets the target and asserts the boot banner on the UART. examples/nucleo-f446re_demo/ walks through both, and docs/testing.md covers writing the run down as a reviewable YAML plan instead.
Where the depth lives
If you want | Read |
to install, upgrade, add CAN, pyOCD or esptool, or look up a command | |
what the authoritative configuration declares and who may change it | |
the complete MCP tool surface and how a run is composed from it | |
to register the server in a specific MCP host | |
to write hardware tests (YAML plans or pytest) | |
why it is safe to leave an agent alone with the bench | |
a failure diagnosed | |
to point your agent at this repository |
Names: the Python distribution/install target, CLI command, repository URL, and MCP server name use agentic-hil. Python imports, pytest plugin names, fixtures, and Python examples use agentic_hil.
Development
python -m pip install -e '.[dev]'
ruff check src tests evals tools
pytest
python -m build
twine check dist/*The package is configured for PyPI publishing through GitHub trusted publishing in .github/workflows/workflow.yml. Contribution guidelines: CONTRIBUTING.md.
Security
Policy bypasses are treated as vulnerabilities; see SECURITY.md.
Support
Linux, macOS and Windows are supported equally, what is supported is the debug probe with the backend behind it (ST-Link through OpenOCD or the STM32CubeProgrammer CLI, CMSIS-DAP probes through pyOCD, an ESP32 board's USB-UART bridge through esptool) rather than any list of boards, and issues are answered within 24 hours on workdays, security reports within seven days: docs/support.md is the whole promise, including what is not promised. Ask in Discussions Q&A, show a run in Show and tell, and put a first run on your own bench, green or red, in the first run report.
License
Apache-2.0. See LICENSE.
Available Tools
44 toolsartifact_uploadAIdempotent
Store a firmware image in artifacts.upload_directory and return its artifact_id for flash_firmware or debug_start_session; no board needed. Give image_path, or filename with data_base64, else invalid_argument. Needs allow_upload, else permission_denied. The id is the sha256 of the bytes plus the lowercased extension: same bytes and extension, same id. Unsafe destination: unsafe_configured_path.
| Name | Required | Description | Default |
|---|---|---|---|
| filename | No | Bare name for data_base64, no path (like app.elf); its lowercased extension picks the format check and ends the artifact_id. A path: invalid_argument. | |
| image_path | No | Local file to store, inside the workspace and artifacts.allowed_roots (build if unset), with an allowed extension (.elf, .hex, .bin). Missing: artifact_not_found; invalid: artifact_validation_failed. | |
| data_base64 | No | The image as padded standard base64, whitespace ignored, else invalid_argument. Decoded, at most artifacts.max_upload_size_mb MiB (default 64), else artifact_too_large. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: requires allow_upload else permission_denied, enumerates failure modes (invalid_argument, unsafe_configured_path, artifact_not_found, artifact_too_large), and explains idempotency concretely (same bytes+extension → same id) rather than just asserting idempotentHint.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose and consumers, then requirements and error semantics in tight clauses; every sentence carries information. Slightly dense with enumerated error codes, but nothing is padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, and the description compensates by explaining the return value (artifact_id is sha256 of bytes plus lowercased extension) and its consumers. Input requirements, permission prerequisites, and failure modes are all covered for a 3-param tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description adds value by restating the oneOf in plain prose ('Give image_path, or filename with data_base64, else invalid_argument'), which tells the agent the two are mutually exclusive alternatives. It does not add format or size detail beyond what the schema already documents.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Store a firmware image in artifacts.upload_directory') and immediately names the downstream consumers (flash_firmware, debug_start_session) whose artifact_id this produces. An agent can distinguish it from board-requiring siblings via 'no board needed' without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Clear context: use this to stage an image for flash_firmware or debug_start_session, and explicitly 'no board needed', which separates it from hardware-bound siblings. It does not spell out when-not to use or name a direct alternative uploader, so it stops short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
bench_run_startA
Declare a run holding the devices a sequence like flash, reset, read needs until bench_run_stop or server exit, no timeout; without one the board is free between calls. All or nothing: a refused start holds none. Other devices fail undeclared_device; a second start, run_already_active; a standing incident, resource_quarantined. A single call, or flash_firmware with capture, needs no run.
| Name | Required | Description | Default |
|---|---|---|---|
| label | No | Optional, no default: free text returned as `run_label` and shown as the holder's label to anyone refused `device_busy`. | |
| wait_s | No | Seconds to wait for a device another holder has, 0 to 900. Default 0: a held device fails `device_busy` at once. | |
| devices | Yes | The devices the run holds, one selector each, all resolved before any is locked. Success returns them as `declared_devices`, with `run_label`. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Despite annotations, the description adds substantial behavioral context beyond them: all-or-nothing locking semantics, no timeout, the exact error codes for each failure mode (undeclared_device, run_already_active, resource_quarantined), and the fact that devices are free between calls without a run. This is exactly the destructive/stateful context annotations don't convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Dense but front-loaded: the core purpose comes first, then constraints, then error modes, then the exception. Every sentence earns its place, though the error-code enumeration is slightly telegraphic.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers purpose, lifecycle, failure modes, and the single-call exception. With no output schema, it appropriately omits return-value details. An agent has everything needed to call this correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so parameters are already fully documented in the schema. The description does not add syntax or format detail for label, wait_s, or devices beyond what the schema covers, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a precise verb ('Declare a run') and resource (the devices held), and explains the core concept: the run persists until bench_run_stop or server exit, and without it the board is free between calls. This distinguishes it from bench_run_stop and from single-call tools like flash_firmware.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use ('a sequence like flash, reset, read needs'), explicit when-not ('a single call, or flash_firmware with capture, needs no run'), and names the stop sibling. Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
bench_run_statusARead-only
Report whether this server has a run open (run_active), what it declared (declared_devices, run_label) and which devices it holds (held_devices); read it when unsure whether you still hold the bench. In memory only: what another process holds shows in hardware_lease_status.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=false, and the description genuinely adds value on top: it discloses that the view is "in memory only" and that state held by another process is not visible here. That is real behavioral context an agent would otherwise have to discover.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two compact sentences that front-load the returned state before the usage trigger and the isolation caveat. Dense but every clause carries information; no padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema and no parameters, the description carries the full burden of describing what comes back, and it names the four fields. Combined with the in-memory vs. cross-process caveat, an agent has everything needed to call and interpret it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so per the rubric the baseline is 4. There is nothing for the description to disambiguate, and it does not need to.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (report) plus the exact resource fields it returns (run_active, declared_devices, run_label, held_devices), so the agent knows precisely what state is read. It also distinguishes itself from hardware_lease_status by scoping itself to this server's in-memory view.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
"Read it when unsure whether you still hold the bench" gives a clear trigger, and the closing sentence names the alternative (hardware_lease_status) for the cross-process case. It stops short of spelling out a when-not for this tool beyond that pointer, and does not relate it to bench_run_start/stop.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
bench_run_stopAIdempotent
End the bench_run_start run and release its devices (released_devices). With no run open it answers run_was_active: false. A COM, CAN or debug session still open keeps its own device: open_leases, still_held_devices. With an incident open it runs the recovery recovery.auto_recover allows (by default reset into halt, then a probe re-read), reported in recovery.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations by disclosing the full state matrix: what happens with no run open, that an open COM/CAN/debug session keeps its own device (open_leases, still_held_devices), and that an open incident triggers recovery.auto_recover with the default reset-into-halt-then-probe sequence. This tells the agent exactly what side effects to expect on a mutation tool whose annotations only say idempotent and non-destructive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core action and its device-release effect before the conditional cases. The sentences are dense with return-field names but each one carries distinct behavioral information (no-run, session-held leases, incident recovery), so little is wasted; it is slightly list-like but earns its length.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema present, the description must carry the return-value burden, and it does: it names released_devices, run_was_active, open_leases, still_held_devices, and recovery, plus the default recovery sequence. Combined with the annotation profile, an agent has everything needed to call and interpret this tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing for the description to disambiguate; baseline 4 applies. The description instead spends its budget on return-field semantics, which is the right allocation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('End the bench_run_start run and release its devices') and names the counterpart tool bench_run_start, so it is immediately distinguishable from siblings like bench_run_status or test_reactor_stop. An agent knows exactly what operation this performs without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Clearly frames the trigger condition: it ends a run started by bench_run_start, and it explicitly handles the no-run case ('With no run open it answers run_was_active: false'). It also describes conditional behavior for open COM/CAN/debug sessions and open incidents. It stops short of naming a competing alternative to use instead, but for a terminal stop operation the usage context is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
can_buses_listARead-only
List every can_buses entry in buses, keyed by bus_id, the name can_session_start, can_send and can_read take. Each shows session_active, listen_only with its listen_only_enforcement, fd, max_frame_data_bytes and max_buffer_frames; a bus with shares adds active_participants. Needs no session and opens no adapter. Use this instead of ip link or candump.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=false, so the safety profile is covered. The description adds genuinely useful behavioral context beyond that: no session is required and no adapter is opened, plus the exact shape of returned records (session_active, listen_only with enforcement, fd, buffer limits, and the conditional active_participants for shared buses). It does not contradict the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Dense and front-loaded: the primary action comes first, then field details, then the usage constraint and alternatives. The field enumeration makes one long run-on sentence, which slightly taxes readability, but every clause adds information an agent needs.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description compensates by enumerating the returned fields and their conditional presence, and it resolves the two most likely agent questions (does it need a session? what should I use otherwise?). Complete for a read-only zero-argument list tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline is 4. There is nothing for the description to clarify, and it correctly does not invent any parameter discussion.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (List) and resource (can_buses entries in buses) and immediately scopes it by naming the key (bus_id) and the siblings that consume it (can_session_start, can_send, can_read). An agent can distinguish this from ip link/candump and from the session tools without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly tells the agent when this is appropriate ('Needs no session and opens no adapter') and names concrete alternatives to prefer it over ('Use this instead of ip link or candump'). No inference required.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
can_readARead-only
Read the CAN frames your can_session_start session received into frames, counted by frames_read. Use it instead of candump; to wait for a reply, pass until_id rather than polling. Without a session: session_not_active. Returned frames are consumed; an empty read is still ok. Adapter faults: can_read_failed; after can_adapter_invalid_response, can_session_stop and start again.
| Name | Required | Description | Default |
|---|---|---|---|
| bus_id | Yes | A `can_buses` entry (can_buses_list), else `can_bus_not_configured`. | |
| until_id | No | Integer id (0 to 0x1FFFFFFF) to wait for, or a list of 1 to 8. Returns the frames read through the first match. Only the numeric id is compared, not the extended flag. | |
| max_frames | No | Most frames to return, 1 to the bus `max_buffer_frames` (1024 unless configured), else `invalid_argument`. Default `max_buffer_frames`. | |
| participant | No | Required on a bus with `shares`. It reads only frames its filter accepts, never its own sends. Each frame read spends its budget; `can_participant_frame_budget_exhausted` ends its run. | |
| wait_timeout_s | No | Seconds to wait for frames. Without until_id: default 0 (answer at once with what is queued), at most the bus `timeout_s` (default 10 s) and 60 s. With until_id: default 10 s, at most 60 s. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=false. The description adds meaningful behavioral context beyond that: frames are consumed on read, empty reads are harmless, a session is required (`session_not_active`), and after `can_adapter_invalid_response` the agent should stop and restart the session.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core read semantics and the candump/until_id guidance, then packs error codes at the end. Dense but every clause carries information; the error-code list is slightly abrupt but not wasteful.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries return-value burden and does explain that frames go into `frames`, are counted by `frames_read`, and are consumed. Combined with 100% schema coverage, an agent has enough to call it correctly and interpret results.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3, but the description adds purpose beyond the schema by explaining that until_id is the mechanism to wait for a reply instead of polling. It does not add per-parameter syntax detail beyond what the schema already covers.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (read) and resource (CAN frames received into `frames`) plus the session context (`can_session_start`). It is clearly distinguishable from sibling tools like can_send, can_session_stop, and can_buses_list.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says to use it instead of candump and to pass until_id rather than polling for a reply, which gives real when/how guidance. It lacks explicit when-not guidance or routing against sibling tools such as can_send, but the usage context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
can_sendADestructive
Send one CAN frame (CAN FD on an fd: true bus) on the can_session_start session, else session_not_active. Needs the bus allow_write, else permission_denied; a listen_only bus refuses with can_listen_only_mode. A repeat sends again. ok: the adapter accepted it, not that a node ACKed it. can_send_failed sets cleanup_required: it may have gone out. Use this instead of cansend.
| Name | Required | Description | Default |
|---|---|---|---|
| rtr | No | Default false: a data frame. True sends a remote frame; an `fd: true` bus refuses it with `can_fd_remote_frame_unsupported`. | |
| bus_id | Yes | A `can_buses` entry (can_buses_list), else `can_bus_not_configured`. The adapter gets the bus `timeout_s` (default 10 s) to take the frame; replies come from can_read. | |
| data_hex | No | Hex byte pairs, whitespace ignored; default empty. At most `max_frame_data_bytes`; classic over 8 bytes: `can_classic_frame_too_large`; FD only 0-8,12,16,20,24,32,48,64: `can_fd_frame_length_invalid`. | |
| extended | No | Default false: 11-bit standard id. True: 29-bit extended id. | |
| frame_id | Yes | Arbitration id: an integer, a decimal string or a 0x hex string. 0 to 0x7FF, or 0 to 0x1FFFFFFF when extended, else `invalid_argument`. The result echoes the sent `frame`. | |
| participant | No | Required with `shares`; needs its own `allow_write`. frame_id must pass its filter (`can_participant_filter_violation`). Sends spend its budget; `can_participant_frame_budget_exhausted` ends its run. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: 'A repeat sends again' reinforces non-idempotency, 'ok: the adapter accepted it, not that a node ACKed it' clarifies the ambiguous success semantics, and 'can_send_failed sets cleanup_required: it may have gone out' justifies the destructiveHint. Permission and listen_only refusals are also disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core action in the first clause, then layers preconditions, result semantics, and the sibling routing. Every clause is information-dense and none is filler despite the length.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the full burden of return-value explanation and does so via `ok`, `can_send_failed`/`cleanup_required`, and multiple error codes. An agent has everything needed to call it and interpret the result.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3, but the description adds environment-level meaning that ties parameters to failure modes (fd bus, allow_write, participant budget, frame echo). It does not add syntax beyond what the schema already provides, so it stops short of 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Send one CAN frame'), scopes it to the can_session_start session, and clarifies the FD variant. An agent can distinguish it from can_read and from the external cansend 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.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear preconditions (active session, bus allow_write) and explicitly routes away from the external tool with 'Use this instead of cansend'. It implies when-not via the error codes but does not name an in-server sibling alternative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
can_session_startADestructive
Open a session on a configured CAN bus for can_send and can_read, until can_session_stop or server exit. Returns session; a repeat call answers already_active: true. Fails can_bus_not_configured, device_busy or resource_busy (bus held), can_adapter_timeout (bridge timeout_s, default 10 s), and on a listen_only bus can_listen_only_unsupported or can_listen_only_unconfirmed.
| Name | Required | Description | Default |
|---|---|---|---|
| bus_id | Yes | A `can_buses` entry (can_buses_list). peak needs PCAN-Basic, socketcan an up interface, both via python-can (`agentic-hil[can]`, else `can_backend_not_available`); process runs a bridge `executable`. | |
| participant | No | Required on a bus with `shares`; any other name, or any name on a bus without `shares`, fails `can_participant_not_configured`. A broker owns the adapter; each participant gets its own filtered queue. | |
| clear_rx_queue | No | Default true: discard frames already queued, also on a repeat call, counted in `frames_drained`. Bounded: a queue that keeps filling fails `can_queue_clear_limit`. Ignored for a participant. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true, idempotentHint=false and readOnlyHint=false, so safety is covered; the description goes further by disclosing the repeat-call semantics ('already_active: true'), the exact failure codes, the bridge timeout default, and listen_only-specific errors. That is real behavioral context beyond the structured fields, though adapter/permission prerequisites are left to the schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the purpose, then return value, then failure modes — a logical order with no filler sentences. The error enumeration is long but each entry is distinct and actionable, so it earns its space.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description correctly supplies the return shape (`session`) and the alternate response, plus the failure taxonomy, which is what an agent needs to call and react. It omits prerequisites such as adapter availability and lease/permission state, which the schema only partially covers.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the per-parameter text is detailed (backend requirements, participant/shares rules, queue-drain counting), so the schema already carries the parameter burden. The description only adds indirect parameter context via `listen_only` and the bridge `timeout_s`, so baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb + resource: 'Open a session on a configured CAN bus', with the scope of the session stated (it exists 'for can_send and can_read, until can_session_stop or server exit'). It names the sibling tools that terminate or consume the session, so an agent can distinguish it from can_session_stop and the read/write tools without opening their schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It makes clear when the session is required (as the precondition for can_send/can_read) and how long it lasts, and enumerates the failure conditions that select retry/abort behavior. It never states a when-not or an alternative path for a bus that is already held, so it stops short of full routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
can_session_stopAIdempotent
Close the can_session_start session on bus_id when done with the bus; its lease is released. Its adapter closes unless other participants share the bus. A declared run still holds the bus. can_send and can_read then answer session_not_active. With no session open, was_active is false. If the close fails or a bridge is silent for 1 s, it returns can_adapter_close_failed and keeps the session.
| Name | Required | Description | Default |
|---|---|---|---|
| bus_id | Yes | A `can_buses` entry from can_buses_list, else `can_bus_not_configured`. Example: can_session_start(bus_id="bench"), can_read(bus_id="bench", max_frames=10), can_session_stop(bus_id="bench"). | |
| participant | No | Required on a bus with `shares`: only this participant detaches, the others stay. A name with no open session, or any name on a bus without `shares`, answers `was_active: false` and closes nothing. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds substantial behavior beyond the annotations: the lease is released, the adapter closes only if unshared, a declared run still holds the bus, no-session calls yield was_active=false, and failure returns can_adapter_close_failed while keeping the session. This goes well past readOnly/destructive/idempotent hints.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the primary action and stacks the observable consequences compactly. It is information-dense but every clause (lease, adapter, run, error code) carries distinct meaning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description supplies the relevant return signals (was_active, session_not_active, can_adapter_close_failed) and the silent-bridge timeout. For a mutation tool with annotations and fully documented params, nothing material is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the schema fully documents bus_id and participant, including the required-on-shared-bus case. The description's mention of shared participants is really session behavior rather than added parameter semantics, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Close the can_session_start session on bus_id') and ties itself directly to its sibling opener, so an agent can distinguish it from can_session_start without opening a schema. Scope (session lifetime, lease release) is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a clear when-to-use trigger ('when done with the bus') and describes the downstream state of can_send/can_read. It doesn't explicitly name alternative teardown paths or exclusions, but the lifecycle context is clear enough to route correctly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
classify_last_errorARead-only
Explain the last hardware failure: error_type names it, likely_causes says what to check, report_path and log_path hold the evidence. Unlike get_last_report, it keeps that failure through later successes. source_tool is the failed tool, or reset_target if a flash's recovery reset failed too. Some refusals, such as allow_flash off, record nothing. Needs no board; no failure yet: report_not_found.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and openWorldHint false, but the description adds substantial context beyond them: it persists a failure through later successes, specifies that some refusals record nothing, explains the source_tool value including the reset_target case, and states preconditions and the no-failure error state.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with purpose and packs multiple useful details into a compact paragraph. Some clauses are dense and semicolon-separated, but every sentence contributes relevant information without obvious waste.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the burden of explaining returns: it names the key output fields and their meanings, covers edge cases (refusals, no failure yet), and states that no board is needed. It is complete for a zero-parameter diagnostic tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero input parameters, so the baseline is 4. The description discusses output fields (error_type, likely_causes, report_path, log_path, source_tool), which is helpful but does not relate to input parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'Explain the last hardware failure.' It also names the sibling it differs from ('Unlike get_last_report') and clarifies the unique persist-through-successes behavior, so an agent can distinguish it from other report-related tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Contrasts with get_last_report and gives conditions ('Needs no board; no failure yet: report_not_found,' 'Some refusals ... record nothing'), which implies when to use it. However, it does not explicitly say 'use this tool when...' or list broader alternatives, keeping it at a strong but not perfect level.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
com_ports_listARead-only
List com_ports entries in ports by port_id, which com_session_start takes (not a device path), with session_active. Opens no port. available_com_ports holds host serial ports, or permission_denied unless a configured port may be read, serial_backend_not_available without pyserial, com_port_discovery_failed on an OS error; the call stays ok. Use this instead of picocom or /dev/tty*.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=false, and the description reinforces this with 'Opens no port.' Beyond that it discloses in-band outcome semantics (permission_denied, serial_backend_not_available, com_port_discovery_failed, and that the call itself stays ok) which is genuine behavioral context neither the annotations nor the empty schema provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose is front-loaded, but the back half is a cramped run-on enumerating three error strings with dense backticked identifiers, making it harder to scan than it needs to be. It is information-dense rather than padded, but the structure lets the important routing statement compete with the error catalogue.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema and no input parameters, the description carries the full burden and meets it: it explains what to do next (feed port_id to com_session_start), what the response fields mean, and how failure conditions are surfaced. An agent has everything needed to call and interpret this correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There are zero input parameters, so the baseline is 4. The description still adds value by explaining the meaning of the returned key (port_id that com_session_start consumes) and the peripheral fields session_active and available_com_ports, compensating for the absence of an output schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
It states a specific verb (List) and resource (com_ports entries in ports, keyed by port_id) and immediately names the consumer, com_session_start, with the clarifying note that it takes a port_id rather than a device path. That distinction from the generic /dev/tty* world makes it identifiable apart from siblings like com_session_start or available_com_ports without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives an explicit alternative to reject ('Use this instead of picocom or /dev/tty*') and clarifies the port_id-vs-device-path convention that routes agents to com_session_start next. It does not cover when to prefer this list over session-oriented siblings, but the routing guidance is clear and actionable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
com_readARead-only
Read what the board sent on a COM port session from com_session_start (else session_not_active), instead of screen, minicom or picocom. With until, one call waits for a pattern instead of polling. Each byte is returned once, as text and hex. If until is not seen in time, the answer is still ok, with until_matched false and the bytes so far.
| Name | Required | Description | Default |
|---|---|---|---|
| until | No | Text, or up to 8 texts, matched literally as bytes in the port's encoding, not as a regex. Returns the feedback through the first match; the rest stays buffered. | |
| port_id | Yes | The com_ports entry name (see com_ports_list), not a device path; an unknown name gives com_port_not_configured. Under config version 1, permission_denied unless allow_read is true. | |
| max_bytes | No | Most bytes to return; default the port's max_buffer_bytes (65536 unless configured). The rest stays buffered, see buffer_remaining_bytes. With until, a wait also ends once max_bytes are buffered. | |
| wait_timeout_s | No | Seconds to wait. Without until the default is 0 and a wait ends at the first bytes to arrive; with until the default is 10 s. Waits are capped at 60 s. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint and openWorldHint; the description adds the behavioral payload that matters: each byte is returned once as text and hex, and a timeout is not an error — the call still returns ok with until_matched=false plus the bytes so far. That timeout/partial-result contract is exactly the kind of non-obvious behavior an agent needs and cannot get from the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences, front-loaded with what the tool does and the prerequisite before the 'until' mode and the return contract. Every clause carries information — error name, alternative tools, waiting semantics, partial-result behavior — with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the burden of describing results and does so: bytes as text and hex, until_matched flag, and buffered remainder. Combined with the schema's documented error codes and buffer semantics, an agent has everything needed to call and interpret this tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents port_id, until, max_bytes, and wait_timeout_s with defaults and error codes. The description adds only a light gloss on 'until' (wait instead of poll) and return encoding, which does not exceed what the schema already states, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Read what the board sent on a COM port session') and ties the session to its producer (com_session_start), which separates it cleanly from siblings like com_write, can_read, and the debug_* family. It also names the conventional tools it replaces (screen, minicom, picocom), so the agent can place it immediately.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives the prerequisite explicitly ('session from com_session_start (else session_not_active)') and states the key usage decision: with 'until', one call waits for a pattern instead of polling. It also implicitly routes away from shell tools by naming the alternatives it replaces, leaving little to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
com_session_startADestructive
Open the serial port a com_ports entry names and hold it, with its machine-wide lock, until com_session_stop; a reader buffers what the board sends for com_read. DTR and RTS are driven as configured on open, which can reset a board. device_busy, resource_busy or com_port_busy: another server, process or program has the port. permission_denied: neither reading nor writing is allowed.
| Name | Required | Description | Default |
|---|---|---|---|
| port_id | Yes | Name of a com_ports entry (com_ports_list shows them), not a device path. Unknown names fail with com_port_not_configured; a device that will not open, with com_port_open_failed. | |
| clear_buffer | No | Default true: discard bytes received so far, also on a repeat start for the same port_id, which keeps a live session (already_active) and replaces a failed one. False keeps them for com_read. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond annotations by disclosing the machine-wide lock held for the session, that DTR/RTS are driven on open and can reset a board, and by decoding the failure modes (device_busy, resource_busy, com_port_busy, permission_denied). This is exactly the side-effect context an agent needs for a destructive session-start tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three dense sentences, front-loaded with the core action and lifetime, then side effects, then error meanings. The error-code list is somewhat telegraphic but each element earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a session-start tool with no output schema, it covers locking scope, buffering behavior, hardware side effects, and failure decoding. An agent has everything needed to call it and interpret outcomes.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so port_id and clear_buffer are fully documented in the schema, setting the baseline at 3. The description reinforces the lock/buffering semantics but adds no parameter syntax or format details beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (open) and resource (the serial port a com_ports entry names), plus the session lifetime boundary by naming com_session_stop. It clearly distinguishes itself from sibling stop/read/write tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explains the session lifecycle (hold until com_session_stop) and that a reader buffers for com_read, which implies when to use it. It does not state explicit exclusions or point to a competing alternative for opening a port, keeping it below a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
com_session_stopAIdempotent
Close the com_session_start session on port_id: stop its reader, close the port, release its lock. Unread bytes are dropped; the session log at log_path keeps them. Without a session it returns ok with was_active false. If the reader does not end within max(1 s, timeout_s + 0.5 s) of the close, it returns com_port_close_failed and keeps the session registered; call again to retry.
| Name | Required | Description | Default |
|---|---|---|---|
| port_id | Yes | Name of a com_ports entry in the project configuration (com_ports_list shows them), not a device path; an unknown name fails with com_port_not_configured. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: discloses that unread bytes are dropped but preserved in the session log, the no-session return shape (ok with was_active false), the timeout formula max(1 s, timeout_s + 0.5 s), and the com_port_close_failed error with the session kept registered. These are exactly the side effects an agent needs before calling a non-readOnly close.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the action and its effects, then layers failure and retry semantics. Every sentence carries information, though the timeout formula and error-code detail make it denser than strictly minimal.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description compensates by describing success and failure return shapes (ok/was_active false, com_port_close_failed) and the retry path. For a one-parameter tool, an agent has everything needed to call it correctly and interpret the outcome.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single parameter is fully documented in the schema (name of a com_ports entry, unknown name fails with com_port_not_configured). The description only references port_id incidentally, adding no format or semantic detail 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.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Close the com_session_start session on port_id') and enumerates the concrete effects (stop reader, close port, release lock). It is unambiguously distinguishable from its sibling com_session_start and from com_write/com_read.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Clearly implies when to call it (to tear down a session opened by com_session_start) and gives an explicit retry condition ('call again to retry') plus idempotent behavior when no session exists. It does not spell out alternatives, but the paired-tool framing makes the usage context clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
com_writeADestructive
Send bytes over the session com_session_start opened on port_id (else session_not_active); needs the port's allow_write (else permission_denied). At most max_write_bytes encoded bytes, 4096 by default. bytes_written counts the bytes sent; a short write returns serial_write_incomplete. Example: com_session_start port_id "uart0", com_write text "hello\r\n", com_read until "\n", com_session_stop.
| Name | Required | Description | Default |
|---|---|---|---|
| hex | No | Bytes as hexadecimal byte pairs, whitespace ignored, for example "0d 0a". Give hex or text, not both; hex suits binary payloads. | |
| text | No | Characters to send, encoded with the port's configured encoding (utf-8 by default) and sent as is: no line ending is added, so include \r\n yourself. Give text or hex, not both. | |
| port_id | Yes | Name of a com_ports entry in the project configuration (com_ports_list shows them), not a device path; an unknown name fails with com_port_not_configured. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations say readOnlyHint=false, destructiveHint=true, idempotentHint=false. The description adds rich context: max_write_bytes (4096 default), short-write error serial_write_incomplete, permission and session preconditions. This goes well beyond the structured annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Single dense sentence followed by an example sequence. Front-loaded with the core operation, no wasted words. Example illustrates the full lifecycle.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers mutation semantics (via annotations), error conditions, size limits, permissions, and an end-to-end example. For a write tool with no output schema, this is complete enough for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3. The description adds port_id semantics (name of a com_ports entry, not a device path) and mentions get list via com_ports_list, but doesn't elaborate on hex vs text encoding or line-ending behavior. Adds some value over the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Send bytes') and resource ('over the session com_session_start opened on port_id'), and names the dependency sibling com_session_start. Distinguishes from com_read and com_session_stop.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states preconditions: needs an open session from com_session_start (else session_not_active), and needs allow_write (else permission_denied). Names the sibling that opens the session, making the sequencing clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
debug_clear_breakpointsAIdempotent
Removes every breakpoint GDB holds in the debug_start_session session (else session_not_active), then checks none is left. It neither resumes nor halts the core. It answers cleared (the count) and backend_reconciled true; a second call clears 0. Unconfirmed: ok false, breakpoint_reconciliation_failed; a retry is safe. OpenOCD only, exactly one debugger configured; else not_supported.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations by stating it neither resumes nor halts the core, that it reconciles the backend, that a second call clears 0 (matching idempotentHint), and that a retry after breakpoint_reconciliation_failed is safe. Failure modes and their signals are spelled out explicitly.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the action and scope, then adds behavior, return values, and error branches in tight sentences. Dense and jargon-heavy but every clause carries information an agent needs; nothing is padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite no output schema, the description documents the return shape (cleared count, backend_reconciled, ok false) and the error identifiers. For a zero-parameter destructive-ish operation, this is complete enough for correct invocation and result interpretation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is no parameter semantics to document; baseline 4 applies. The description correctly implies the target session is implicit rather than passed as an argument.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (removes) and resource (every breakpoint GDB holds) scoped to a named session (debug_start_session). This clearly distinguishes it from debug_set_breakpoint and debug_list_breakpoints 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.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete usage context: OpenOCD only, exactly one debugger configured, otherwise not_supported; second call clears 0, so repeat invocation is understood as a no-op. It does not explicitly point to the sibling for individual breakpoint removal, but the operational conditions are well covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
debug_continueA
Resumes the core in the debug_start_session session until it stops. Needs allow_debug_execution, else permission_denied. Returns stop_reason, stop (frame): breakpoint_hit is ok; unexpected_breakpoint and target_exception are not. An exception or debugger_error stop is not resumed. No session: session_not_active. OpenOCD only, exactly one debugger configured; else not_supported.
| Name | Required | Description | Default |
|---|---|---|---|
| timeout_s | No | Seconds to wait for a stop. Default and ceiling: the debugger entry's timeout_s (60 unless set); under 0.1 counts as 0.1 first. Expiry: interrupt, its stop, up to 5 s each; timeout, halt_confirmed. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare the generic safety profile (readOnlyHint=false, destructiveHint=false, non-idempotent); the description adds substantial context beyond them: auth requirement (allow_debug_execution), the specific error codes for missing session and unsupported setups, and the semantics of stop_reason values (breakpoint_hit is ok; unexpected_breakpoint/target_exception are not; exception/debugger_error stops are not resumed). This is exactly the extra behavioral detail 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.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core action, then packs preconditions and return-value interpretation into terse clauses with no filler. Slightly telegraphic phrasing ('stop (frame)', 'its stop, up to 5 s each') borders on cryptic but remains readable and every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite having no output schema, the description explains the meaningful return values (stop_reason and the stop frame, with which outcomes are acceptable) and all failure modes. For a single-optional-parameter resume tool, an agent has everything needed to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single parameter timeout_s is fully documented in the schema (default/ceiling, minimum clamping, expiry behavior). The description adds no parameter-level detail, so the baseline of 3 applies since the schema already does the work.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (resumes) and resource (the core in the debug_start_session session) with explicit scope 'until it stops.' An agent can distinguish this from debug_halt, debug_start_session, and debug_get_stop_reason without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear preconditions for use: requires allow_debug_execution (else permission_denied), needs an active session (else session_not_active), and is OpenOCD-only with exactly one debugger (else not_supported). It never explicitly routes to a sibling like debug_halt as the alternative when you don't want to resume, so it stops short of full when/when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
debug_dump_symbol_ihexADestructive
Read an allowed symbol from target memory and write it as Intel HEX to output_path; returns address, size_bytes and output. Value inline: debug_symbol_value. OpenOCD needs debug_start_session (else session_not_active); pyOCD and STM32CubeProgrammer, the ELF last flashed via flash_firmware (else symbol_source_not_available). Over debug.max_dump_size_bytes: permission_denied.
| Name | Required | Description | Default |
|---|---|---|---|
| symbol | Yes | C identifier, optionally ::-qualified, e.g. boot_counter. Allowed if in debug.allowed_symbols or debug.allow_all_symbols is true (default false), else permission_denied. Not in ELF: symbol_not_found. | |
| output_path | Yes | Workspace path ending .hex or .ihex, no '..' segment, under artifacts.allowed_roots if validation.require_allowed_root (default true), else output_validation_failed. Folders created, a file replaced. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructiveHint=true and idempotentHint=false, and the description adds concrete behavioral detail beyond them: folders are created and an existing file is replaced, symbol access is gated by debug.allowed_symbols/allow_all_symbols, and dumps above debug.max_dump_size_bytes return permission_denied. It also names the failure modes (session_not_active, symbol_source_not_available, symbol_not_found).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core action and its output path lead the sentence, with prerequisites and error conditions following — well front-loaded and free of filler. The telegraphic semicolon fragments ('Value inline: debug_symbol_value') require some parsing but each clause carries real information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description correctly names the return values (address, size_bytes, output), and it covers the probe-specific preconditions, permission model, size limit, and the relevant error codes. Nothing an agent needs to invoke this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and both parameters are fully documented in the schema (pattern, allowed-roots rule, .hex/.ihex constraint, error codes). The description repeats the output_path role and some error codes but adds no syntax or format meaning 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.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource — read an allowed symbol from target memory and write it as Intel HEX to output_path — and distinguishes itself from the sibling debug_symbol_value by reserving that tool for inline values. An agent can separate this from debug_symbol_info and debug_symbol_value without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Routes the agent explicitly: 'Value inline: debug_symbol_value' names the alternative and the condition that selects it, and the description spells out per-probe prerequisites (OpenOCD needs debug_start_session; pyOCD/STM32CubeProgrammer need the ELF from flash_firmware). When-to-use, when-not, and prerequisites are all present.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
debugger_infoARead-only
Check the debugger backend is installed: runs only --version, at most 10 s; contacts no probe or board. Replaces openocd. Returns backend, executable, version, config_status. Next: debugger_probes_list (probe ids), probe_target (board). Failures: debugger_not_found (missing), timeout; not_supported unless exactly one debugger is configured; permission_denied without allow_probe (config version 1).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover read-only and closed-world, but the description adds substantial beyond-annotation behavior: it runs only --version, is bounded at 10 s, contacts no probe or board, and enumerates the failure modes (debugger_not_found, timeout, not_supported, permission_denied) with their preconditions. This is exactly the extra context annotations can't carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and bounded tightly by semicolons; nearly every clause earns its place (scope, cost, returns, next steps, failures). It is telegraphic and dense rather than wasteful, though the run-on semicolon style slightly taxes readability.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Even without an output schema, it names the returned fields (backend, executable, version, config_status), the runtime bound, the follow-up workflow, and every failure mode. Nothing an agent needs to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Zero parameters, so the schema has nothing to document and the baseline is 4. The description correctly implies no inputs are needed, and there is no parameter ambiguity to resolve.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Check the debugger backend is installed') and immediately scopes it ('runs only --version'). It also distinguishes itself from siblings by noting it 'Replaces openocd' and by naming the follow-up tools, so an agent can place it 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.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear usage context and explicit routing to alternatives ('Next: debugger_probes_list (probe ids), probe_target (board)'), plus the failure conditions that gate success. It stops short of stating when *not* to call it, so it lands at clear-context rather than 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.
debugger_probes_listARead-only
List the probe ids of the in-circuit debuggers or programmers on this host; connects to no board. Replaces st-info. Returns probes, each with a probe_id to set as the debugger entry's probe_id. pyOCD and STM32CubeProgrammer ask their CLI; OpenOCD reads the USB serial inventory, complete false (adapters it cannot read there: not_supported). Failure: probe_discovery_failed.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and openWorldHint=false, yet the description adds substantial context beyond them: it connects to no board, discloses per-backend discovery behavior (pyOCD/STM32CubeProgrammer query their CLI; OpenOCD reads the USB serial inventory), warns that 'complete' may be false with 'not_supported' adapters, and names the failure code 'probe_discovery_failed.' That is unusually rich disclosure for a read-only list tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose and scope in the first clause, then layered detail on backends and failure. Information-dense and mostly justified, though the semicolon-chained backend clause is terse to the point of being hard to parse on first read.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description must carry the return shape — and it does: a list of probes each with a probe_id, plus the 'complete' flag and 'not_supported' adapter caveat, and the failure code. Nothing an agent needs to call and interpret this tool is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so per the rubric the baseline is 4. The description does describe the returned probe_id field, but that is return-value information rather than parameter semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List the probe ids of the in-circuit debuggers or programmers on this host') and immediately scopes it against siblings like debugger_info or com_ports_list by noting it 'connects to no board.' Naming the legacy equivalent ('Replaces st-info') further disambiguates intent.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a clear use context: enumerate probe ids so one can be set as the debugger entry's probe_id, and clarifies the non-connecting nature versus tools that touch hardware. It does not name an explicit alternative or a when-not-to-use condition, so it falls short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
debug_get_session_statusARead-only
Reports if the debug_start_session session is open and its status: halted, running, error or cleanup_required. Records new stops, but never halts or resumes the core; debug_halt halts, debug_get_stop_reason reads the last stop. Abnormal stop: ok true, target_ok false, target_error_type. No session: ok, active false, status stopped. OpenOCD only, exactly one debugger configured; else not_supported.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=true and openWorldHint=false, so safety is partly covered, yet the description adds substantial context beyond them: it records new stops but never halts or resumes the core, and it defines return shapes for abnormal stops (ok true, target_ok false, target_error_type) and the no-session case. The 'records new stops' side effect is the one mild tension with readOnlyHint, but the description clarifies no core state is modified, so it reads as observation rather than contradiction.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the purpose and status set, and every clause is functional. The telegraphic style ('Abnormal stop: ok true, target_ok false, target_error_type') is information-dense but slightly compressed for easy parsing.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description must carry the return contract, and it does: it specifies the abnormal-stop fields and the no-session response. Combined with the environment constraints, an agent has everything needed to call and interpret it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline is 4. There is nothing for the description to disambiguate at the parameter level, and schema coverage is reported at 100%.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource (reports whether the debug_start_session session is open and its status) and enumerates the exact status values: halted, running, error, cleanup_required. It explicitly names the sibling tools it is not (debug_halt halts, debug_get_stop_reason reads the last stop), so an agent can route without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names alternatives and the conditions selecting them: use debug_halt to halt, debug_get_stop_reason to read the last stop. It also states the operating preconditions (OpenOCD only, exactly one debugger configured; otherwise not_supported), which tells the agent when this tool is even viable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
debug_get_stop_reasonARead-only
Why the core last stopped: stop_reason (breakpoint_hit, halted, exception), stop (frame). Records a newly arrived stop; never halts or resumes the core. Abnormal stop: ok true, target_ok false, target_error_type. None yet: stop_reason_not_available. Without debug_start_session: session_not_active. Session: debug_get_session_status. OpenOCD only, exactly one debugger configured; else not_supported.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond readOnlyHint/openWorldHint, it discloses that the call merely records a newly arrived stop and never halts or resumes the core, plus a full set of failure modes (target_error_type, stop_reason_not_available, session_not_active, not_supported) and the hard platform constraint.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded and every fragment delivers information, but the telegraphic, colon-heavy style ('stop (frame)', 'None yet: stop_reason_not_available') is dense rather than cleanly structured into sentences.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the burden of explaining return values falls on the description, and it does enumerate stop_reason values, the abnormal-stop shape, and all sentinel error responses. For a zero-parameter getter this is complete enough to call and interpret correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is no parameter semantics to document and the baseline of 4 applies. The description instead describes return shapes, which is helpful but not a parameter concern.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific resource and action - retrieving why the core last stopped - and even enumerates the possible stop_reason values (breakpoint_hit, halted, exception). It distinguishes itself from the session sibling by naming debug_get_session_status, so an agent can route correctly without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear prerequisites and error conditions: without debug_start_session it returns session_not_active, no stop yet yields stop_reason_not_available, and it only works on OpenOCD with exactly one debugger. It points to debug_get_session_status for session context but never explicitly frames this as a when-to-use-vs-sibling choice beyond that pointer.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
debug_haltA
Halts the core; the session stays open. It needs debug_start_session (else session_not_active) on OpenOCD with exactly one debugger configured, else not_supported. debug_continue resumes. Returns stop_reason halted or a stopped core's recorded stop. If an acknowledged interrupt's stop times out, ok and halt_confirmed are false, target_state unknown, bench quarantined; a confirmed halt can lift it.
| Name | Required | Description | Default |
|---|---|---|---|
| timeout_s | No | Seconds each for the interrupt and stop. The default and ceiling is 10, or the debugger's timeout_s if lower; under 0.1 counts as 0.1 first. Expiry answers timeout. A stopped core gets no interrupt. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare the mutation profile (readOnly=false, idempotent=false, destructive=false); the description goes far beyond by disclosing that the session survives, the returned stop_reason values, timeout semantics (ok/halt_confirmed false, target_state unknown, bench quarantined), and that a confirmed halt lifts quarantine. That is exactly the kind of side-effect detail 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.
Is the description appropriately sized, front-loaded, and free of redundancy?
Single dense paragraph that is front-loaded with the core action and prerequisite, then layers error and timeout behavior. Every sentence carries information, though the jargon-heavy clause stacking makes it slightly harder to parse than an ideal split into two or three sentences.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description compensates by describing return values (stop_reason halted or a stopped core's recorded stop) and the degraded-result case. Combined with prerequisites and failure codes, an agent has everything needed to invoke and interpret this tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and timeout_s is fully documented in the schema (default/ceiling, minimum, 'A stopped core gets no interrupt'). The description only alludes to timeout behavior in passing and adds no syntax or default detail 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.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a precise verb+resource+scope: 'Halts the core; the session stays open.' It also names the inverse operation (debug_continue resumes), so an agent can separate it from siblings like debug_stop_session without reading schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
States the prerequisite explicitly (requires debug_start_session, otherwise session_not_active) and the environment constraint (OpenOCD with exactly one debugger, otherwise not_supported), plus the complementary tool debug_continue. When-to-use and failure conditions are both given.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
debug_list_breakpointsARead-only
Lists the breakpoints debug_set_breakpoint added in the debug_start_session session, from the session's own record without asking GDB: breakpoints (id, backend_id, location). Never halts or resumes the core. No session: ok, active false, breakpoints empty. debug_clear_breakpoints removes them and checks GDB. OpenOCD only, exactly one debugger configured; else not_supported.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the readOnlyHint/openWorldHint annotations: it discloses that the operation never halts or resumes the core, that it reads from the session's own record rather than asking GDB, the exact edge-case return for no session ('ok, active false, breakpoints empty'), and environment constraints (OpenOCD only, single debugger, else not_supported). This is the kind of behavioral detail an agent needs before calling.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Information-dense and front-loaded: the core behavior leads, constraints and edge cases follow. The telegraphic, colon-heavy style ('breakpoints (id, backend_id, location)') is efficient but slightly clipped, keeping it from a 5.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, and the description compensates by naming the returned fields and the empty/no-session case. Combined with the environment preconditions and the non-interference guarantee, an agent has everything needed to call this correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline is 4. The description instead documents the return tuple (id, backend_id, location), which is useful but concerns output rather than inputs; there is nothing further to say about parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb+resource ('Lists the breakpoints') with precise scope: breakpoints added by debug_set_breakpoint within a debug_start_session session, read from the session's own record rather than GDB. It explicitly names sibling tools (debug_set_breakpoint, debug_start_session, debug_clear_breakpoints), so an agent can place it among the debug_* family 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.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Clear context: use this to inspect breakpoints without touching GDB, versus debug_clear_breakpoints which removes them and queries GDB. It also states the precondition 'OpenOCD only, exactly one debugger configured; else not_supported.' It does not name an alternative listing path or an explicit when-not-to-use beyond the not_supported case, so it stops short of a full 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
debug_set_breakpointA
Adds a breakpoint in the debug_start_session session (else session_not_active) without resuming the core. Each call adds one and returns its breakpoint id; debug_list_breakpoints lists them. A location without a grant answers permission_denied. An unconfirmed insert answers cleanup_required; call debug_clear_breakpoints. OpenOCD only, exactly one debugger configured; else not_supported.
| Name | Required | Description | Default |
|---|---|---|---|
| location | Yes | "main", {"symbol": "main"}, {"function": "main"}: C identifier, needs debug.allowed_symbols or debug.allow_all_symbols. {"file": "a.c", "line": 9}: line from 1, no '..', needs debug.allow_all_symbols. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark it non-readOnly, non-idempotent, non-destructive, but the description adds rich context beyond them: it does not resume the core, each call adds a distinct breakpoint, returns its breakpoint id, and enumerates failure modes (session_not_active, permission_denied without a grant, cleanup_required with a prescribed recovery call, not_supported).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core action and then layers error/constraint facts compactly; every sentence carries operational value. It is dense with slash-separated clauses, but there is no filler and nothing redundant given the number of distinct failure conditions it must convey.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter mutation tool with no output schema, the description covers the essentials an agent needs: session precondition, non-resuming behavior, returned breakpoint id, all named error outcomes with a recovery path, and environment limitations. Nothing needed to invoke or recover from it is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the schema itself exhaustively documents the accepted 'location' forms and their grant requirements, so the heavy lifting is already done. The description only adds that a location lacking a grant answers permission_denied, which is a useful but marginal supplement. Baseline 3 is appropriate when the schema fully documents the single parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Adds a breakpoint in the debug_start_session session') and clarifies a key behavioral nuance ('without resuming the core'). It also distinguishes itself from siblings by naming debug_list_breakpoints (lists them) and debug_clear_breakpoints (cleanup). An agent can route to it versus other debug_* tools 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.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit preconditions and routing: requires an active debug_start_session (else session_not_active), points to debug_list_breakpoints for listing and debug_clear_breakpoints when cleanup_required occurs, and states the environment constraint (OpenOCD only, exactly one debugger, else not_supported). When-to-use, when-it-fails, and alternatives are all present.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
debug_start_sessionADestructive
Opens a GDB session on an ELF for debug_continue and debug_halt. OpenOCD backend only; others answer not_supported. Needs GDB (debug.gdb_executable or PATH), the debugger entry's scripts and allow_raw_debugger_commands off. Returns the core halted: session (status, stop_reason), log_path. A second start: session_already_active. debug_get_session_status inspects it; debug_stop_session ends it.
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | attach (default): halts the core, no reset. reset_halt: resets, halts; needs allow_reset. load: resets, flashes the ELF, resets, halts; needs allow_reset and allow_flash, not allow_mass_erase. | attach |
| timeout_s | No | Seconds. Default and ceiling: the debugger entry's timeout_s (60 unless set); 0.1 at least. Bounds the debug server's start and each GDB step (10 s at most). Expiry: timeout. | |
| image_path | No | Path to a .elf file, relative to the workspace or absolute, inside the workspace and (by default) artifacts.allowed_roots. Give this or artifact_id, not both. | |
| artifact_id | No | Id of an ELF stored with artifact_upload. Give this or image_path, not both. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover safety/idempotency, yet the description adds substantial context beyond them: prerequisites (GDB executable, entry scripts, allow_raw_debugger_commands off), the halted-state outcome, the exact return fields (session status, stop_reason, log_path), and the session_already_active failure mode on a second start. This is exactly the extra behavioral disclosure the bar rewards.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Dense but front-loaded: purpose and consumer tools come first, then backend/prerequisite constraints, then return and error semantics. Five sentences all carry information, though the prerequisite clause is slightly compressed.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description steps in to describe the return shape (halted session with status/stop_reason, log_path) and the primary error case. Combined with the prerequisites and backend constraint, an agent has everything needed to call this mutation tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so mode, timeout_s, image_path and artifact_id are already fully documented in the schema, including enum meanings and the either/or constraint. The description adds no parameter-level detail beyond referencing allow_reset/allow_flash, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource (opens a GDB session on an ELF) and immediately scopes its purpose to debug_continue/debug_halt. It is clearly distinguishable from siblings debug_get_session_status and debug_stop_session, which it names explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a clear usage context (needed for debug_continue and debug_halt), a backend exclusion ('OpenOCD backend only; others answer not_supported'), and routes to the sibling that inspects it and the one that ends it. No explicit 'use X instead of Y' branch for alternative start paths, but the surrounding guidance is strong.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
debug_stop_sessionAIdempotent
Ends the debug_start_session session; debug_halt keeps it open. Confirms the core halted, disables resume on detach, ends GDB and the debug server, drops breakpoints, frees flash_firmware and reset_target. OpenOCD backend only; others answer not_supported. Success: safe_state_confirmed true. No session: ok, active false. Unproven: ok false, cleanup_required, hardware_state unknown, quarantined.
| Name | Required | Description | Default |
|---|---|---|---|
| timeout_s | No | Seconds per teardown step. Default and ceiling: 5, or the debugger entry's timeout_s if lower; 0.1 at least. A failed or expired step: halt_not_confirmed, detach_resume_not_confirmed, cleanup_failed. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Discloses rich behavior beyond the annotations: it confirms the core halted, disables resume on detach, ends GDB and the debug server, drops breakpoints, frees flash_firmware and reset_target, is OpenOCD-only (others return not_supported), and enumerates outcome states (safe_state_confirmed, no-session ok/active false, unproven cleanup_required/quarantined). This is exactly the side-effect and failure-mode detail the annotations do not carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the key distinction before the side-effect and outcome details, and every clause carries information. The telegraphic, fragment-heavy style is dense rather than wasteful, though slightly harder to parse than prose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the return-state burden and does so explicitly (success, no-session, and unproven/quarantined outcomes), and it covers backend scope, side effects, and the sole parameter's default/failure behavior. Nothing essential to correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single timeout_s parameter is already fully documented in the schema, including per-step failure codes. The description adds no parameter meaning, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ("Ends the debug_start_session session") and immediately names the sibling it is not (debug_halt keeps it open). An agent can distinguish this from debug_halt 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.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names the alternative (debug_halt) and the condition that distinguishes it (this ends the session, halt keeps it open), which gives clear selection context. It does not spell out a broader when-not, but the critical routing decision is covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
debug_symbol_infoARead-only
Find an allowed symbol's hex address, size_bytes and resolved_from in the ELF. Reads no target memory; for bytes use debug_symbol_value, for Intel HEX debug_dump_symbol_ihex. OpenOCD needs debug_start_session (else session_not_active). pyOCD and STM32CubeProgrammer use the ELF this server last flashed via flash_firmware (else symbol_source_not_available; symbol_source_changed if changed since).
| Name | Required | Description | Default |
|---|---|---|---|
| symbol | Yes | C identifier, optionally ::-qualified, e.g. boot_counter. Allowed if in debug.allowed_symbols or debug.allow_all_symbols is true (default false), else permission_denied. Not in ELF: symbol_not_found. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=false, yet the description adds meaningful behavior beyond them: it reads no target memory, requires an active session for OpenOCD, and derives symbols from the last-flashed ELF for pyOCD/STM32CubeProgrammer, with named error codes. That is substantial context the structured fields do not carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose, then a scoping clause, then the alternative-tool routing, then backend prerequisites — every sentence earns its place with zero filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, and the description names the returned fields (hex address, size_bytes, resolved_from) while covering both backend prerequisite paths and their failure codes. Nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the symbol parameter's schema description already documents the C-identifier pattern, allow-list gating, permission_denied, and symbol_not_found. The description only alludes to 'allowed symbol' and adds no format or gating detail beyond the schema, so the baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (find/resolve) and resource (an allowed symbol's hex address, size_bytes, resolved_from in the ELF), and explicitly distinguishes itself from debug_symbol_value (bytes) and debug_dump_symbol_ihex (Intel HEX). An agent can differentiate it from siblings without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit when-to-use routing to two named alternatives, plus prerequisites per backend: debug_start_session for OpenOCD (else session_not_active) and flash_firmware for pyOCD/STM32CubeProgrammer (else symbol_source_not_available / symbol_source_changed). This is exemplary when/when-not/alternative guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
debug_symbol_valueARead-only
Reads a symbol from target memory, like gdb print. debug_symbol_info gives its address, debug_dump_symbol_ihex a file. Returns hex, plus value_unsigned and value_signed at 1, 2, 4 or 8 bytes. OpenOCD needs debug_start_session (else session_not_active); pyOCD and STM32CubeProgrammer, the ELF flash_firmware last wrote (else symbol_source_not_available). Over max_dump_size_bytes: permission_denied.
| Name | Required | Description | Default |
|---|---|---|---|
| symbol | Yes | C identifier, optionally ::-qualified, e.g. boot_counter. Allowed if in debug.allowed_symbols or debug.allow_all_symbols is true (default false), else permission_denied. Not in ELF: symbol_not_found. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the read-only and closed-world profile, yet the description goes further by disclosing return shape (hex plus value_unsigned/value_signed at 1, 2, 4 or 8 bytes) and three specific error codes with their triggering conditions (session_not_active, symbol_source_not_available, permission_denied). This is unusually rich behavioral context beyond 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.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action, and each following clause carries real information (returns, prerequisites, error codes). The sentences are long and slightly run-on, but nothing is wasted filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description compensates fully by describing the return values, and it covers prerequisites and failure modes for a multi-backend debugger tool. Nothing an agent needs to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single parameter's constraints (C-identifier pattern, allowlist behavior, symbol_not_found) are fully documented in the schema itself. The description adds little parameter-level detail beyond the byte-width of returned values, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Reads a symbol from target memory, like gdb print') and explicitly distinguishes itself from the sibling tools debug_symbol_info (address) and debug_dump_symbol_ihex (file). An agent can select it without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names the two alternative tools and the condition that selects each, plus the exact preconditions per backend (debug_start_session for OpenOCD, ELF written by flash_firmware for pyOCD/STM32CubeProgrammer). It even pre-empts the failure modes so the agent knows what is required before calling.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
flash_firmwareADestructive
Write firmware to the board via the in-circuit debugger or programmer, not st-flash; every call writes it again. Needs allow_flash, else permission_denied. resource_busy: debug_stop_session first; device_busy: held elsewhere. The debugger entry's timeout_s (seconds, 60 unless set) caps each debugger command, else timeout. No bench_run_start needed; capture with reset_after_flash adds boot output.
| Name | Required | Description | Default |
|---|---|---|---|
| capture | No | Read a COM port across the flash: opened before it, ended by a match, max_bytes or the wait. Needs reset_after_flash. A read failing after a good flash is ok false, image written. | |
| image_path | No | A .elf, .hex or .bin inside the workspace and artifacts.allowed_roots (build if unset). A .bin needs flash_address on pyOCD and STM32CubeProgrammer. pyOCD does not verify (verify false). | |
| artifact_id | No | An artifact_id from artifact_upload, not with image_path; needs allow_upload, else permission_denied. Refused: artifact_not_found, artifact_validation_failed, artifact_too_large (max_upload_size_mb). | |
| reset_after_flash | No | Reset the board after flashing; needs allow_reset, else permission_denied. Default false: not reset. If a failed flash leaves an incident, recovery.auto_recover may try a reset into halt. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructive=true and idempotent=false, but the description goes well beyond them: it spells out the permission gate, the named error codes for busy/denied states, and the timeout mechanism (debugger entry timeout_s, 60s default, capping each debugger command). That is real operational context an agent cannot get from 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.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and the st-flash exclusion are front-loaded, and virtually every clause carries a fact (permission gate, busy routing, timeout, capture). It is telegraphic in places ('held elsewhere', 'resource_busy: debug_stop_session first'), which costs a little readability but not much content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive, multi-modal tool with no output schema, the description covers prerequisites, failure codes, and timeout behavior, and hints at the result shape via 'ok false, image written'. It stops short of describing the normal success payload or post-flash board state, but nothing critical to invoking it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the schema is itself verbose, so the baseline is 3. The description still adds cross-parameter semantics the schema does not: capture requires reset_after_flash, artifact_id is mutually exclusive with image_path and needs allow_upload, and the timeout_s that bounds the flash lives on the debugger entry rather than in the call.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening clause gives a specific verb+resource (write firmware to the board) and immediately scopes the mechanism (in-circuit debugger or programmer, not st-flash). It also flags the repeat-write nature, which is what distinguishes it from a one-shot upload tool. An agent can identify this 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.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states the precondition (needs allow_flash, else permission_denied), the routing for two distinct busy states (resource_busy -> debug_stop_session first; device_busy -> held elsewhere), and a when-not (no bench_run_start needed). It also names the condition that unlocks boot output (capture with reset_after_flash).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_last_reportARead-only
Return the newest stored hardware report, pass or fail, under report. For the last failure diagnosed, even after successes, use classify_last_error. Needs no board; reading changes nothing. After a failure it can be the recovery's reset_target or probe_target (report.tool). ok stays true for a failed report: judge report.ok, report.audit_ok, report.cleanup_required. None yet: report_not_found.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover readOnlyHint=true and openWorldHint=false, so 'reading changes nothing' and 'needs no board' are largely redundant. The genuinely additive behavioral detail is the non-obvious semantics that 'ok stays true for a failed report' and that one must judge report.ok/report.audit_ok/report.cleanup_required, plus the report_not_found case.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose is front-loaded well, but the middle sentences ('Needs no board; reading changes nothing') duplicate what the readOnlyHint/openWorldHint annotations already convey, adding waste for a zero-parameter tool. The return-value caveats are useful but packed densely without clear grouping.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the burden of explaining return values, and it does so reasonably: the report payload, the meaning of ok/audit_ok/cleanup_required, the report_not_found case, and the report.tool linkage to recovery targets. A slightly richer description of the payload's contents would make it complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
This tool takes zero parameters, so there is no parameter semantics to document and the baseline of 4 applies. Nothing in the description is needed to compensate for schema gaps.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb+resource ('Return the newest stored hardware report') and clarifies scope ('pass or fail, under report'), which lets an agent distinguish it from classify_last_error. It is clear but relies on the reader parsing several clauses to fully pin down the purpose.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives an explicit alternative and condition: 'For the last failure diagnosed, even after successes, use classify_last_error.' It also notes 'Needs no board' as a usage precondition. It stops short of a full when/when-not map across all siblings, so 4 rather than 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
hardware_lease_statusARead-only
Read who holds this bench, from any process (bench_held, held_devices), and any open incident: blocked, cleanup_reasons, auto_recoverable, quarantine_guidance, next_step. Only incident_stands: true needs hardware_recover; otherwise the next hardware call settles it or stands it down. standing_incidents are other projects' incidents, not yours to clear. Drives no device.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=false; the description reinforces this with 'Drives no device' and adds non-obvious context: which incident flags mean recovery is needed and that other projects' incidents are not actionable. It adds real behavioral meaning beyond the annotations and does not contradict them.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Content is dense with backtick-quoted field names but every clause carries information, and the core purpose ('Read who holds this bench') is front-loaded. It is compact for the amount of return-field semantics it conveys, though the jargon-heavy list is somewhat dense to parse.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description must explain the return shape — and it does, naming the key fields (bench_held, held_devices, blocked, cleanup_reasons, auto_recoverable, quarantine_guidance, next_step, incident_stands, standing_incidents). It is essentially complete for a zero-arg, read-only status call, with only minor gaps in overall response structure.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline of 4 applies; there is nothing for the description to compensate for. It spends its words on return-value meaning instead, which is appropriate for a no-arg status tool.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ('Read who holds this bench') and enumerates the returned fields, so the agent knows exactly what it retrieves. It also references the sibling hardware_recover, but does not differentiate against most other status-oriented siblings (bench_run_status, debug_get_session_status).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a conditional routing rule: only `incident_stands: true` requires hardware_recover, otherwise the next hardware call settles it. It also adds an exclusion — `standing_incidents` are other projects' incidents and not the caller's to clear. This is clear when-to-use and when-not guidance, though it stops short of an exhaustive alternative map.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
hardware_recoverAIdempotent
Clear the standing quarantine that blocks hardware calls. Call it when hardware_lease_status shows incident_stands, rather than deleting state files. It needs allow_recover and touches no hardware. A no-contact reason clears with no argument. Any other reason answers recovery_requires_physical_check: ask the operator, pass their answer verbatim as operator_statement, never invent one.
| Name | Required | Description | Default |
|---|---|---|---|
| operator_statement | No | The operator's own answer, asked in chat, passed verbatim; recorded in the ledger as theirs. Never invent one. No statement clears an audit_broken reason: only its operator_command does. | |
| accept_config_change | No | Default false. True only after the operator has reviewed both digests a config_changed refusal reports: accepts the configuration change since the incident; recorded in the ledger. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only give the safety profile (idempotent, non-destructive, closed-world); the description adds materially more: it contacts no hardware, needs allow_recover, clears with no argument for no-contact reasons, and warns against fabricating an operator_statement that gets recorded as the operator's own. That is exactly the ledger/auth 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.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the action, then reason-scoped behavior in a tight sequence of sentences. Dense but every clause carries a routing or safety rule; the internal jargon tokens (incident_stands, recovery_requires_physical_check) are only slightly opaque without the sibling tool's vocabulary.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the result burden and does state the two outcome signals (clears, or recovery_requires_physical_check). It stops short of describing what a successful clear returns or whether allow_recover affects the result, leaving a minor gap for a state-mutating recovery tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description goes further by stating the conditional requirement for operator_statement (only when the reason is not no-contact) and that it must be verbatim, which the schema alone frames only as 'the operator's own answer'.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb and resource: 'Clear the standing quarantine that blocks hardware calls.' It immediately distinguishes itself from the sibling hardware_lease_status (which reports the condition) and from destructive alternatives ('rather than deleting state files').
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit trigger condition ('when hardware_lease_status shows incident_stands'), an explicit anti-pattern ('rather than deleting state files'), and branching guidance for the two outcome classes (no-contact reason vs. any other reason requiring an operator statement). Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
probe_targetAIdempotent
Connect the in-circuit debugger or programmer to the board and confirm it answers (target_detected true), with no reset and no flash; reset_target resets. Replaces openocd. Refused with resource_busy while a debug session is open. Failures: adapter_not_found (no probe), target_not_detected (board silent), debugger_not_found (backend missing), timeout (one command over debugger.timeout_s).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover safety (readOnlyHint=false, destructiveHint=false, idempotentHint=true, openWorldHint=false), and the description adds real behavioral detail beyond them: the non-destructive scope, the resource_busy refusal condition, the timeout tied to debugger.timeout_s, and a full failure taxonomy (adapter_not_found, target_not_detected, debugger_not_found). The stated mutation is merely the connection itself, which is consistent with readOnlyHint=false.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the action and its constraints, followed by the alternative, refusal condition, and error list. Dense but each clause carries operational value; the trailing error enumeration is slightly list-like but earns its place for failure handling.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description supplies the success signal (target_detected true) and all documented failure modes, plus the refusal condition. Nothing an agent needs 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.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so per the baseline the schema cannot be improved upon; the description does not need to explain any input. It nonetheless documents the returned signal (target_detected true), which is a useful addition rather than a gap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a concrete verb+resource ('Connect the in-circuit debugger or programmer to the board and confirm it answers') and explicitly bounds the action ('no reset and no flash'), which cleanly separates it from siblings reset_target and flash_firmware.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly names what to use instead for resetting ('reset_target resets'), states a hard precondition ('Refused with resource_busy while a debug session is open'), and contrasts against openocd. Both when-to-use and when-not-to-use are covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
project_config_adopt_hardwareAIdempotent
Fill the configuration keys that still hold placeholders from the attached probe. Call it once a board is attached, so nobody retypes its serial. It may also rename a COM device to its stable name and correct a stale identity_source. It writes only when apply is true, never flashes or erases. A read that leaves the board state unknown may get it reset into halt by recovery (resource_quarantined).
| Name | Required | Description | Default |
|---|---|---|---|
| apply | No | Default false writes nothing. true writes carried via project_config_set (allow_config_description_write, else permission_denied), then call project_config_reload_description; none: applied false. | |
| probe_id | No | Serial of the attached probe to read, each read step taking up to 10 s; defaults to the configured probe_id. With neither, several attached probes answer ambiguous_hardware. Selects, never adds one. | |
| com_port_id | No | com_ports entry for the discovered device; default: the one naming it, else the only one, else a new dut_uart, created with every permission false. Several, none named: unavailable. | |
| debugger_id | No | Configured debuggers entry that receives the values; needed when there are several (else invalid_argument). Not configured: unknown_device. An entry naming another probe: hardware_mismatch. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: it clarifies that despite being a write (readOnlyHint=false), writes are gated by apply=true and it 'never flashes or erases,' and it warns that a read leaving board state unknown may trigger a reset into halt by recovery (resource_quarantined). That is exactly the kind of side-effect disclosure an agent needs for a mutation tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose, then layering trigger, extra behaviors, write gating, and a recovery warning. Every sentence carries information, though the paragraph is fairly dense for a config tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers purpose, when to call, write conditions, and a meaningful failure mode for a four-parameter mutation tool whose annotations and schema already document safety and parameters. No output schema exists, so return values need not be described.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so each of the four parameters is already fully documented in the schema; baseline is 3. The description adds conceptual framing (stable-name rename, identity_source correction) but no syntax or format detail beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource: it fills configuration keys that hold placeholders from an attached probe, and additionally renames a COM device and corrects a stale identity_source. The scope is concrete and distinguishable from project_config_set/create, though it does not name any sibling explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a clear triggering condition: 'Call it once a board is attached, so nobody retypes its serial.' This tells the agent when to reach for it, but there is no explicit exclusion or named alternative (e.g., project_config_set) for the case where a probe is not attached.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
project_config_createADestructive
Generate this workspace's configuration from attached hardware instead of writing one by hand: every permission true except allow_raw_debugger_commands and allow_mass_erase, which it writes false. Never ask for those two to be turned on. Regenerating is the operator's call, not a way to narrow or re-open.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare destructiveHint=true and idempotentHint=false, and the description adds genuinely useful behavioral detail: all permissions are written true except allow_raw_debugger_commands and allow_mass_erase which are set false, plus an operational rule never to ask for those. It does not spell out that it overwrites an existing config, which the destructive hint implies, leaving a small gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three compact sentences that front-load the core action and the permission defaults, with no filler. The final sentence is slightly oblique ('not a way to narrow or re-open') but still earns its place as guidance.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter, no-output-schema tool with annotations covering safety, the description supplies the write defaults and the operational constraint, which is what an agent actually needs. It could be more explicit about how it relates to project_config_adopt_hardware and project_config_describe, but nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, which is the baseline-4 case; there is nothing for the description to disambiguate and the schema is empty by design. No additional parameter meaning is needed.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Generate) plus resource (this workspace's configuration) plus source (from attached hardware), and explicitly contrasts it with writing a config by hand, which distinguishes it from project_config_set. An agent can identify what this does 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.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'instead of writing one by hand' implies the alternative (project_config_set) and the trigger for using it, and 'Regenerating is the operator's call, not a way to narrow or re-open' gives a when-not condition. It stops short of naming sibling tools explicitly, so it is clear but not fully routed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
project_config_describeARead-only
List the keys project_config_set may change: writable_keys with current_value and value_schema, locked_keys naming in unlocked_by the permission that opens each. Read it before project_config_set instead of guessing; it needs no permission. writes_blocked_by_open_run is true while this server holds a run or session. Bad YAML answers config_invalid, an unreadable file config_unreadable.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, but the description adds substantial context beyond them: no permission required, the meaning of writes_blocked_by_open_run while a run/session is held, and the error semantics (config_invalid for bad YAML, config_unreadable for an unreadable file). This is rich behavioral disclosure that structured fields do not carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded and every sentence carries information (fields, permission, blocking flag, error codes). It is slightly dense and runs several distinct clauses together, but there is little waste.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description correctly compensates by naming the returned fields and their sub-structure (current_value, value_schema, unlocked_by) plus error conditions. Nothing an agent needs to call and interpret it is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing for the description to clarify; baseline for a 0-param tool is 4. The description instead documents the response shape, which is a bonus rather than a parameter concern.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (List) and resource (the keys project_config_set may change), and enumerates the returned structure (writable_keys, locked_keys, unlocked_by). An agent can distinguish it from project_config_set (describe vs. set) 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.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says to read it before project_config_set instead of guessing, and notes it needs no permission. This names both the trigger condition and the alternative tool it precedes.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
project_config_reload_descriptionARead-only
Re-read target, debuggers, com_ports and can_buses from this workspace's configuration into the running server, never permissions or debug. Call it after project_config_set, project_config_adopt_hardware or a hand edit, rather than a restart. New devices get every permission false; changed grants need a restart (restart_required_for). description_changes lists what moved.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true and openWorldHint=false; the description adds substantial behavior the annotations cannot express: the scope of what is re-read, the fact that permissions/debug are untouched, the default-deny permission outcome for newly discovered devices, and the restart caveat for changed grants. It also names the description_changes field as the record of what moved.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and scope, and every sentence carries information. The middle sentence is dense, stacking two distinct rules plus a field name ('New devices get every permission false; changed grants need a restart (restart_required_for)'), which slightly taxes readability without wasting words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no parameters, no output schema and thin annotations, the description carries the full burden and does so: it covers scope, exclusions, trigger conditions, permission side effects, restart requirements and the feedback field. Nothing an agent needs before invoking it is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so per the baseline this is a 4. The description goes further by naming result fields (description_changes, restart_required_for), but those are outputs rather than parameters, so no parameter-level semantics are added.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a precise verb (re-read) plus the exact resources pulled in (target, debuggers, com_ports, can_buses) and the destination (the running server), and explicitly excludes permissions and debug. It is clearly distinguishable from siblings like project_config_set, project_config_describe and project_config_adopt_hardware.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use routing: call it after project_config_set, project_config_adopt_hardware, or a hand edit, instead of restarting. It also names the exception condition (changed grants need a restart) so the agent knows when this tool will not suffice.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
project_config_setADestructive
Write values you choose to named keys of the configuration file. Call it after project_config_describe lists the keys, rather than editing the configuration file. Device keys need allow_config_description_write, permission keys allow_config_permissions_write, else permission_denied. Permissions only narrow: closing allow_config_permissions_write freezes them all at once (permissions_frozen).
| Name | Required | Description | Default |
|---|---|---|---|
| changes | Yes | One or more {key, value} pairs, each key at most once, validated together: an unknown or repeated key or a value its value_schema refuses answers invalid_argument and nothing is written. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructiveHint=true and readOnlyHint=false, but the description goes well beyond them: per-key-type authorization (allow_config_description_write vs allow_config_permissions_write), the permission_denied failure mode, the one-way narrowing rule for permissions, and the permissions_frozen terminal state. These are behavioral consequences an agent cannot infer from the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the action and resource in the first clause, then prerequisites and authorization rules in priority order. The final sentence is dense and packs three distinct error states into one line, which slightly taxes readability but every clause carries load-bearing information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a mutation tool with no output schema, the description covers ordering, authorization per key class, failure codes, the narrowing-only semantics, and the freeze behavior. There is no output to explain, and nothing an agent needs to invoke this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the nested schema already documents key/value semantics, including permission_widening_denied and reload_required, so the baseline is 3. The description still adds meaning by tying key categories to the specific permissions they require and stating that permissions only ever narrow, which the schema does not express.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'Write values you choose to named keys of the configuration file.' It clearly distinguishes itself from the sibling project_config_describe (read) and project_config_reload_description (apply), so an agent can route without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit ordering guidance: 'Call it after project_config_describe lists the keys, rather than editing the configuration file.' This names both the prerequisite tool and the discouraged alternative path, which is exactly the when-to-use / when-not-to-use information an agent needs.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reset_targetA
Reset the board through the in-circuit debugger or programmer: the firmware restarts, flash is kept. Replaces st-util. Needs allow_reset (else permission_denied). Refused with resource_busy while a debug session is open: debug_stop_session first. To check the board without a reset use probe_target. Failures: reset_failed (reset not confirmed), timeout (one command over debugger.timeout_s).
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | Default 'run' (core executes); 'halt' stops the core at reset; 'init' also runs the reset-init script (clocks, wait states, watchdog), OpenOCD-only, else not_supported. | run |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only cover the safety profile (readOnlyHint=false, destructiveHint=false, idempotentHint=false). The description goes well beyond, disclosing the non-destructive reset semantics (flash kept), the allow_reset permission gate with the permission_denied result, the resource_busy conflict and its resolution, and the specific failure modes reset_failed and timeout with debugger.timeout_s.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and its non-destructive semantics, then preconditions, alternative, and failure codes in dense, zero-waste sentences. Every clause is actionable; nothing is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter reset tool with no output schema, the description covers outcome semantics, prerequisites, session conflict handling, alternatives, and error codes — everything an agent needs to invoke it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single 'mode' enum is fully documented in the schema (run/halt/init with the not_supported caveat), so the description adds no parameter meaning. Baseline 3 is appropriate when the schema does all the work.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (reset) and resource (the board) via the in-circuit debugger/programmer, and immediately clarifies the key semantic: firmware restarts but flash is kept. It explicitly distinguishes itself from the sibling probe_target ('to check the board without a reset').
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-not guidance: it is refused with resource_busy while a debug session is open, and directs the agent to call debug_stop_session first. It also names the alternative (probe_target) and the condition that selects it, plus the allow_reset prerequisite.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
server_upgradeAIdempotent
Upgrade this installation to the newest release with the uv, pipx or pip that installed it. Use it when the operator asks; it takes no arguments and needs allow_upgrade. Each manager run may take 600 s. running_version stays old until this server restarts. On Windows, ask the operator to run agentic-hil upgrade (upgrade_cli_only_on_host). On failure the operator runs any reinstall_command.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations by disclosing a 600 s runtime per manager, the allow_upgrade authorization requirement, and the key gotcha that running_version stays old until the server restarts. It leaves 'allow_upgrade' undefined and doesn't say existing files get replaced, so not a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core action and keeps only operative details (prerequisite, duration, restart caveat, platform path, failure path); no filler. The many clauses are compressed into long sentences, which costs a little readability.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a mutation tool with no output schema and no annotations covering timing/auth, the description supplies the runtime, the authorization requirement, the version-staleness caveat, and platform/failure fallbacks. It still leaves the meaning of allow_upgrade implicit, which is the only notable gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing for the schema to document; the description correctly notes 'it takes no arguments'. Baseline 4 applies for a parameterless tool.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'Upgrade this installation to the newest release', and even names the mechanism (the uv/pipx/pip that installed it). No sibling overlaps this action, but there is no explicit differentiation from siblings, so it sits just below a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit trigger ('when the operator asks') plus a prerequisite ('needs allow_upgrade') and a when-not/alternative path ('On Windows, ask the operator to run agentic-hil upgrade') and a failure fallback. The primary trigger is thin, but the environment-specific alternatives provide real routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
test_reactor_runADestructive
Run a test plan file (agentic-hil://reference/test-plan) on the board. For calls made one by one, use bench_run_start, whose open run refuses this with run_already_active. permission_denied and device_busy refuse at once, before any step. A failing step gets the recovery recovery.auto_recover allows, reported in recovery. With detach, poll test_reactor_status; test_reactor_stop ends it.
| Name | Required | Description | Default |
|---|---|---|---|
| detach | No | Default false: answers at the plan's end with `ok`, `steps`. True: once a worker holds the devices (30 s max), not at the plan's end: `run`, `state` or the verdict; else `run_worker_unresponsive`. | |
| test_config_path | No | Path inside workspace_root, relative to it; default `.agentic-hil/testconfig.yaml`. Missing: `test_config_not_found`; unreadable: `test_config_unreadable`; outside or malformed: `test_config_invalid`. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructive/non-idempotent, but the description adds substantial context: the error codes `permission_denied` and `device_busy` refuse before any step, a failing step gets the `recovery.auto_recover` behavior reported in `recovery`, and detach semantics are described. This is behavior well beyond the structured safety hints, with no contradiction.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and efficiently packed with routing, error, and recovery details in a few sentences. The telegraphic style is slightly cryptic in places, but every sentence carries information and nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description does much of the work: it covers failure modes, recovery reporting, detach polling, and stop semantics. It could say more about the returned verdict structure, but for a run tool it is close to complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both parameters (detach, test_config_path) are fully documented in the schema. The description's mention of detach polling does not add format or syntax detail beyond what the schema already provides, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Run) and resource (a test plan file on the board), and immediately distinguishes itself from the sibling bench_run_start, which is for calls made one by one. An agent can tell the two apart 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.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent: use bench_run_start for one-by-one calls, and this tool will refuse an open run with `run_already_active`. It also names test_reactor_status for polling and test_reactor_stop to end the run, giving clear when/when-not/alternative guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
test_reactor_statusARead-only
Follow a detached test_reactor_run by its handle; for a bench_run_start run, use bench_run_status. state goes starting, running, then finished or stopped, or worker_gone if its process died; stop_requested_at dates a test_reactor_stop. Once ended, run_ok is the verdict and canonical_report_path its own report; report_path is a mirror the next run overwrites. Fails run_state_invalid.
| Name | Required | Description | Default |
|---|---|---|---|
| run | No | A handle from test_reactor_run's `run`: `run-` and 16 hex digits, else `invalid_argument`; unknown: `run_not_found`. Leave it out to list this bench's runs: `runs`, `active_runs`. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark this as readOnlyHint true, so safety is covered. The description adds state machine transitions (starting, running, finished/stopped/worker_gone), stop_requested_at semantics, run_ok verdict, report_path mirroring behavior, and the run_state_invalid failure mode.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is dense but front-loads purpose and packs state, stop, verdict, and report details efficiently. It could be slightly clearer with structure but earns its space for a status tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema and annotations covering safety, the description carries the burden well by explaining state transitions, response fields, and failure modes. It is complete for a read-only status tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the parameter is already fully documented. The description adds some context about the handle format indirectly, but largely relies on the schema for parameter semantics, warranting a baseline 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Follow a detached test_reactor_run by its handle.' It explicitly distinguishes itself from bench_run_status for bench_run_start runs, which helps routing among siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It says to use bench_run_status for a bench_run_start run, and the schema notes that leaving out the run handle lists runs. However, it doesn't give broader when/why to poll status versus alternatives beyond that one distinction.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
test_reactor_stopAIdempotent
Ask a test plan run to stop by writing a request it reads between steps. It finishes the step it is in (a delay or device wait ends early), closes its devices and writes its report; one still starting ends before any step. Answers at once stop_requested: true, also on a repeat; an ended run answers stop_requested: false. Fails run_state_invalid, or run_worker_gone (its process died).
| Name | Required | Description | Default |
|---|---|---|---|
| run | Yes | A handle from test_reactor_run's `run`: `run-` and 16 hex digits, else `invalid_argument`; one this bench never issued fails `run_not_found`. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With annotations covering safety (readOnly=false, destructive=false, idempotent=true), the description still adds substantial context the annotations do not: the in-flight step completes, device waits end early, devices are closed, a report is written, repeats are answered the same way, and specific failure codes (run_state_invalid, run_worker_gone) are disclosed. The idempotent behavior is consistent with 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.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action, then sequences behavior, response, and errors compactly in three sentences. The middle sentence is dense and slightly run-on, but no sentence is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description correctly carries the return contract (`stop_requested: true`/`false`) and error outcomes, plus lifecycle effects, giving an agent everything needed for a one-parameter control call.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the `run` handle format, invalid_argument, and run_not_found semantics are already fully documented in the schema. The description adds nothing new about the parameter, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('ask a test plan run to stop') and explains the mechanism (writing a request read between steps), which clearly separates it from siblings like bench_run_stop and test_reactor_run. An agent can identify the 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.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains the effect on running and starting runs and what an ended run returns, which implicitly tells the agent when the call is meaningful, but it never names an alternative (e.g. bench_run_stop) or states explicit when-not-to-use conditions.
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.
26 tool updates
v0.22.1- Changed
artifact_upload3 fields changed- added
Input schema / properties / data_base64 / descriptionAdded value: +"The image as padded standard base64, whitespace ignored, else invalid_argument. Decoded, at most artifacts.max_upload_size_mb MiB (default 64), else artifact_too_large." - added
Input schema / properties / filename / descriptionAdded value: +"Bare name for data_base64, no path (like app.elf); its lowercased extension picks the format check and ends the artifact_id. A path: invalid_argument." - added
Input schema / properties / image_path / descriptionAdded value: +"Local file to store, inside the workspace and artifacts.allowed_roots (build if unset), with an allowed extension (.elf, .hex, .bin). Missing: artifact_not_found; invalid: artifact_validation_failed."
- Changed
bench_run_start6 fields changed- added
Input schema / properties / devices / descriptionAdded value: +"The devices the run holds, one selector each, all resolved before any is locked. Success returns them as `declared_devices`, with `run_label`." - added
Input schema / properties / devices / items / properties / id / descriptionAdded value: +"The config entry's name, else `unknown_device`. Required for uart and can; a debugger may leave it out, meaning the one this server is bound to or the only one configured, else `invalid_argument`." - added
Input schema / properties / devices / items / properties / kind / descriptionAdded value: +"debugger (a `debuggers` entry), uart (`com_ports`) or can (`can_buses`). The board under test is not a kind." - added
Input schema / properties / devices / items / properties / participant / descriptionAdded value: +"Only for can, else `invalid_argument`. Required on a bus with `shares` (`can_participant_required`); a name the bus lacks fails `can_participant_not_configured`." - added
Input schema / properties / label / descriptionAdded value: +"Optional, no default: free text returned as `run_label` and shown as the holder's label to anyone refused `device_busy`." - added
Input schema / properties / wait_s / descriptionAdded value: +"Seconds to wait for a device another holder has, 0 to 900. Default 0: a held device fails `device_busy` at once."
- Changed
can_read5 fields changed- added
Input schema / properties / bus_id / descriptionAdded value: +"A `can_buses` entry (can_buses_list), else `can_bus_not_configured`." - added
Input schema / properties / max_frames / descriptionAdded value: +"Most frames to return, 1 to the bus `max_buffer_frames` (1024 unless configured), else `invalid_argument`. Default `max_buffer_frames`." - changed
Input schema / properties / participant / descriptionPrevious value: -"On a bus with `shares`, name the participant whose session reads frames."New value: +"Required on a bus with `shares`. It reads only frames its filter accepts, never its own sends. Each frame read spends its budget; `can_participant_frame_budget_exhausted` ends its run." - changed
Input schema / properties / until_id / descriptionPrevious value: -"Arbitration id to wait for, or up to 8 ids. Returns the frames read through the first match. Only the numeric id is compared, not the extended flag. Waits 10 s by default."New value: +"Integer id (0 to 0x1FFFFFFF) to wait for, or a list of 1 to 8. Returns the frames read through the first match. Only the numeric id is compared, not the extended flag." - added
Input schema / properties / wait_timeout_s / descriptionAdded value: +"Seconds to wait for frames. Without until_id: default 0 (answer at once with what is queued), at most the bus `timeout_s` (default 10 s) and 60 s. With until_id: default 10 s, at most 60 s."
- Changed
can_send6 fields changed- added
Input schema / properties / bus_id / descriptionAdded value: +"A `can_buses` entry (can_buses_list), else `can_bus_not_configured`. The adapter gets the bus `timeout_s` (default 10 s) to take the frame; replies come from can_read." - added
Input schema / properties / data_hex / descriptionAdded value: +"Hex byte pairs, whitespace ignored; default empty. At most `max_frame_data_bytes`; classic over 8 bytes: `can_classic_frame_too_large`; FD only 0-8,12,16,20,24,32,48,64: `can_fd_frame_length_invalid`." - added
Input schema / properties / extended / descriptionAdded value: +"Default false: 11-bit standard id. True: 29-bit extended id." - added
Input schema / properties / frame_id / descriptionAdded value: +"Arbitration id: an integer, a decimal string or a 0x hex string. 0 to 0x7FF, or 0 to 0x1FFFFFFF when extended, else `invalid_argument`. The result echoes the sent `frame`." - changed
Input schema / properties / participant / descriptionPrevious value: -"On a bus with `shares`, name the participant whose session sends the frame."New value: +"Required with `shares`; needs its own `allow_write`. frame_id must pass its filter (`can_participant_filter_violation`). Sends spend its budget; `can_participant_frame_budget_exhausted` ends its run." - added
Input schema / properties / rtr / descriptionAdded value: +"Default false: a data frame. True sends a remote frame; an `fd: true` bus refuses it with `can_fd_remote_frame_unsupported`."
- Changed
can_session_start3 fields changed- added
Input schema / properties / bus_id / descriptionAdded value: +"A `can_buses` entry (can_buses_list). peak needs PCAN-Basic, socketcan an up interface, both via python-can (`agentic-hil[can]`, else `can_backend_not_available`); process runs a bridge `executable`." - added
Input schema / properties / clear_rx_queue / descriptionAdded value: +"Default true: discard frames already queued, also on a repeat call, counted in `frames_drained`. Bounded: a queue that keeps filling fails `can_queue_clear_limit`. Ignored for a participant." - changed
Input schema / properties / participant / descriptionPrevious value: -"On a bus with `shares`, name one configured participant. It owns this session's filtered view and permissions."New value: +"Required on a bus with `shares`; any other name, or any name on a bus without `shares`, fails `can_participant_not_configured`. A broker owns the adapter; each participant gets its own filtered queue."
- Changed
can_session_stop2 fields changed- added
Input schema / properties / bus_id / descriptionAdded value: +"A `can_buses` entry from can_buses_list, else `can_bus_not_configured`. Example: can_session_start(bus_id=\"bench\"), can_read(bus_id=\"bench\", max_frames=10), can_session_stop(bus_id=\"bench\")." - changed
Input schema / properties / participant / descriptionPrevious value: -"On a bus with `shares`, name the participant whose session to stop."New value: +"Required on a bus with `shares`: only this participant detaches, the others stay. A name with no open session, or any name on a bus without `shares`, answers `was_active: false` and closes nothing."
- Changed
com_read4 fields changed- added
Input schema / properties / max_bytes / descriptionAdded value: +"Most bytes to return; default the port's max_buffer_bytes (65536 unless configured). The rest stays buffered, see buffer_remaining_bytes. With until, a wait also ends once max_bytes are buffered." - added
Input schema / properties / port_id / descriptionAdded value: +"The com_ports entry name (see com_ports_list), not a device path; an unknown name gives com_port_not_configured. Under config version 1, permission_denied unless allow_read is true." - changed
Input schema / properties / until / descriptionPrevious value: -"Text to wait for, or up to 8 texts, matched as bytes in the port's encoding. Returns the feedback through the first match and leaves the rest buffered. Waits 10 s by default."New value: +"Text, or up to 8 texts, matched literally as bytes in the port's encoding, not as a regex. Returns the feedback through the first match; the rest stays buffered." - added
Input schema / properties / wait_timeout_s / descriptionAdded value: +"Seconds to wait. Without until the default is 0 and a wait ends at the first bytes to arrive; with until the default is 10 s. Waits are capped at 60 s."
- Changed
com_session_start2 fields changed- added
Input schema / properties / clear_buffer / descriptionAdded value: +"Default true: discard bytes received so far, also on a repeat start for the same port_id, which keeps a live session (already_active) and replaces a failed one. False keeps them for com_read." - added
Input schema / properties / port_id / descriptionAdded value: +"Name of a com_ports entry (com_ports_list shows them), not a device path. Unknown names fail with com_port_not_configured; a device that will not open, with com_port_open_failed."
- Changed
com_session_stop1 field changed- added
Input schema / properties / port_id / descriptionAdded value: +"Name of a com_ports entry in the project configuration (com_ports_list shows them), not a device path; an unknown name fails with com_port_not_configured."
- Changed
com_write3 fields changed- added
Input schema / properties / hex / descriptionAdded value: +"Bytes as hexadecimal byte pairs, whitespace ignored, for example \"0d 0a\". Give hex or text, not both; hex suits binary payloads." - added
Input schema / properties / port_id / descriptionAdded value: +"Name of a com_ports entry in the project configuration (com_ports_list shows them), not a device path; an unknown name fails with com_port_not_configured." - added
Input schema / properties / text / descriptionAdded value: +"Characters to send, encoded with the port's configured encoding (utf-8 by default) and sent as is: no line ending is added, so include \\r\\n yourself. Give text or hex, not both."
- Changed
debug_continue1 field changed- added
Input schema / properties / timeout_s / descriptionAdded value: +"Seconds to wait for a stop. Default and ceiling: the debugger entry's timeout_s (60 unless set); under 0.1 counts as 0.1 first. Expiry: interrupt, its stop, up to 5 s each; timeout, halt_confirmed."
- Changed
debug_dump_symbol_ihex2 fields changed- added
Input schema / properties / output_path / descriptionAdded value: +"Workspace path ending .hex or .ihex, no '..' segment, under artifacts.allowed_roots if validation.require_allowed_root (default true), else output_validation_failed. Folders created, a file replaced." - added
Input schema / properties / symbol / descriptionAdded value: +"C identifier, optionally ::-qualified, e.g. boot_counter. Allowed if in debug.allowed_symbols or debug.allow_all_symbols is true (default false), else permission_denied. Not in ELF: symbol_not_found."
- Changed
debug_halt1 field changed- added
Input schema / properties / timeout_s / descriptionAdded value: +"Seconds each for the interrupt and stop. The default and ceiling is 10, or the debugger's timeout_s if lower; under 0.1 counts as 0.1 first. Expiry answers timeout. A stopped core gets no interrupt."
- Changed
debug_set_breakpoint1 field changed- added
Input schema / properties / location / descriptionAdded value: +"\"main\", {\"symbol\": \"main\"}, {\"function\": \"main\"}: C identifier, needs debug.allowed_symbols or debug.allow_all_symbols. {\"file\": \"a.c\", \"line\": 9}: line from 1, no '..', needs debug.allow_all_symbols."
- Changed
debug_start_session4 fields changed- added
Input schema / properties / artifact_id / descriptionAdded value: +"Id of an ELF stored with artifact_upload. Give this or image_path, not both." - added
Input schema / properties / image_path / descriptionAdded value: +"Path to a .elf file, relative to the workspace or absolute, inside the workspace and (by default) artifacts.allowed_roots. Give this or artifact_id, not both." - added
Input schema / properties / mode / descriptionAdded value: +"attach (default): halts the core, no reset. reset_halt: resets, halts; needs allow_reset. load: resets, flashes the ELF, resets, halts; needs allow_reset and allow_flash, not allow_mass_erase." - added
Input schema / properties / timeout_s / descriptionAdded value: +"Seconds. Default and ceiling: the debugger entry's timeout_s (60 unless set); 0.1 at least. Bounds the debug server's start and each GDB step (10 s at most). Expiry: timeout."
- Changed
debug_stop_session1 field changed- added
Input schema / properties / timeout_s / descriptionAdded value: +"Seconds per teardown step. Default and ceiling: 5, or the debugger entry's timeout_s if lower; 0.1 at least. A failed or expired step: halt_not_confirmed, detach_resume_not_confirmed, cleanup_failed."
- Changed
debug_symbol_info1 field changed- added
Input schema / properties / symbol / descriptionAdded value: +"C identifier, optionally ::-qualified, e.g. boot_counter. Allowed if in debug.allowed_symbols or debug.allow_all_symbols is true (default false), else permission_denied. Not in ELF: symbol_not_found."
- Changed
debug_symbol_value1 field changed- added
Input schema / properties / symbol / descriptionAdded value: +"C identifier, optionally ::-qualified, e.g. boot_counter. Allowed if in debug.allowed_symbols or debug.allow_all_symbols is true (default false), else permission_denied. Not in ELF: symbol_not_found."
- Changed
flash_firmware6 fields changed- added
Input schema / properties / artifact_id / descriptionAdded value: +"An artifact_id from artifact_upload, not with image_path; needs allow_upload, else permission_denied. Refused: artifact_not_found, artifact_validation_failed, artifact_too_large (max_upload_size_mb)." - changed
Input schema / properties / capture / descriptionPrevious value: -"Read a COM port across the flash. The capture starts when the port is opened, before the flash, and ends at a match, max_bytes or the wait. Needs reset_after_flash."New value: +"Read a COM port across the flash: opened before it, ended by a match, max_bytes or the wait. Needs reset_after_flash. A read failing after a good flash is ok false, image written." - changed
Input schema / properties / capture / properties / max_bytes / descriptionPrevious value: -"Most bytes to return."New value: +"Most bytes to return; the port's max_buffer_bytes by default." - changed
Input schema / properties / capture / properties / until / descriptionPrevious value: -"Text to wait for, or up to 8 texts, as in com_read."New value: +"Text to wait for, or up to 8 texts of at most 256 characters each, as in com_read." - added
Input schema / properties / image_path / descriptionAdded value: +"A .elf, .hex or .bin inside the workspace and artifacts.allowed_roots (build if unset). A .bin needs flash_address on pyOCD and STM32CubeProgrammer. pyOCD does not verify (verify false)." - added
Input schema / properties / reset_after_flash / descriptionAdded value: +"Reset the board after flashing; needs allow_reset, else permission_denied. Default false: not reset. If a failed flash leaves an incident, recovery.auto_recover may try a reset into halt."
- Changed
hardware_recover2 fields changed- changed
Input schema / properties / accept_config_change / descriptionPrevious value: -"Only after the operator has reviewed the two digests a config_changed refusal reports: accepts that the configuration changed after the incident. Recorded in the ledger beside both digests."New value: +"Default false. True only after the operator has reviewed both digests a config_changed refusal reports: accepts the configuration change since the incident; recorded in the ledger." - added
Input schema / properties / operator_statement / descriptionAdded value: +"The operator's own answer, asked in chat, passed verbatim; recorded in the ledger as theirs. Never invent one. No statement clears an audit_broken reason: only its operator_command does."
- Changed
project_config_adopt_hardware4 fields changed- changed
Input schema / properties / apply / descriptionPrevious value: -"Write the plan. Without it the call reads hardware and the configuration and changes nothing."New value: +"Default false writes nothing. true writes carried via project_config_set (allow_config_description_write, else permission_denied), then call project_config_reload_description; none: applied false." - changed
Input schema / properties / com_port_id / descriptionPrevious value: -"Which com_ports entry receives the discovered device. Created with every permission false if it does not exist."New value: +"com_ports entry for the discovered device; default: the one naming it, else the only one, else a new dut_uart, created with every permission false. Several, none named: unavailable." - changed
Input schema / properties / debugger_id / descriptionPrevious value: -"Which configured debugger entry receives the values. Only needed when the configuration declares more than one."New value: +"Configured debuggers entry that receives the values; needed when there are several (else invalid_argument). Not configured: unknown_device. An entry naming another probe: hardware_mismatch." - changed
Input schema / properties / probe_id / descriptionPrevious value: -"Which attached probe this is about. Needed when more than one is attached; it selects among the attached probes and never adds one."New value: +"Serial of the attached probe to read, each read step taking up to 10 s; defaults to the configured probe_id. With neither, several attached probes answer ambiguous_hardware. Selects, never adds one."
- Changed
project_config_set3 fields changed- added
Input schema / properties / changes / descriptionAdded value: +"One or more {key, value} pairs, each key at most once, validated together: an unknown or repeated key or a value its value_schema refuses answers invalid_argument and nothing is written." - changed
Input schema / properties / changes / items / properties / key / descriptionPrevious value: -"Dotted configuration key, e.g. debuggers.dut.probe_id. project_config_describe lists the ones this caller may set."New value: +"Dotted key project_config_describe lists. Not in force until re-read (reload_required): project_config_reload_description takes target, debuggers, com_ports, can_buses keys, not debug or permissions." - changed
Input schema / properties / changes / items / properties / value / descriptionPrevious value: -"A single scalar. Objects and arrays are refused: a whole subtree is content the agent authored, which is what this tool exists not to accept."New value: +"A single scalar matching the key's value_schema; objects and arrays are refused. A permission key takes only false: true answers permission_widening_denied, since only the operator widens."
- Changed
reset_target1 field changed- changed
Input schema / properties / mode / descriptionPrevious value: -"How the target is left: 'run' executes, 'halt' stops the core, 'init' also runs the reset-init script (clock tree, wait states, watchdog) and is OpenOCD-only: other backends answer not_supported."New value: +"Default 'run' (core executes); 'halt' stops the core at reset; 'init' also runs the reset-init script (clocks, wait states, watchdog), OpenOCD-only, else not_supported."
- Changed
test_reactor_run2 fields changed- added
Input schema / properties / detach / descriptionAdded value: +"Default false: answers at the plan's end with `ok`, `steps`. True: once a worker holds the devices (30 s max), not at the plan's end: `run`, `state` or the verdict; else `run_worker_unresponsive`." - added
Input schema / properties / test_config_path / descriptionAdded value: +"Path inside workspace_root, relative to it; default `.agentic-hil/testconfig.yaml`. Missing: `test_config_not_found`; unreadable: `test_config_unreadable`; outside or malformed: `test_config_invalid`."
- Changed
test_reactor_status1 field changed- added
Input schema / properties / run / descriptionAdded value: +"A handle from test_reactor_run's `run`: `run-` and 16 hex digits, else `invalid_argument`; unknown: `run_not_found`. Leave it out to list this bench's runs: `runs`, `active_runs`."
- Changed
test_reactor_stop1 field changed- added
Input schema / properties / run / descriptionAdded value: +"A handle from test_reactor_run's `run`: `run-` and 16 hex digits, else `invalid_argument`; one this bench never issued fails `run_not_found`."
44 tool updates
v0.22.1-dev.0- First observed
artifact_upload - First observed
bench_run_start - First observed
bench_run_status - First observed
bench_run_stop - First observed
can_buses_list - First observed
can_read - First observed
can_send - First observed
can_session_start - First observed
can_session_stop - First observed
classify_last_error - First observed
com_ports_list - First observed
com_read - First observed
com_session_start - First observed
com_session_stop - First observed
com_write - First observed
debug_clear_breakpoints - First observed
debug_continue - First observed
debug_dump_symbol_ihex - First observed
debug_get_session_status - First observed
debug_get_stop_reason - First observed
debug_halt - First observed
debug_list_breakpoints - First observed
debug_set_breakpoint - First observed
debug_start_session - First observed
debug_stop_session - First observed
debug_symbol_info - First observed
debug_symbol_value - First observed
debugger_info - First observed
debugger_probes_list - First observed
flash_firmware - First observed
get_last_report - First observed
hardware_lease_status - First observed
hardware_recover - First observed
probe_target - First observed
project_config_adopt_hardware - First observed
project_config_create - First observed
project_config_describe - First observed
project_config_reload_description - First observed
project_config_set - First observed
reset_target - First observed
server_upgrade - First observed
test_reactor_run - First observed
test_reactor_status - First observed
test_reactor_stop
TDQS
Scored across 44 tools
The set has several superficially similar status/report tools (debug_get_session_status, debug_get_stop_reason, get_last_report, classify_last_error, bench_run_status, test_reactor_status, hardware_lease_status), but descriptions cross-reference each other explicitly and assign distinct purposes, so an agent can tell them apart. The run-vs-run distinction (bench_run_start vs test_reactor_run) is also carefully delineated. Only minor boundary friction remains among the many 'status' tools.
Names are uniformly snake_case with a clear verb_noun pattern and domain prefixes (debug_*, com_*, can_*, bench_run_*, project_config_*). A few names lack a domain prefix (get_last_report, classify_last_error, artifact_upload, server_upgrade) and project_config_reload_description is an awkward phrasing, but overall the convention is predictable.
44 tools is well beyond the 25+ heavy threshold. The domain is genuinely broad (debug, flash, serial, CAN, config, recovery, bench orchestration), but the surface is bloated with many fine-grained session/status/breakpoint tools that could be consolidated. This is a lot of surface for an agent to navigate reliably.
Coverage is remarkably thorough: each subsystem has full lifecycle tools (session start/stop, breakpoint set/list/clear, read/write), plus flash, reset, symbol inspection, bench-run orchestration, config describe/set/adopt/create, error classification, and quarantine recovery. No obvious dead ends for the stated hardware-in-the-loop purpose.
Maintenance
Related MCP Connectors
MCP server for building and testing AI agents with multi-model experimentation and insights.
MCP server for your apps' tools and custom tools, plus hosted AI agents and approval-gated workflows
MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.
Nifty's MCP server — exposes tasks, projects, messages, and files as tools for AI agents.
Related MCP Servers
- AlicenseAqualityCmaintenanceStateful MCP server for driving debug probes (J-Link) to flash, debug, and inspect embedded targets. Enables AI agents to perform flash, memory, breakpoint, and ELF/SVD-aware operations conversationally.4130 PyPI10MIT
- AlicenseNot gradedqualityAmaintenanceMCP server for simulating firmware on virtual microcontroller instances, allowing AI agents to upload, run, and read UART output from supported boards such as STM32 and Nordic.17MIT
- AlicenseCqualityAmaintenanceMCP server for AI-assisted MCU and embedded firmware debugging. It connects to real hardware via debug probes, inspects CPU/memory/peripherals, manages Keil builds, and provides structured evidence for fault diagnosis.1920 PyPI6MIT
- AlicenseNot gradedqualityCmaintenanceAn MCP server that lets AI coding agents drive the full STM32 development loop—code generation, build, flash, debug, serial monitoring, and fault diagnosis—end to end via CubeIDE, CubeMX, CubeProgrammer, OpenOCD, and GDB.1MIT