Tendrl CLI: Getting Started

tendrl-cli is the command-line interface for the whole Tendrl platform — Contact, Strand, and Surface from one terminal. Where the SDKs connect devices to the platform, the CLI is for you: register and manage entities, read and export messages, run workflows, submit scans, manage API keys and team access, and script any of it with --json.

tendrl-cli listing a device fleet, with online in green and offline in red

Requirements: Python 3.10+

Two different tools

tendrl-cli is not the tendrl Nano Agent CLI. The Nano Agent's tendrl binary talks to a local agent socket on a device; tendrl-cli talks to the platform APIs with your account credentials.

Install#

Installs straight from GitHub — with uv (recommended):

bash

uv tool install git+https://github.com/tendrl-inc-labs/tendrl-cli

or with pipx:

bash

pipx install git+https://github.com/tendrl-inc-labs/tendrl-cli

Pin a release for reproducible installs:

bash

uv tool install "git+https://github.com/tendrl-inc-labs/[email protected]"

Verify it landed:

bash

tendrl-cli --version

Two kinds of credentials#

The CLI uses the same authentication the platform does, and it helps to know which credential does what:

Credential Commands it powers Where it comes from
Session (browser or password) whoami, accounts, billing plans tendrl-cli login
Account API keys (one per product) everything else — contact, strand, surface Access Control in each product's console, or minted from the CLI

Device/entity keys (TENDRL_KEY in the SDKs) are deliberately not used: the CLI is an account tool, and entity keys can't call account endpoints anyway.

Sign in#

bash

tendrl-cli login

Your browser opens to an approval page — sign in there if you aren't already (email + password or GitHub/Google, so OAuth accounts work), click Approve sign-in, and the CLI receives its session. No password ever touches the terminal, and the CLI gets its own 14-day session, revocable independently of your browser's.

tendrl-cli login opening the browser and receiving a session

The approval page shows which account is signing in and gives you a single Approve sign-in button. The authorization code is single-use, expires in 60 seconds, and the exchange is PKCE-protected — the code alone is useless without the verifier that stays in the CLI process.

Over SSH or without a browser, tendrl-cli login --no-browser prints the approval URL and asks for the code the page shows. tendrl-cli login --password keeps the old email + password prompt. The session is cached in ~/.config/tendrl/config.json (file mode 0600); tendrl-cli logout revokes it.

Set your API keys#

Each product reads its own key, from a flag, an environment variable, or the config file — in that order:

Product Environment variable Stored alternative
Contact TENDRL_API_KEY (or CONTACT_API_KEY) tendrl-cli config set-key contact
Strand STRAND_API_KEY tendrl-cli config set-key strand
Surface SURFACE_KEY (or SURFACE_API_KEY) tendrl-cli config set-key surface
No API key yet? Bootstrap from your session

After tendrl-cli login, you can mint your first Contact account key with the CLI itself — the session token works as the bearer credential:

bash

tendrl-cli --json --key "$(python3 -c "import json;print(json.load(open('$HOME/.config/tendrl/config.json'))['session_token'])")" \
  contact keys create --data '{"name":"my-cli-key","role":"Admin"}'

The token in the response is shown once — save it as TENDRL_API_KEY.

First commands#

bash

# who am I, which account?
tendrl-cli whoami

# fleet at a glance
tendrl-cli contact entities list

# data usage against your plan
tendrl-cli contact insights usage

# run a workflow and watch it
tendrl-cli strand workflows run <workflow-id> --data '{"temp": 71.2}'
tendrl-cli strand runs list --limit 10

# scan a file with Surface
tendrl-cli surface scan file ./firmware.bin

Scripting with --json#

Every command accepts a global --json flag that prints the raw API response to stdout (tables and status messages go to stderr, so pipes stay clean either way):

bash

tendrl-cli --json contact entities list | jq -r '.data[].name'

The platform URL#

The CLI talks to https://app.tendrl.com. TENDRL_APP_URL, --app-url, or tendrl-cli config set-url override it, should you ever need to point it elsewhere.

Troubleshooting#

Next#