Skip to main content
Embedder writes Python hardware automation under .embedder/hardware/. Run these files with hardware_script_run so provider helpers, bridge routing, validation, capture publishing, and hardware leases all apply. Do not run a hardware script with plain Python or a shell command. Injected helpers will be missing, and the process will not participate in hardware coordination.

Choose a script location

Use a loose script for one probe:
Open a case as soon as the investigation needs a second script:
Case IDs use lowercase letters, digits, and hyphens. They start with a letter or digit and contain at most 64 characters. Reuse or edit an existing script. Do not create numbered copies such as capture2.py or capture_v2.py; stale variants make it unclear which probe produced the evidence.

Keep a durable case note

CASE.md stores one bug across context compaction and later sessions. Use this structure:
.embedder/hardware/cases/spi2-nack/CASE.md
Valid statuses are open, resolved, and abandoned. You may also add an updated timestamp. Do not delete a closed case; change its status and keep the evidence. Update hypothesis verdicts and findings when a probe settles them. Keep the short in-session checklist in the task list instead of duplicating it in the note.

Write against injected helpers

The script runner inspects the file and selects providers from the detected hardware and helper names it uses. Provider preludes inject helpers before your code runs. Examples include:
  • gdb.*, serial_send, serial_read, and serial_read_history
  • rtt_send, rtt_read, and rtt_read_history
  • la_*, scope_*, ppk2_*, and joulescope_*
  • ble_*
Use the generic la_* interface for Saleae, Digilent, and PicoScope logic capture. Direct Digilent vendor helper calls are rejected. Most provider libraries must not be imported directly. The J-Trace SDK is the exception: import jtrace in a script when you need its custom API.

Return structured results

Print a final one-line JSON object with success and summary. Add data and metadata when they help the next step.
.embedder/hardware/read_boot.py
Wrap asynchronous UART or RTT reads in asyncio.run. The runner parses the last valid result object from stdout. Provider publish helpers can add instrument captures to the Logic, Power, or Oscilloscope views. BLE helpers stream scan, GATT, and notification events to the Bluetooth view. The tool result lists each published instrument capture.

Run tools on the hardware host

Call run_tool inside a hardware script when you need a flasher or debugger executable:
It runs on the machine that owns the hardware, which is the paired bridge when one is active and the local host otherwise. A direct subprocess would run on the wrong machine in a bridge session. The result includes exit_code, output, and host.

Understand hardware leases

Every hardware_script_run requests exclusive access.

Foreground lease

A foreground script holds the hardware for the tool operation. Other sessions wait until the script and provider cleanup finish. The default timeout is 60 seconds. You can set a foreground timeout from 1 second through 10 minutes.

Background lease

Set run_in_background=true for a soak, endurance test, or long capture:
The tool returns immediately with a task ID and output path. The Python process keeps the board leased to that session. The foreground timeout value is ignored; a 24-hour backstop prevents a dead script from holding the board forever. Only one background hardware script may run in a session. A second script is refused until the first exits.

Cross-session protection

The arbiter queues other sessions behind an active owner. It also prevents a session from running an unchanged script whose latest successful run belongs to another session. Rewrite it for your task or use another filename. When a script programs firmware, Embedder records the load so other sessions know their previous hardware observations may be stale.

Wait for or stop a background run

Use the task ID returned by hardware_script_run:
wait_task listens for completion. If its wait times out, the script keeps running and the lease remains held. Stop a run with:
The runner sends SIGINT so Python cleanup and provider cleanup can release devices. Do not poll with sleep commands or start a duplicate run while you wait.

Review validation before running

File writes return hardware-script diagnostics. Fix them before you execute the script. Validation checks include:
  • Unknown or vendor-internal helper names
  • A provider action used without its connection helper
  • Unsafe or unsupported argument combinations
  • Direct imports that bypass provider setup
Runtime preparation can still ask you to install a Python package or managed instrument runtime. Approving one script does not approve every future script; permission is scoped by script name.

Find existing scripts

The debug-session toolbox lists loose scripts, open cases, closed cases, and each script’s leading docstring. .embedder is normally ignored by project search, so open a listed script by its exact path or list .embedder/hardware/ directly. Pass the path relative to .embedder/hardware as script_name:

Fix script problems

Run the file with hardware_script_run, not Python or shell. Confirm that hardware_status reports the provider and that the script uses its documented helper name.
Refresh hardware_status and follow the provider’s dependency or connection reason before rerunning.
Check active trace sessions and background tasks. Wait for the owner or stop your session’s task; do not bypass the lease.
Replace subprocess use with run_tool so the command runs on the hardware host.
Print a final JSON object containing a boolean success and string summary on one line.

Combined workflows

Coordinate several observations in one script.

Debug mode overview

Choose a provider for the next probe.
Last modified on August 24, 2026