litmus-cli - Command-Line Interface for Litmus

You are reading this at https://api.litmus.io/cli.md (HTML version at https://api.litmus.io/cli).

litmus-cli is the standalone command-line client for Litmus Edge, Litmus Edge Manager, and Litmus Unify. It exposes the full Litmus SDK surface (~1250 functions) as shell commands with JSON output, and is the preferred method for AI agents and agentic tasks: no code to write, install, or run.


Ecosystem Context

Layer Guide
MCP Server (curated tools, no code needed) https://api.litmus.io/mcp-agents.md
litmus-cli (this document) https://api.litmus.io/cli.md
Language SDKs (Python today; Go and Rust in the works) https://api.litmus.io/sdk-agents.md
Raw API Collection (full 3,310 endpoints) https://api.litmus.io/agents.md
API Portal (human-readable workspace) https://api.litmus.io

What it is

litmus-cli is the standalone command-line client for the Litmus APIs: the full SDK surface (~1250 functions) as shell commands with JSON output, covering Litmus Edge, Litmus Edge Manager, and Litmus Unify. It is the preferred method for AI agents and agentic tasks.


What's new in cli-v1.0.0

First stable release. Litmus Edge 4.4.x and Litmus Edge Manager 3.0.x are the supported LTS releases, and the CLI follows semantic versioning from here on.

Product Supported Best-effort Dropped
Litmus Edge 4.4.x 4.0.x 3.x
Litmus Edge Manager 3.0.x 2.31.x older than 2.31
Litmus Unify 2.0.x

Breaking and behavior changes - check scripts that call:

Known issues in cli-v1.0.0:


Install and update

# macOS / Linux: detects platform, verifies SHA256, installs to ~/.local/bin
curl -fsSL https://raw.githubusercontent.com/litmusautomation/litmus-sdk-releases/main/install.sh | sh

# Windows: download litmus-cli-windows-amd64.exe from the latest cli-v* release at
# https://github.com/litmusautomation/litmus-sdk-releases/releases and put it on PATH.

litmus-cli version   # print CLI version and build details
litmus-cli update    # self-update in place to the latest cli-v* release

Command overview

Command Purpose
litmus-cli list [prefix] Browse the SDK function catalog (~1250 functions) with parameter names
litmus-cli run <dotted.path> Call any SDK function by dotted path with JSON arguments
litmus-cli le <shortcut> Curated Litmus Edge shortcuts (devices, tags, flows, containers, ...)
litmus-cli le data <cmd> Data plane: provision credentials (setup), live tag values and tag writes (NATS), time-series history (InfluxDB)
litmus-cli le exec\|cp\|logs Marketplace containers: shell or command, file copy in and out, newest logs with tail, since, grep and follow (cli-v0.12.0+)
litmus-cli lem <shortcut> Curated Edge Manager shortcuts (companies, projects, devices)
litmus-cli login [le\|lem\|unify] Browser-based sign-in; no argument shows all three product cards
litmus-cli config set/show Manage saved connection profiles (~/.litmus/<profile>.json)
litmus-cli completion <shell> Shell completion (bash, zsh, fish, powershell); completes run/list paths too
litmus-cli version / update CLI version / self-update

Every command and SDK package has built-in docs via --help.


Discover and run any SDK function

The list / run pair is the core workflow, and the reason the CLI works so well for AI agents: discover the exact function path and arguments, then call it.

# Discover - lists every callable path with argument names
litmus-cli list                 # top-level packages
litmus-cli list le.devicehub    # functions in one package
litmus-cli list lem.Get         # filter by any dotted-path prefix

# Read the docs before calling
litmus-cli list le.devicehub --help                # full docs for that SDK package
litmus-cli run le.devicehub.ListDeviceTags --help  # signature + ready-to-fill --args skeleton

# Run - result is JSON on stdout, errors on stderr
litmus-cli run le.devicehub.ListDevices
litmus-cli run lem.ListIncidents --args '{"projectID": "my-project"}'
litmus-cli run unify.GetNamespace

Litmus Edge packages live under the le. prefix: le.devicehub, le.system, le.analytics, le.digitaltwins, le.flows, le.integrations, le.marketplace, le.opc. Edge Manager and Unify paths are lem.* and unify.* with no extra prefix; the LEM Admin Console (installation-wide settings) is lem.admin.* (cli-v0.13.0+). Live streams and subscriptions (events, device status, processor output) take maxEvents/seconds style bounds and return what arrived (cli-v0.13.0+). Argument keys are camelCase; list <pkg> shows the exact names.

Recommended agent loop: list <prefix> to find the function, run <path> --help for the argument skeleton, then run <path> --args '{...}'.


