Hardware-in-the-loop, declared

Run firmware tests on real hardware — from the CI you already have.

Tensile turns any bench into CI infrastructure. Blades host your self-hosted runners and the physical devices under test; one command runs build → flash → test hermetically, reproducibly, every time.

  • Reproducible
  • Deterministic
  • Durable
  • CI-native
the bench blade-01 · online
Your CI GitHub · GitLab · Jenkins tensile exec lock → build → flash → test → release blade-01 CI runner provides: nano DUT · nano label: nano
requires ⟷ providesmatched by label · no aliases
hermetic · bit-for-bit reproducible

What it is

Your CI orchestrates. Tensile runs the hardware.

There is no separate control plane to operate. Tensile plugs into the pipeline you run today. A single blade with a single device works with zero extra services — multi-blade racks are additive, not the default.

Hermetic runs

Build, flash, and test execute in a locked, logged environment — reproducible bit-for-bit across every machine.

Real devices

DUTs attach to a blade over USB, serial, or a debug probe. The blade owns the physical topology; your tests just read it.

YAML only

Customers author plain YAML. The full toolchain ships ready to run — nothing to install, nothing to wire up by hand.

The two-layer model

Hardware and firmware, joined by a contract.

Every run composes two layers matched by label, exactly. A machine discovers hardware facts; a human supplies the semantic label — that's the wiring knowledge, and the key a product matches on.

blade layer owns the physical hardware
# blades/blade-01.yaml
provides:
  - label: nano
    type: serial
    path: /dev/ttyUSB0
    usb_id: "2341:0043"
    chip: atmega328p
label: nano
matched exactly
product layer owns the toolchain & tests
# tensile.yaml
requires:
  - label: nano
phases:
  build: make firmware
  flash: avrdude -p $TENSILE_NANO_CHIP \
         -P $TENSILE_NANO_PATH
  test:  pytest tests/hil

nothing is hard-coded to a port — the product addresses its device by label, and the blade resolves it to real hardware at run time.

How a run works

Lock, then build → flash → test.

01

Build

Tensile resolves a pinned, reproducible environment and runs your build command hermetically. Same inputs, same artifact, every time.

02

Flash

The freshly built image is flashed to the labelled device on the locked blade — over the exact probe or serial port the contract resolved.

03

Test

Your HIL tests run against live hardware. Results, logs, and a run summary come back to the CI job that triggered them.

ci · tensile exec
# in your existing pipeline
$ tensile validate --file tensile.yaml
 config ⟷ blade contract ok

$ tensile exec --file tensile.yaml
lock    nano@blade-01
build   make firmware            ok
flash   $TENSILE_NANO_PATH       ok
test    pytest tests/hil    28 passed
release nano@blade-01
✓ run complete · 41.2s · reproducible

The portal

Every run, landing on real silicon.

Behind single sign-on, your team sees a live projection of CI runs alongside the health of every blade on the bench — contract version, DUT kind, devices attached, online or offline.

  • Workflow runs, projected per installation — you see only your org.
  • Live blade status, polled continuously over a private network.
  • Identity verified at the edge — every session cryptographically authenticated.
Open the portal →
tensile·portal [email protected] #4711
Workflow runs
firmware-ci
acme/sensor-fw · main · a1f9c02
success
2m ago
flash-regression
acme/sensor-fw · pr/218 · 7d3e1b8
in progress
just now
nightly-hil
acme/motor-ctl · main · 0b52aa1
failure
1h ago

Bring CI to the bench.

Wire a blade once, label its ports, and let every pull request prove itself on real silicon.

Evaluating Tensile for your lab? [email protected]