---
name: bmcli
description: Control BUSMUST automotive bus hardware with BMCLI for ECU tool development, verification and validation, diagnostics, test automation, logging, replay, DBC signal work, ISO-TP, UDS DID/DTC access, security access, and firmware download. Use when an engineer asks to inspect or initialize a CAN/CAN FD bench, turn communication matrices or diagnostic/bootloader specifications into maintainable tests and evidence, build a dashboard or other application backed by BUSMUST hardware, capture or generate bus traffic, investigate ECU firmware behavior, or automate repeatable hardware workflows from direct commands, shell, Python, LabVIEW, or another harness.
---

# BMCLI

Use `bmcli` as the application-level interface to BUSMUST hardware. Prefer it
over writing new BMAPI bindings when the requested operation is already exposed
by the CLI.

## Establish the bench context

Every hardware, development, validation, or debugging workflow must begin with
`bmcli bench show --format=json`. Use the CLI output as the configuration
contract; do not read or merge `.bmcli/ecu.json` and `bench.local.json` directly.
Follow it with `bmcli bench validate --hardware --format=json` before hardware
access, or without `--hardware` when deliberately planning offline.

1. Read explicit values from the current request first: analyzer serial number,
   port, nominal/data bitrate, terminal resistor, CAN mode, UDS request/response
   IDs, addressing mode, padding, DBC paths, and ECU variant.
2. Run `bmcli bench show --format=json` to resolve `.bmcli/ecu.json` and
   `.bmcli/bench.local.json` through BMCLI. See
   [environment.md](references/environment.md) for ownership and schema.
3. Treat explicit current-request values as authoritative, followed by project
   ECU configuration, local bench configuration, then discovery.
4. Validate cached physical values before a hardware action. Run `bmcli doctor`
   and `bmcli bench validate --hardware --format=json`. Never assume enumeration
   index 0 still means the same analyzer.
5. Classify the state as `READY`, `DEGRADED`, `NEEDS_INPUT`,
   `DISCOVERY_REQUIRED`, or `OFFLINE`, then follow the state rules in
   [environment.md](references/environment.md).

Do not silently guess a port, bitrate, UDS ID, extended addressing byte, or DBC
variant. When discovery has more than one plausible answer, present the evidence
and ask the user to select.

## Discover only with permission

- Enumerating USB analyzers is read-only and may be done automatically.
- If exactly one suitable analyzer exists, propose its stable `SN/port` values;
  do not infer which port reaches the ECU without evidence.
- AutoSet requires exclusive hardware access. If the daemon is running, ask
  before stopping it. Start with passive detection, which needs existing CAN
  traffic but does not transmit:

  `bmcli channel autoset --channel=<SN/port> --mode=passive --timeout=10000 --format=json`

- If passive detection fails because the bus is silent, offer active detection.
  Explain that it transmits probe frames and may affect a live network; run it
  only after explicit authorization, preferably on an isolated bench:

  `bmcli channel autoset --channel=<SN/port> --mode=active --timeout=10000 --format=json`

- Treat passive success as RX traffic evidence and active success as repeated
  TX-ACK evidence at the detected timing, not proof of a specific ECU identity.
- Functional-address UDS discovery can transmit onto the bus and may wake
  multiple ECUs. Use it only after explicit authorization and only on an
  isolated bench. Dry-run first, then run `bmcli uds discover --channel=<SN/port>
  --allow-functional --format=json`. If TesterPresent gets no response, retry
  only with a documented harmless read request such as `--data="22 F1 90"`.
  Accept only IDs marked `correlated`, meaning they answered every repeated
  probe. If `selection_required=true`, list all response IDs and ask the user
  which ECU is the target. Never auto-select or persist one of multiple IDs.
- Persist confirmed values with `bmcli bench init`; do not hand-edit files when
  the CLI can represent the field. Keep `bench.local.json` out of version
  control and logical ECU requirements in `ecu.json`.

## Plan before acting

Read [command-discovery.md](references/command-discovery.md) before composing
commands. Query the installed binary's JSON help; never treat remembered syntax
or a copied example as the command contract.

Use these exact discovery forms before naming a callable command:

```text
bmcli help --format=json
bmcli help <category> --format=json
bmcli help <category> <action> --format=json
```

Do not substitute remembered spellings such as `stream`, `filter`, `stats`, or
`channel listen`. If runtime help does not list a capability, describe it as an
application-layer workflow or a future requirement, not as a BMCLI command.

In the current command model, read a DID with `bmcli uds request 22 F1 90
--channel=<SN/port> --reqid=<CAN-ID> --respid=<CAN-ID> --format=json` and inspect
DTCs with `bmcli uds dtc active --format=json` after resolving the endpoint from
bench context. There is no `uds read`, `read-did`, or `uds dtc read` convenience
command unless a future runtime help explicitly adds one.

For raw capture, the current command is `bmcli message recv
--channel=<SN/port> --duration=60 --format=jsonl`; for a file-backed recording,
query `bmcli help logging start --format=json` and use `logging start`. There is
no `message listen`, `channel listen`, or `stream` command. `duration` is in
seconds; `timeout`, `cycle`, `interval`, and `delay` are in milliseconds.

When planning offline and unable to execute runtime help, include only executable
BMCLI snippets that appear verbatim in this skill. Describe every other operation
as a capability whose exact command must be resolved from JSON help at execution
time. Never fill a syntax gap from general CAN/UDS tool experience.

Load exactly the task methodology needed:

- Read [development.md](references/development.md) when building a dashboard,
  prototype upper-computer application, service, Python/LabVIEW integration, or
  other software that uses BMCLI as its hardware backend.
- Read [verification-validation.md](references/verification-validation.md) when
  deriving requirements, test cases, automation, reports, or regression suites
  from a DBC, communication matrix, diagnostic survey, CDD, bootloader flow, or
  enterprise protocol specification.
- Read [debugging.md](references/debugging.md) for ECU fault isolation, DID/DTC
  inspection, captures, controlled traffic generation, firmware investigation,
  or one-off programming support.

For every operation:

1. State the target channel and bus configuration.
2. Use `--format=json` for bounded commands and `--format=jsonl` for streams.
3. Use stable `SN/port`, never a legacy enumeration index in generated assets.
4. Dry-run UDS request construction before first transmission when supported.
5. Capture the exact command, exit code, structured output, timestamps, and
   relevant artifacts in generated test evidence.
6. Separate transport failure, negative UDS response, assertion failure, and
   infrastructure failure in test results.
7. Clean up daemon, cyclic tasks, routes, logging, and replay that the workflow
   started. Do not stop pre-existing user-owned activity without approval.

## Use the least risky interface

- Use direct BMCLI commands for inspection and one-off operations.
- Use shell scripts for fixed, serial command sequences with simple pass/fail.
- Use Python `subprocess` for loops, matrices, retries, JSON/JSONL parsing,
  artifact generation, richer assertions, and long-term test maintenance.
- Use a DBC when the matching network/variant file is available. Without one,
  degrade to raw CAN IDs and payloads rather than blocking the whole workflow.
- When sending by DBC message name, preserve its extended-ID, CAN FD, and BRS
  attributes. Supply `--flags` only when the user or test intentionally overrides
  the DBC metadata.
- Keep OEM security algorithms external. `uds unlock` requires the approved
  DLL/shared library; never invent seed-key logic.

## Apply safety gates

Read/listen operations may proceed after context validation. Ask for explicit
confirmation before transmitting unspecified traffic, changing ECU state,
clearing DTCs, invoking routines, unlocking security, writing identifiers,
starting download, flashing firmware, or changing analyzer persistent state.

Before flashing, verify the exact ECU identity, firmware artifact and checksum,
address/segment map, programming preconditions, power stability, diagnostic
session, security level, rollback/recovery path, and user authorization. The
built-in `uds download` implements the transfer phase, not every OEM bootloader
precondition or post-programming validation step.

Analyzer firmware is a separate physical-device workflow. Use `bmcli device
update --device=<serial> --check --format=json` to inspect the CID changelist;
this is read-only. Run `bmcli device update --device=<serial>` only after the
user explicitly authorizes analyzer downtime and all channels on that device
are idle. The current implementation supports generation-3 HPM devices only,
downloads firmware before entering BMBOOT, and must report the expected version
after re-enumeration. Never turn an available-update check into an automatic
flash during routine diagnosis or release testing.
