What you’ll do
1
Create a personal access token
On API keys, create a personal access token and give it a name. Chiplab shows the token once. Copy it into a CI secret. The job sends it as a bearer token,
CHIPLAB_API_KEY.CHIPLAB_API_KEY stays in the CI environment. The config file holds the ${CHIPLAB_API_KEY} placeholder, so the token is expanded when the job connects.2
Start from the GitHub Actions template
The examples repository ships
.github/workflows/claude-chiplab-smoke.yml. The template runs Claude Code in the job, which then uses Chiplab. It runs when someone comments /smoke-test on a pull request. It builds examples/bare-metal/stm32f4-discovery and checks the captured UART. It needs two secrets: CHIPLAB_API_KEY (a Chiplab personal access token, starts with veecle_pat_) and ANTHROPIC_API_KEY (for Claude Code). Treat it as a template: the trigger, the agent, and the example path are yours to change. Changing the on: trigger by itself is not enough. The job checks that the comment contains /smoke-test, and it checks out the pull request number from that comment.3
Run on every pull request
To run on every Delete the job-level Check out the pull request head:The fork-guard step calls
pull_request, change the trigger, the job-level comment check, and the checkout together. A pull_request event has no comment body, and github.event.issue.number is empty.if. It looks for /smoke-test in the comment. Deleting it also drops the check that the commenter is OWNER, MEMBER, or COLLABORATOR.gh pr view with that same number. Point it at the pull request:4
Run on the virtual board
The job calls
ask for the current boards, tools, and gotchas, produces an ELF, uploads it, and runs it on the target board with the UART the firmware writes. It then waits and downloads uart.5
Fail when the expected output is missing
Fail the pipeline unless
uart contains what you expect. The public examples expect Hello world!. The check must look at the uart output, not the run status, because a crashing firmware still returns succeeded.6
Gate on each test
To get a pass or fail per test, swap that UART check for
run_test_suite. In your copy of the template, the prompt tells the agent to fail when the captured UART does not contain Hello world!. Change it so the agent uploads a suite, calls run_test_suite, and fails unless every test passed. result.summary has planned, passed, and failed. A null summary means the suite did not compile, or it threw before any test ran.Ask your agent
What you get back
The job downloadsuart and fails the pipeline unless that output contains what you expect. The public examples expect Hello world!.
Next
test
Get a pass or fail for each test.
run
Execute an ELF on a virtual board and read the UART.