Agentic HIL

io.github.agentic-hilPublished by GitHub account agentic-hilv0.26.0Updated Nov 7, 2026

Develop firmware on the real board behind a debug probe: flash, reset, UART and CAN, policy-gated.

The publisher's own server: agentic.no

VerifiedSTDIODesktop onlyDeveloper ToolsSecurity & Monitoring

Overview

Agentic HIL's local MCP server; no sign-in required; STDIO; 48 tools.

No AI overview yet: these facts come from the registry entry and the server itself.

Installation

In SourceWeft

  1. Open Agentic HIL in the dashboard and add it to a workspace.
  2. Enable the server for the chats that should use its tools.

Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.

Other MCP clients

Follow the launch instructions in the repository.

README

Agentic HIL

[PyPI version] [CI] [License]

Connect your AI to reality.

Let your agent develop, test, and improve firmware autonomously. In the real world. Agentic HIL makes this possible as a hard gate: it enforces strict safety boundaries and verifies the results on real hardware.

https://github.com/user-attachments/assets/8d39ba93-beeb-484e-b9e9-d9ce79538523

Watch the agent set up a fresh firmware project, write the firmware, and make the board say Hello World after installation and one restart. The recording shows real hardware feedback through the gate. The agent saves a test plan and runs it with both a correct and a deliberately wrong expectation. You get the plan, a report, and evidence that the test can pass and fail. The run ends with the lease released, the safe state confirmed, and nothing quarantined.

Get started

Install Agentic HIL for your user with one command. No admin rights required.

Linux / macOS (any shell):

bash
curl -LsSf https://agentic-hil.github.io/install.sh | sh

Windows, in PowerShell:

powershell
irm https://agentic-hil.github.io/install.ps1 | iex

The installer registers the skill and MCP server for every supported agent CLI it finds on your PATH. It keeps the installation outside your repositories. Restart your agent once, then ask your first hardware question. Your agent sets up the project's bench through MCP.

If no claude, codex, or opencode CLI is found, the installer prints the next step. Install your agent CLI, then run agentic-hil agent-install --agent <claude-code|codex|opencode> to register it.

The installer asks the package manager where its user bin directory is and adds that directory to your shell startup files or Windows user Path when needed. Open a new shell to use the command. Pass --no-path (-NoPath in PowerShell) to manage that change yourself; the installer prints the line to add.

A fresh installation gets agentic-hil[can] from PyPI. Use --version <x.y.z> to pin a release. Rerunning the installer repairs an existing installation: editable checkouts reporting a .devN version are kept, and uv tools installed from a path, URL, or git reference are refreshed from that recorded source. To inspect and verify the installer before running it, follow the checksummed route in installation: download the script and its checksum from the same release, check the file, then run that file.

For a guided first run, try the STM32 starter. It has the firmware, test plans, and a planted defect ready for a three-step walkthrough on a Nucleo-F446RE.

Claude Code can also install the skill from the plugin marketplace: /plugin marketplace add agentic-hil/agentic-hil, then /plugin install agentic-hil@agentic-hil. The install command above still provides and registers the MCP server, with a verified absolute executable path outside your repository.

See installation for cmd.exe, registering one agent, using your own package manager, setting up an attached bench, optional components, and upgrades. The same installer command can repair an installation when agentic-hil upgrade fails. Troubleshooting covers startup problems.

In a clone of this repository, try a first check without a board:

bash
agentic-hil check-plan examples/nucleo-f446re_demo/testconfig.yaml

It answers All 1 test plan(s) load through the reactor's loader. and exits 0, without loading a bench configuration or touching hardware.

Let your agent close the loop

You set the goal. Your agent writes and builds the firmware. Agentic HIL puts it on the board, exercises the device, and checks its responses against the test criteria. When a test fails, the agent gets concrete results it can use to diagnose the problem, change the code, and try again.

Agentic HIL supplies the hardware execution and feedback that make this development loop possible. Much of the flashing, testing, and checking you would do at the bench becomes part of the agent's workflow. You review the code alongside a record of what ran, what passed, and what failed, and focus your attention on requirements, design decisions, and test coverage.

[Your agent builds firmware. Agentic HIL flashes it, exercises the board, and checks its responses within configured safety boundaries. The agent uses the results to diagnose, fix, and rebuild. You review the code and the hardware test results.]

Agentic Hardware-in-the-Loop (Agentic HIL) connects coding agents to the bench through MCP tools and CI suites through a pytest plugin. Setup is available for Claude Code, Codex, and OpenCode.

[Your coding agent sends hardware requests through MCP. Agentic HIL enforces the operator's configuration, drives debug probes, serial ports, and CAN buses, and returns structured results and reports. The configuration and audit record stay outside the agent's workspace.]

