Skip to content

ShortArrow/ivi-cli

Repository files navigation

English | 日本語

ivi-cli

ivi-cli is an integrated CLI for managing, diagnosing, and operating instruments addressed via VISA/IVI.

Status: v0.2.8 (pre-1.0.0). Phase 1–3 are landed: CLI core, HiSLIP / VXI-11 / SOCKET gateways, scenario-driven mock-VISA container (ghcr.io/shortarrow/ivi-cli-mock), Management HTTP / WebSocket API with PAT + TLS + audit, OpenTelemetry, and LAN discovery (LXI mDNS + VXI-11 broadcast, plus opt-in --port socket sweep). Breaking changes are still possible. See CHANGELOG.md.

Highlights

  • Stateful, VISA-native CLI
    • A current device, like a shell's working directory. ivicli visa add psu1 <resource> registers an alias once; ivicli visa use psu1 makes it the current device, so every later visa query / write / script needs no target at all — no VISA resource, not even the alias.
    • VISA-compatible. Parses standard TCPIP::, USB::, GPIB:: resource strings without proprietary syntax.
    • Automation-friendly. Stdout carries data (including --json); stderr carries logs. Exit codes are POSIX-conventional. Shell completion ships for bash / zsh / PowerShell.
  • Discover & inspect
    • Auto-discovery. ivicli visa scan walks the LAN via LXI mDNS / DNS-SD + VXI-11 portmapper broadcast and lists every responder; --add registers them all in one shot.
    • IVI Configuration Store introspection. ivicli driver list / ivicli logical list parse IviConfigurationStore.xml to enumerate installed IVI drivers and logical names — debugging "instrument talks but driver mismatched" without opening the Configuration Server GUI.
  • Backends & gateways
    • Multiple backends. Local NI-VISA, HiSLIP, VXI-11, raw TCP SOCKET, Fake (programmable + scenario playback), Replay (strict deterministic playback) — all behind a single IIviBackend port.
    • Gateway servers. Expose a local instrument over HiSLIP (TCPIP::host::hislip0::INSTR) or raw socket so remote PyVISA / NI-VISA clients can drive it without redeploying the test.
  • Test without hardware
    • Run a mock instrument. The Fake backend answers SCPI from a scenario — a scripted set of query → response rules — so ivicli (or your own VISA app) can talk to a stand-in with zero bench time.
    • Capture, then replay. Record a live session (IVICLI_CAPTURE=<path>) or a SCPI script run (mock scenario record --from-script foo.scpi) into a scenario, then re-run it deterministically with IVICLI_REPLAY=<scenario> — no hardware burned on regression checks.
    • Run & lint SCPI scripts. visa script foo.scpi runs a .scpi file — SCPI commands plus ivi-cli's inline assertions — against the current device; visa lint foo.scpi flags unknown SCPI roots (IEEE 488.2 + SCPI core) before you run it.
    • Audit-friendly. Set IVICLI_CAPTURE=<path> and every backend operation streams to an NDJSON log for post-hoc inspection — tail -f path | jq, or ivicli mock received <device> --match ':VOLT' to confirm out-of-band exactly which SCPI writes reached the mock when a test drives it through its own VISA stack.
  • Control plane (HTTP / WebSocket API)
    • JSON HTTP API. ivicli api start exposes a JSON HTTP API at http://127.0.0.1:8080/v1 (with /openapi/v1.json) so AI agents, dashboards, and CI scripts can list devices / fire SCPI queries / read status without speaking VISA.
    • Browser-friendly streaming. A WebSocket at ws://127.0.0.1:8080/v1/devices/{name}/visa carries {op:'query',scpi:'…'} frames and replies with {event:'response',…} — drop-in for any dashboard or AI agent runtime.
    • Lock down the API. ivicli api token create mints a PAT (shown once, only the hash is stored); the listener validates Authorization: Bearer … for HTTP and ivi-cli-pat.<token> for WebSocket so binding beyond loopback is safe.

Install

# .NET tool (requires the .NET 10 SDK or runtime)
dotnet tool install -g ivi-cli

# Self-contained single-file binary (no .NET install required)
# Download the artifact for your OS / arch from the GitHub Releases page.

Releases ship for win-x64, win-arm64, linux-x64, linux-arm64, osx-x64, and osx-arm64.

Quick start

# 1. Register an instrument
ivicli visa add psu1 TCPIP0::192.168.0.10::inst0::INSTR
ivicli visa use psu1

# 2. Talk to it
ivicli visa query "*IDN?"
ivicli visa write "OUTP ON"

# 3. Replay a recorded scenario instead of hitting hardware
IVICLI_REPLAY=psu1-smoke ivicli visa query "*IDN?"

# 4. Watch every registered instrument live (Ctrl+C to exit)
ivicli visa watch --interval 500

# 5. Expose the instrument over HiSLIP for remote clients
ivicli server add hislip-srv --type hislip --port 4880
ivicli server route add hislip-srv hislip0 psu1
ivicli server start hislip-srv

Configuration lives at the platform-specific XDG-style path:

OS Default path
Linux $XDG_CONFIG_HOME/ivi-cli/config.toml (default ~/.config/ivi-cli/config.toml)
macOS ~/.config/ivi-cli/config.toml
Windows %LOCALAPPDATA%\ivi-cli\config.toml

Override with the IVICLI_CONFIG environment variable.

Try it now — no hardware

