Automating ViewAlyzer
Everything the ViewAlyzer app does with a target or a recording is available without the window: one process per job, JSON in and JSON out. Three doors open onto the same engine, and you pick by who is calling.
| DOOR | USE IT FROM | WHAT IT IS |
|---|---|---|
**viewalyzer-cli** | Shell scripts, CI jobs, any language with a process API | The headless CLI: capture, snapshot, poll, query, export, fingerprint, and the probe and license utilities. Every payload is one JSON object; captures also stream live events. This section documents it. |
Python SDK (pip install viewalyzer-sdk) | Python: pytest, notebooks, HIL benches | A thin, typed wrapper over the CLI: ViewAlyzer().record(...) returns a Recording with query methods and a read-only SQLite connection; stream() yields samples as they arrive. See the Python SDK section. |
| MCP server | AI assistants (Claude, Cursor, any MCP client) | va_record, va_timeline, va_sql and thirty other tools over the same CLI, so an assistant can capture and reason about a trace. See AI assistants in the BKPT Debug guide. |
The recorder on the firmware side has its own section: ViewAlyzer Recorder.
The contract
The CLI's verbs, flags, output shapes and the [headless] lines are an API: hosts (the SDK, BKPT Studio, the BKPT Debug extension, HIL harnesses) are written against them and they do not change. Additions happen, removals and renames do not. Every JSON payload carries "schema_version": 2 (2 since the hardware-trace queries and stream events were added; the bump was additive), and a host that checks the field can refuse a binary it does not know.
Two spellings reach the same commands: the verb form (viewalyzer-cli capture ...) and the flag form (viewalyzer --headless --config ...) that the desktop binary also accepts, so a script can drive either executable.
What a session looks like
$ viewalyzer-cli probes
{"schema_version":2,"probes":[{"type":"stlink","serial":"0033004B3033510735393935","description":"STLink V3","vid":"0483","pid":"374e"}],"warnings":[]}
$ viewalyzer-cli capture --config nucleo_g474_rambuf.vacf --elf firmware.elf --output run.vadb --duration 5
[headless] Capture: stlink-rambuf target STM32G474RE cb 0x2000005C scan 0x20000000+0x20000 reset=true
[headless] State: Recording
[headless] t=1.8 s 13981 events 107 KB 54.5 KB/s
[headless] Recording saved: D:/tmp/run.vadb (2848 KB)
[headless] Recording registered: id=328d49aa4eb6
{"schema_version":2,"recording_id":"328d49aa4eb6","path":"D:/tmp/run.vadb","summary":{"events":36614,"objects":7,"bytes":285717,"lost_events":0,"corrupt_bytes":0,"duration_us":5111530,"wall_s":5.02,"os":"BareMetal","cpu_hz":170000000.0,"transport":"stlink-rambuf"}}
$ viewalyzer-cli query timeline --recording run.vadb
{"schema_version":2,"query":"timeline","tier":"summary","total_slices":14679,"cpu_load_percent":0.27,
"task_legend":{"T1":{"name":"SysTick","kind":"isr"},"T2":{"name":"Work Block","kind":"fn"}},
"tasks":[{"code":"T1","cpu_percent":0.27,"slice_count":5111,"p50_slice_us":2.75,"p99_slice_us":2.77,"max_jitter_us":2.22, ...}]}
A capture prints progress to stdout, two stable lines a host parses (Recording saved, Recording registered), and one JSON envelope last. Queries print exactly one JSON object. Failures print an error envelope and exit 1.
Where to go
- Command reference: every verb, every connection key, output conventions, exit codes.
- Capture and stream: captures, the
.vacfconnection file, live stream events, snapshots, polling variables without instrumentation, hardware trace. - Queries: the pre-shaped JSON views of a recording, tiers and budgets, SQL, the hardware-trace queries.
- Regression tests in CI: fingerprints, compare, exit codes, a GitHub Actions job.
- The .vadb file: the SQLite schema, for when a query does not shape the data the way you need.
Free mode
Without a license the CLI still works: captures are capped at 5 s with a 5 s cooldown between them (cooldown_active with retry_after_s when you come back too soon), and a recording keeps its first 10 task and ISR lanes. viewalyzer-cli license get shows the caps in force; it never goes online. license activate <key> does.