Each hardware action returns a structured result with its outcome, diagnostics, and report and log paths. Your agent gets feedback it can act on, and you can trace the result back to the recorded run.

Bring your bench into the loop

Agentic HIL connects to your probe through its backend: ST-Link through OpenOCD or the STM32CubeProgrammer CLI, and CMSIS-DAP probes through pyOCD. It also flashes and resets ESP32 targets through esptool and their USB-UART bridge, without opening a debug session. Hardware support follows the probe and backend.

Send commands and read responses over serial ports and CAN buses using PCAN, SocketCAN, or a custom bridge. Several runs can share a CAN bus through the broker.

Agentic HIL runs on Linux, macOS, and Windows with Python 3.10 or newer, with CI coverage across all three platforms. The Nucleo-F446RE example takes you through a complete run on the board used to demonstrate the loop. See installation for backend and platform details.

Put the firmware to the test

Write down what the device should do in a reviewable YAML test plan. The test reactor validates the plan before touching hardware, then flashes, resets, and exercises the device in the order you specify. Checks compare actual responses with exact values, patterns, or numeric ranges. A check passes when the device meets that expectation.

Plans name logical devices, and the bench configuration connects them to real hardware. Use the same plan at your desk and in CI. A failed step stops the run; sessions are cleaned up, and configured recovery actions and their outcomes are recorded with the test results. Write your first hardware test.

Set boundaries that hold

You decide which devices and actions your agent may use. Agentic HIL rejects undeclared devices before opening a driver. It enforces permissions, validates requests, applies timeouts, and records what happened. The CLI, MCP tools, pytest plugin, and test reactor all pass through the same gate.

The authoritative configuration lives outside the workspace, beyond the agent's own file tools. Review the permissions it grants. Use agentic-hil revoke <key> or agentic-hil grant <key> from your own shell to change individual grants. Over MCP, an agent can only narrow its authority. Flashing is refused while either allow_raw_debugger_commands or allow_mass_erase is enabled.

Device leases protect runs from interference across the machine, and a SHA-256 audit chain makes the hardware record tamper-evident. A failed run keeps its failed verdict while configured recovery works to restore the bench and records the outcome. A broken audit trail holds the bench until operator recovery, because another hardware test cannot rebuild missing evidence.

Read the safety model for the overview and the security design for the full reasoning.

Try it on a real board

Start with the Nucleo-F446RE demo. Connect the board, build the firmware, and set up Agentic HIL from the example's directory:

bash
cd examples/nucleo-f446re_democmake --preset Debug && cmake --build --preset Debug   # → build/Debug/nucleo-f446re_demo.elfagentic-hil setup --agent claude-code                  # or: codex / opencodeagentic-hil doctor

doctor checks the configuration against the attached bench and reports missing tools or hardware before you flash. If you connected the board after setup, agentic-hil adopt-hardware fills in the probe identity, backend executable, and COM device left unset. Use --dry-run to see the proposed changes first. On a host with OpenOCD and no STM32CubeProgrammer, the host's USB inventory can identify an attached ST-Link. Use --probe-id <serial> to select one when several probes are attached.

Run the example's hardware test plan:

bash
agentic-hil test-reactor --test-config testconfig.yaml

The plan flashes the firmware, opens the serial port, resets the board, and checks the boot output for Hello World. A missing or wrong boot banner fails the test and returns the device output for diagnosis. The run closes the sessions it opened, including when a step fails.

Your agent can drive the same steps through MCP tools. Run pytest tests/ from the example directory to put the boot check in a regression suite. The example guide covers all three paths, and hardware testing shows how to write plans for your own device.

Go deeper

Your next stepRead
Install, upgrade, or add CAN, pyOCD, or esptool supportdocs/installation.md
Define the bench and its permissionsdocs/configuration.md
Drive hardware through MCPdocs/mcp-tools.md
Connect a specific MCP hostdocs/mcp-hosts.md
Write hardware tests with YAML or pytestdocs/testing.md
Understand how safety boundaries and recovery workdocs/safety-model.md and docs/security-design.md
Find platform and response-time commitmentsdocs/support.md
Diagnose a failed runTROUBLESHOOTING.md
Set up your agent for this projectAI_AGENT_QUICKSTART.md and AGENTS.md

Use agentic-hil for the package installation, CLI command, repository URL, and MCP server name. Python imports, pytest plugin names, fixtures, and Python examples use agentic_hil.

Development

To work on Agentic HIL itself:

bash
python -m pip install -e '.[dev]'ruff check src tests evals toolspytestpython -m buildtwine check dist/*

Releases publish to PyPI through GitHub trusted publishing in .github/workflows/workflow.yml. See CONTRIBUTING.md to contribute.

Security

Policy bypasses are treated as vulnerabilities; see SECURITY.md.

Support

Linux, macOS, and Windows have equal support. Hardware support follows the probe and backend: ST-Link through OpenOCD or STM32CubeProgrammer, CMSIS-DAP through pyOCD, and ESP32 USB-UART bridges through esptool.

Issues receive a response within 24 hours on workdays, and security reports within seven days. See the support policy for the full scope and commitments.

Ask questions in Discussions Q&A, share a run in Show and tell, or submit your first run report, whether it passed or failed.

License

Apache-2.0. See LICENSE.

Source: README.md at commit f1aee36

Tools

48

debugger_info

Debugger backend availability

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).

Takes no parameters.

debugger_probes_list

List connected debug probes

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.

Takes no parameters.

probe_target

Probe the target

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).

Takes no parameters.

artifact_upload

Upload a firmware artifact

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.

Parametersfilenameimage_pathdata_base64

flash_firmware

Flash firmware

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.

Parameterscaptureimage_pathartifact_idreset_after_flash

reset_target

Reset the target

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).

Parametersmode

debug_start_session

Start a debug session

Opens a GDB session on an ELF for debug_continue and debug_halt. OpenOCD, pyOCD or ST-LINK_gdbserver; else not_supported. Needs GDB (debug.gdb_executable or PATH), the debugger's executable 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.

Parametersmodetimeout_simage_pathartifact_id

debug_stop_session

Stop the debug session

Ends the debug_start_session session; debug_halt keeps it open. Confirms core halted, disables resume on detach, ends GDB and debug server, drops breakpoints, frees flash_firmware and reset_target. OpenOCD, pyOCD or ST-LINK_gdbserver only; else not_supported. Success: safe_state_confirmed true. No session: ok, active false. Unproven: ok false, cleanup_required, hardware_state unknown, quarantined.

Parameterstimeout_s

debug_get_session_status

Debug session status

Reports if the debug_start_session session is open and its status: halted, running, error or cleanup_required. Records new stops; 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. GDB server only, exactly one debugger configured; else not_supported.

Takes no parameters.

debug_set_breakpoint

Set a breakpoint

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. GDB server only, exactly one debugger configured; else not_supported.

Parameterslocationrequired

debug_list_breakpoints

List breakpoints

Lists the breakpoints from the debug_start_session session's own record without asking GDB: breakpoints (id, backend_id, location), status, and cleanup_required, quarantined and hardware_state when cleanup is unconfirmed. Never halts or resumes the core. No session: ok, active false. debug_clear_breakpoints removes them. GDB server only, exactly one debugger configured; else not_supported.

Takes no parameters.

debug_clear_breakpoints

Clear all breakpoints

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. GDB server only, exactly one debugger configured; else not_supported.

Takes no parameters.

debug_continue

Continue the target

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. GDB server only, exactly one debugger configured; else not_supported.

Parameterstimeout_s

debug_halt

Halt the target

Halts the core; the session stays open. Needs debug_start_session (else session_not_active) on a GDB server, exactly one debugger configured, else not_supported. 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, quarantined; a confirmed halt lifts it unless the session is in error.

Parameterstimeout_s

debug_get_stop_reason

Last stop reason

Reads why the core last stopped: stop_reason (breakpoint_hit, halted, exception), stop (frame). Records a new 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. GDB server only, exactly one debugger configured; else not_supported.

Takes no parameters.

debug_symbol_info

Resolve a debug symbol

Find a 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 an open session, else the ELF flash_firmware last wrote (else symbol_source_not_available; symbol_source_changed if changed since).

Parameterssymbolrequired

debug_symbol_value

Read a symbol's value

Reads a symbol from target memory, like gdb print. Address: debug_symbol_info; file: debug_dump_symbol_ihex. Returns hex plus value_unsigned and value_signed at 1/2/4/8 bytes. OpenOCD needs debug_start_session (else session_not_active); pyOCD and STM32CubeProgrammer use an open session, else flash_firmware's last ELF (else symbol_source_not_available). Over max_dump_size_bytes: permission_denied.

Parameterssymbolrequired

debug_dump_symbol_ihex

Dump a symbol as Intel HEX

Read a 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 use an open session, else the ELF flash_firmware last wrote (else symbol_source_not_available). Over debug.max_dump_size_bytes: permission_denied.

Parameterssymbolrequiredoutput_pathrequired

get_last_report

Last structured report

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.

Takes no parameters.

classify_last_error

Classify the last failure

Explain the last hardware failure. Unlike get_last_report, the failure survives later successes. Returns error_type (its code), likely_causes (what to check), report_path and log_path (evidence). source_tool is the failed tool, or reset_target if a flash's recovery reset failed too. Flash refusals by allow_flash or allow_mass_erase record nothing. Needs no board; no failure yet: report_not_found.

Takes no parameters.

com_ports_list

List COM ports

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 ports, or `permission_denied` on version 1 unless a configured port may be read, `serial_backend_not_available` without pyserial, `com_port_discovery_failed` on OS errors; the call stays ok. Use this instead of picocom or /dev/tty*.

Takes no parameters.

com_session_start

Open a COM session

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.

Parametersport_idrequiredclear_buffer

com_session_stop

Close a COM session

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.

Parametersport_idrequired

com_write

Write to a COM port

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.

Parametershextextport_idrequired

com_read

Read from a COM port

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.

Parametersuntilport_idrequiredmax_byteswait_timeout_s

can_buses_list

List CAN buses

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.

Takes no parameters.

can_session_start

Open a CAN session

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`.

Parametersbus_idrequiredparticipantclear_rx_queue

can_session_stop

Close a CAN session

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.

Parametersbus_idrequiredparticipant

can_send

Send a CAN frame

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.

Parametersrtrbus_idrequireddata_hexextendedframe_idrequiredparticipant

can_read

Read CAN frames

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.

Parametersbus_idrequireduntil_idmax_framesparticipantwait_timeout_s

power_supply_status

Read a power supply

Read a configured bench power supply: per channel its set points, measured voltage and current, output state, protection and effective limits, each exact or null where the type cannot read it. Writes nothing and needs no grant. `missing_limits` and `writes_refused_reason` say why writes on a channel would be refused. A unit other than the configured one fails `power_supply_identity_mismatch`.

Parameterschannelsupply_idrequired

power_supply_set

Set a power supply channel

Set the voltage, the current or both on one supply channel. Needs `allow_set`. Refused before contact when the configuration sets no limit for the channel, or a value is above its effective limit (`power_supply_limit_exceeded`). Arms the supply's protection at the limits first, writes, and reads every value back exactly (`power_supply_readback_mismatch`). Does not switch the output.

Parameterschannelcurrent_asupply_idrequiredvoltage_v

power_supply_output

Switch a power supply output

Switch one supply channel's output on or off and read the state back. Needs `allow_output`. Before switching on, the stored set points are held to the effective limits and the protection is armed at them. A type that cannot read its output state is refused before contact (`not_supported`). Switching to the state already held changes nothing.

Parametersonrequiredchannelsupply_idrequired

power_supply_cycle

Power-cycle a board

Power-cycle the board on one supply channel: output off, wait `off_s`, output on, each state read back. Needs `allow_output`. The stored set points are held to the effective limits and the protection is armed at them first. A type that cannot read its output state is refused before contact (`not_supported`). Every call cycles the board again.

Parametersoff_srequiredchannelsupply_idrequired

bench_run_start

Declare a bench run

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.

Parameterslabelwait_sdevicesrequired

bench_run_stop

End the bench run

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`.

Takes no parameters.

bench_run_status

Bench run status

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.

Takes no parameters.

test_reactor_run

Run a test plan

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.

Parametersdetachtest_config_path

test_reactor_status

Test run status

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`.

Parametersrun

test_reactor_stop

Stop a test run

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).

Parametersrunrequired

hardware_recover

Clear a bench quarantine

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.

Parametersoperator_statementaccept_config_change

hardware_lease_status

Bench lease status

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.

Takes no parameters.

project_config_create

Generate the project configuration

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.

Takes no parameters.

project_config_describe

Describe the configuration

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.

Takes no parameters.

project_config_set

Change configuration keys

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).

Parameterschangesrequired

project_config_adopt_hardware

Adopt attached hardware

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).

Parametersapplyprobe_idcom_port_iddebugger_id

project_config_reload_description

Reload the bench description

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.

Takes no parameters.

server_upgrade

Upgrade this Agentic HIL installation

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.

Takes no parameters.

Version history

6
  1. v0.26.0LatestNov 3, 2026
  2. v0.25.0Oct 26, 2026
  3. v0.24.0Oct 6, 2026
  4. v0.23.0Oct 5, 2026
  5. v0.22.0Oct 1, 2026
  6. v0.21.5Sep 16, 2026

Score

90% of the applicable checks met

How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.

  • Reached in the last 30 days25 pts
  • Auth declared10 pts

    Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.

  • Tools listedRequired15 pts
  • DescriptionRequired15 pts
  • Logo10 pts
  • Documentation15 pts
  • License10 pts

Other Agentic integrations