Curated shortcuts

Common reads are one short command, no dotted path needed.

Litmus Edge (litmus-cli le ...)

Shortcut What it returns
version Device firmware version, API major version, bridge status
apps Installed Edge Applications (from a marketplace catalog) with status and image
versions Every component's version and git commit in one call (DeviceHub, Flows, Analytics, Marketplace, Integrations, OPC UA, Digital Twins, device management, auth, licensing, FTP, UI)
system-info Full firmware build information
devices DeviceHub devices with IDs, driver, running state
drivers [limit] Driver definitions
tags <deviceID> [limit] A device's tags/registers
users Local user accounts
dt-models / dt-instances Digital Twins models / instances
analytics-groups Analytics processor groups
processor-library Analytics processor types (live, falls back to embedded catalog)
flows Node-RED flow services
containers / images Marketplace containers / images
providers / provider-catalog / instances Integration providers and connector instances
opc-config OPC UA server configuration
processor-library-defaults / provider-catalog-defaults / driver-cache-versions Embedded offline catalogs, no connection required

Litmus Edge Manager (litmus-cli lem ...)

Shortcut What it returns
companies Companies visible to the API token
projects <companyName> A company's projects
devices <projectID> [status] A project's devices, optionally filtered (e.g. ACTIVE)

Anything not covered by a shortcut is reachable through run - the shortcuts and the dotted paths hit the same SDK underneath.


Data plane: live and historical tag data

litmus-cli le data reaches past the REST API to the device data plane: live tag values and tag writes through the DataHub broker (NATS, port 4222), and historical values from the device time-series database (InfluxDB, port 8086, database tsdata). Both authenticate separately from the REST API; litmus-cli le data --help explains the credentials.

On a device you administer, le data setup creates those credentials for you and saves them to the profile, so nothing has to be set up by hand in the LE UI. It creates or adopts a broker access account, grants it read on the topics you name (> by default), switches on the device-wide external NATS proxy, and creates or adopts a time-series DB user with READ on tsdata - then connects to both ports to prove the credentials work.

# provision everything and save NATS_TOKEN / INFLUX_* to the profile
litmus-cli le data setup

# report what it would create or adopt, changing nothing
litmus-cli le data setup --dry-run

# check whether the credentials currently in effect still work
litmus-cli le data status

Rerunning setup is safe: it adopts the account and DB user it made last time rather than replacing them, and never resets a credential unless you pass --reset-key or --reset-db-password. One consequence worth knowing: the device cannot report an existing DB user's password, so an adopted user leaves INFLUX_PASSWORD untouched - pass --db-password or --reset-db-password when you need it rewritten. Secrets are masked in the output unless --show-secrets.

# stream live tag values from the DataHub broker (NATS wildcards work)
litmus-cli le data subscribe 'devicehub.alias.MyDevice.*' --limit 5

# long-running: reconnect after dropped connections or broker restarts
# (cli-v0.11.0+; --limit 0 and --wait 0 mean no limit; values published while disconnected are lost)
litmus-cli le data subscribe 'devicehub.alias.MyDevice.*' --reconnect --limit 0 --wait 0

# list time-series measurements (one per device: <DeviceName>.<DeviceID>)
litmus-cli le data measurements

# query historical rows, newest first, with an optional InfluxQL filter
litmus-cli le data poll 'MyDevice.<deviceID>' --last 15m --filter "\"tag\" = 'Temperature'"

Writing tags

Requires cli-v0.11.0 or later. Run litmus-cli version to check and litmus-cli update to upgrade; older releases have no le data write or --write-topics.

le data write <device> <tag> <value> writes a value to a DeviceHub tag and prints the device's reply. <device> and <tag> are names, as in the tag's devicehub.write.<device>.<tag> topic (listed in the tag's Topics). <value> is parsed as JSON when it can be (42, 1.5, true, "text"), otherwise sent as a string.

# grant the broker account write access once (read on '>' already covers the replies)
litmus-cli le data setup --write-topics 'devicehub.write.>'

litmus-cli le data write MyDevice Setpoint 42.5
# {"success": true, "status": "Good", "statusCode": 0, "timestamp": ..., "writeID": "..."}

The command publishes {"value": ..., "writeID": ...} to devicehub.write.<device>.<tag> and waits for the matching reply on devicehub.write_response.<device>.<tag>. It exits non-zero when the device reports success: false, when no reply arrives within TIMEOUT_SECONDS, or when the broker refuses the topic (permission denied ... no access), which means the access account lacks the write or read grant.


Containers: exec, cp, logs

Since cli-v0.12.0 the CLI works inside Marketplace containers on Litmus Edge, the way docker exec, docker cp and docker logs would. <container> is a name or a unique ID prefix from litmus-cli le containers.

# interactive shell (bash if the image has it, else sh)
litmus-cli le exec my-app

# one command with its own arguments; exits with the command's status
litmus-cli le exec my-app -- sh -c 'ls -la /data | head'
cat dump.sql | litmus-cli le exec my-db -i -- psql -U postgres

# copy one file in or out; '-' is stdin/stdout; a trailing '/' copies into a directory
litmus-cli le cp ./app.conf my-app:/etc/app/app.conf
litmus-cli le cp ./app.conf my-app:/etc/app/
litmus-cli le cp my-app:/var/log/app.log ./app.log

# newest log output, filtered and as JSON lines
litmus-cli le logs my-app --tail 100
litmus-cli le logs my-app --since 15m --grep '(?i)error|warn'
litmus-cli le logs my-app --since 2026-10-08T09:00:00Z --json
litmus-cli le logs my-app -f

Limits set by Litmus Edge:

Every one of these commands lists the errors it can return, and what each one means, under "If something goes wrong" in its --help. Read that before running them, especially in an agent.

The same operations are callable through run, for scripts and the MCP fallback tools:

Path Arguments Returns
le.marketplace.ExecOutput container, command (argv array) {exitCode, output}
le.marketplace.CopyToContainer container, path, content (base64) nothing
le.marketplace.CopyFromContainer container, path the file, base64
le.marketplace.ContainerLogs container, since (RFC 3339; omit the key for all) {entries: [{stream, text}], since, truncated}
le.marketplace.ContainerLogTail container, lines {entries: [{stream, text}], since, truncated}

le.marketplace.ContainerLog (the single raw response) now returns plain text, without Docker's stream-frame bytes; it is still the OLDEST 1 MiB.


Configuration

Settings resolve in this order (later overrides earlier):

profile (~/.litmus/<profile>.json)  <  .env file  <  environment  <  flags
# sign in via the browser (writes a profile), or save one by hand
litmus-cli login
litmus-cli config set --EDGE_URL https://10.0.0.5 \
    --EDGE_API_CLIENT_ID abc --EDGE_API_CLIENT_SECRET xyz
litmus-cli config show          # print a saved profile, secrets masked

# multiple devices via named profiles
litmus-cli run le.devicehub.ListDevices --profile staging

# one-off connection via flags (--insecure for self-signed device certs)
litmus-cli --edge-url https://10.0.0.5 --client-id abc --client-secret xyz --insecure le version

Connection variables

Connection Required variables
Direct to a Litmus Edge device EDGE_URL, EDGE_API_CLIENT_ID, EDGE_API_CLIENT_SECRET
Edge via the LEM bridge USE_LEM_BRIDGE=true, EDGE_MANAGER_URL, EDGE_API_TOKEN, EDGE_MANAGER_PROJECT_ID, EDGE_MANAGER_DEVICE_ID
Edge Manager (lem ...) EDGE_MANAGER_URL, EDGE_API_TOKEN
Unify (unify.*) UNS_URL plus UNS_USERNAME/UNS_PASSWORD
Data plane, live (le data subscribe, le data write) NATS_TOKEN (or NATS_USER/NATS_PASSWORD); optional NATS_SOURCE, NATS_PORT, NATS_TLS
Data plane, historical (le data poll) INFLUX_USERNAME, INFLUX_PASSWORD; optional INFLUX_HOST, INFLUX_PORT, INFLUX_DB_NAME, INFLUX_SSL

Common optional variables: VALIDATE_CERTIFICATE=false (self-signed certs; per-product overrides exist), TIMEOUT_SECONDS (default 30), LITMUS_CONFIG_DIR (profile directory, default ~/.litmus). Each variable has a matching flag; run litmus-cli -h for the full list.

To get Edge credentials: in the Litmus Edge UI navigate to System -> Access Control -> Tokens, create an OAuth 2.0 Client with Admin permissions, and copy the Client ID and Client Secret.

Profiles share the Python SDK CLI's format, so existing ~/.litmus/<profile>.json files carry over unchanged.


Notes for AI agents


Cross-References

Need Go to
Download the binary https://github.com/litmusautomation/litmus-sdk-releases/releases (cli-v* tags)
CLI and SDK navigation guide for LLMs https://api.litmus.io/sdk-agents.md
MCP server (tool calls, no shell) https://api.litmus.io/mcp-agents.md
Raw API collection https://api.litmus.io/agents.md
Report a bug or request a feature https://github.com/litmusautomation/litmus-sdk-releases/issues
Product docs https://docs.litmus.io

View this page as Markdown