A ready-made mock instrument in one command — no .NET install, no config:

docker run --rm -p 4880:4880 -p 5025:5025 \
    ghcr.io/shortarrow/ivi-cli-mock:latest

# In another terminal — using ivicli itself, or any SCPI client:
ivicli visa add mock TCPIP::localhost::hislip0::INSTR
ivicli visa query mock "*IDN?"
# → IVICLI-MOCK,gateway,1,0.1.0

The container serves the same scenario over a HiSLIP gateway on 4880 and a raw SOCKET gateway on 5025 (*IDN? / *RST / *OPC? / SYST:ERR? out of the box).

Mock a VISA instrument

Building an app that drives a VISA instrument and want to test it without the hardware on the bench? Stand up a mock that answers your app's SCPI:

  • Run a ready-made mock — the container above, or the bare CLI.
  • Author a scenario for your instrument — map its *IDN?, queries, and state transitions.
  • Point your app at itivicli or any VISA client; NI-VISA / Keysight-VISA apps register the mock in NI MAX.

Mock a VISA instrument is the step-by-step guide; the PSU sample is a complete worked example (drop-in scenario + setup scripts).

Subcommand map

Group Verbs Purpose
visa add remove list use current scan query write read status script monitor watch lint Manage and talk to instruments
mock scenario list create remove show activate deactivate record import + scene add / scene remove Author and capture mock-device scenarios
mock received <device> Confirm which SCPI writes a device received, read back from an IVICLI_CAPTURE traffic log
server add remove list route add / route remove / route list start stop status log Gateway-server lifecycle
api start stop token create token list token revoke Management HTTP JSON API + WebSocket subprotocol + PAT auth
top-level doctor completion <shell> Environment health + shell autocomplete

Verbosity & format flags

Flag Effect
(none) Information+
-v, --verbose Debug+
-vv Trace+
-q, --quiet Suppress console below Warning (file sink unaffected)
--log-file <path> Override the rolling log file destination
--log-format human|json Console format (default human)

Shell completion

# bash: source from .bashrc
eval "$(ivicli completion bash)"

# zsh: source from .zshrc
eval "$(ivicli completion zsh)"

# PowerShell: source from your profile
ivicli completion powershell | Out-String | Invoke-Expression

Once installed, <Tab> expands subcommands, options, and runtime identifiers (device aliases, server names, scenario names).

How it connects

ivicli sits between a caller and an instrument. The four ways you use it:

1 · Drive real hardware

flowchart LR
    u["you / CI"] -->|"VISA — NI-VISA / HiSLIP / VXI-11 / SOCKET"| c["ivicli"] --> i["instrument (LAN, USB/GPIB)"]
Loading

2 · Test without hardware

flowchart LR
    u["you / CI"] --> c["ivicli"] -->|"Fake / Replay / mock container"| n["no hardware"]
Loading

3 · Expose a local instrument

flowchart LR
    r["remote PyVISA / NI-VISA client"] -->|"HiSLIP / SOCKET gateway"| c["ivicli"] --> i["local instrument"]
Loading

4 · Control plane

flowchart LR
    a["AI agent / dashboard / CI"] -->|"HTTP / WebSocket API"| c["ivicli"] --> i["instrument"]
Loading

The internal layering — Clean Architecture with a one-way dependency direction, enforced by an architecture-test suite — is a contributor concern, intentionally omitted from this user-facing README.

Support & quality

What every release verifies. A vX.Y.Z release is published only after, at the tagged commit:

  • each of the six binaries (win / linux / osx × x64 / arm64) is built, passes the unit + architecture test suite, and is smoke-run on a native runner of the same OS and architecture;
  • the mock container passes a HEALTHCHECK + SCPI round-trip smoke natively on both amd64 and arm64 before the multi-arch push;
  • the tag, project version, and CHANGELOG entry agree.

The integration suite (real sockets, PyVISA interop) runs nightly on three OSes; it is not a release gate.

Compatibility promise (pre-1.0). While the version is 0.x, two surfaces are stable contracts: the --json output schemas and the config.toml / scenario TOML schema. Breaking either requires a minor version bump (0.Y → 0.Y+1) with an explicit CHANGELOG entry — patch releases never break them. Everything else (human-readable output, log text, Management API shape, container internals) may change in any release until 1.0.

Verified instruments. Entries are point-in-time: verified at the recorded version, not re-verified on later releases. Instruments not listed fall under best-effort standards conformance (HiSLIP, VXI-11, raw SOCKET, IEEE 488.2 / SCPI) — incompatibility with a spec-conforming instrument is a bug; attach an IVICLI_CAPTURE traffic log to the report.

Instrument Verified at Result
Kikusui PWR801L v0.2.6 SOCKET (5025) and HiSLIP (4880) round-trips work; LAN discovery finds it. VXI-11 portmapper resolution works, but queries are blocked by a device-side Core-port issue.

Support. GitHub issues, best-effort, no SLA. Only the latest release is supported — fixes ship as new releases, no backports. For vulnerabilities see SECURITY.md.

Documentation

Building from source

dotnet tool restore
dotnet restore --locked-mode
dotnet build
dotnet test --filter "Category!=Integration"

A local CSharpier formatter check on commit installs on first contributor run via dotnet husky install. Build and tests run in CI, not on push.

License

Licensed under either of

at your option.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

About

VISA/IVI based instrument integrated CLI

Topics

Resources

Contributing

Security policy

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages