Developer tools & API

Telmoni CLI

Installing and using the official Telmoni command-line tool (telmoni): device authentication, CI login, status, organizations, and configuration.

The Telmoni CLI (telmoni) is the official command-line interface for interacting with Telmoni from your terminal, scripts, and CI/CD pipelines.

Installation

Install the latest release binary.

$ curl -fsSL https://raw.githubusercontent.com/telmoni/telmoni-cli/main/install.sh | sh

The installer downloads the release archive for your platform, checks it against the release's SHA256SUMS, and installs telmoni into /usr/local/bin when that directory is writable or the installer runs as root, and into ~/.local/bin otherwise. https://telmoni.com/install.sh redirects to the latest release's copy of the same script. TELMONI_INSTALL_DRY_RUN=1 prints the download, extract, mkdir, mv and chmod commands instead of running them. To pin a version or choose the directory, set TELMONI_VERSION or TELMONI_INSTALL_DIR. The installer goes through sudo or doas to create a directory that does not exist yet, the default ~/.local/bin included, and to write into one your user cannot write to:

$ curl -fsSL https://raw.githubusercontent.com/telmoni/telmoni-cli/main/install.sh | TELMONI_VERSION=0.1.2 TELMONI_INSTALL_DIR=/usr/local/bin sh

Release binaries are built for x86_64 Linux and link against glibc. On a Mac the installer stops until the macOS build is signed, as it does on ARM64 Linux, and on a musl-based system such as Alpine the binary does not run, so you build from source instead.

Each release's archives and install.sh carry build provenance signed through Sigstore, which the GitHub CLI checks a download against:

$ gh attestation verify telmoni-linux-x86_64.tar.gz --repo telmoni/telmoni-cli

Verify the installation by checking the version, which the CLI prints after its name:

$ telmoni --version

Authentication

1. Interactive login (Browser & Device Code)

For local development machines, authenticate using the interactive device authorization flow (RFC 8628):

$ telmoni login

The CLI prints a one-time code and the address of the console's device page (/auth/device), then opens that page in your browser with the code filled in. It opens the page only when the address is the endpoint's own, or the console beside a machine host — the endpoint's host with its leading api. taken off, so api.telmoni.com opens a page on telmoni.com; a deployment whose console answers anywhere else gets note: the verification page is not on <endpoint>; open it yourself instead. For headless environments or SSH sessions where a browser cannot be opened, add --no-browser:

$ telmoni login --no-browser

To authenticate against a self-hosted Telmoni instance, supply the --endpoint flag (or set TELMONI_ENDPOINT): the deployment's machine host, or its console's host where the machine lanes are routed by path (Self-hosting → Production):

$ telmoni login --endpoint https://api.telmoni.example.com

The endpoint must use HTTPS unless it is this machine (localhost or a loopback address): the CLI refuses to send credentials over plain HTTP to any other host. A request to this machine never goes through a proxy, whatever the system proxy variables name. An endpoint given without a scheme gets https://, or http:// for this machine. The CLI follows no redirects, and gives up on a request after 30 seconds.

  1. Open the printed address in a browser, on any machine. If you are not signed in to the console there, it asks you to sign in first and returns you to the page.
  2. Check that the code on the page is the one in your terminal. The page the CLI opened already carries it; otherwise, type it in.
  3. Select Approve.
  4. The CLI, which has been polling for the decision every five seconds, saves its credentials and prints the address you signed in as and your active organization, which starts as your default organization. The code is good for ten minutes: one nobody approves in time, or that the page's Deny refuses, ends login with an error, and you run it again.

Your CLI session appears under Active sessions on your account's Privacy page (/account/privacy), labeled by operating system, such as Telmoni CLI (macOS). Ending the session there ends the CLI's: the next command that calls the server, such as status, is refused, and the CLI removes its saved credentials. Signing in again, with the browser or a key, replaces the saved credentials without ending the earlier session, which stays under Active sessions until it is ended there, or by a password reset or an email change, which end every session; run telmoni logout first to end it.

2. Programmatic & CI login (API key)

For headless build systems, GitHub Actions, Docker containers, and background automation, use an API key. Put it in the TELMONI_API_KEY environment variable, and every command that acts with a key uses it, ahead of any saved login, without saving it:

$ export TELMONI_API_KEY="telmoni_..."
$ telmoni status

At a terminal, a command that acts with a key asks before it uses a new one, on stderr and without showing it: TELMONI_API_KEY holds an API key. Use it ahead of the saved login? [y/N]. Your answer is kept for that key alone, in config.json under api_key_answers, by the key's SHA-256 rather than the key, so a new key is asked about again; no answer at all, as Ctrl-D gives, passes it over for that command alone. A key you decline is passed over as if the variable were unset. To change your answer, set use_api_key_env while the variable holds the key:

$ telmoni config set use_api_key_env true

Where nobody can answer — in CI, with standard input or standard error not a terminal, or with --json — the key is used without asking, whatever you answered at a terminal.

A blank TELMONI_API_KEY counts as unset. To save a key instead, pipe it to telmoni login --with-key, which reads it from standard input, so it never sits on the command line, in your shell history or in the process list. Typed at a terminal, it is refused:

$ telmoni login --with-key < key.txt

login --with-key checks only the key's shape (the telmoni_ prefix with something after it, and no whitespace) and saves it with the endpoint. It does not call the server, so a wrong key is refused by the first command that uses it.

To fetch the key from a secret manager for each command instead, set api_key_helper to a command that prints it. It runs through sh when TELMONI_API_KEY is unset or its key declined, with 30 seconds to answer; what it prints is the key, never shown or saved, and its error output is shown as it is.

For the CLI, a key opens the API and nothing else, and only a key holding the read scope (Read the API) opens it. With a key, status is the one command that calls the server, and a key minted only to send spans gets 403 there (this API key does not hold the read scope); the org commands need a browser session. While TELMONI_API_KEY is set, login, logout and the org commands, which manage the saved login, say on stderr that the variable comes first, unless you declined its key at a terminal or have yet to be asked about it.


Checking session status

To verify your active identity and selected organization context:

$ telmoni status

telmoni whoami is the same command under another name. With a browser session, it prints:

  • the address you are signed in as, with your display name when you have one;
  • the active organization: its name, its ID and your role in it;
  • how many organizations you belong to;
  • the endpoint the session belongs to;
  • how many minutes the access token has left.

With an API key, it asks GET /v1/organization and prints the ID and name of the key's organization, then the endpoint. A key from TELMONI_API_KEY or api_key_helper is named as such (API key from TELMONI_API_KEY for …), and asks at the endpoint TELMONI_ENDPOINT, the configuration file or the default names. Signed out, it prints the endpoint it would sign in to and exits with an error.

With a browser session, status also saves the organizations the server answered. If you are no longer in the saved active organization, it replaces it with your default organization, whether or not TELMONI_ORG is set.

JSON output for automation

Add --json to produce machine-readable output suitable for jq or scripting:

$ telmoni status --json

With a browser session, the object holds:

FieldValue
authTypedevice
endpointThe endpoint the session belongs to
personAn object: userId, email and displayName
activeOrganizationAn object: organizationId, slug, label and role; null when there is none
organizationCountHow many organizations you belong to
tokenExpiresInSecsSeconds until the access token expires

With an API key, it holds authType (api_key), keySource (environment, helper or saved), endpoint, and organization: an object of organizationId, slug and label. Signed out, status --json prints nothing and exits with an error.


Managing organizations

If your account belongs to multiple organizations, use the org subcommand to list them and to choose the one the CLI acts in.

List organizations

$ telmoni org list

The list has one line per organization: its ID, its slug, its name and your role, with * marking the active one. It is the list the CLI saved the last time login, status or org switch asked the server; org list itself sends no request.

Switch active organization

Switch the organization that future commands act in:

$ telmoni org switch acme

The argument is the organization's ID (org_...) or its slug (the first segment of its console URL), matched exactly; a name is not accepted. The CLI looks it up in the list it saved, so one that list does not hold is refused before any request. It then asks the server for your organizations again and saves the answer. It refuses when you are no longer in the organization, or when a URL change has moved the slug off it; otherwise it saves the organization as the active one and prints it.

To act in another organization for a single command without changing the active one, set TELMONI_ORG to its ID or slug. With a browser session, status (whoami) and logout read it; with an API key, they ignore it. Like org switch, they look it up in the list the CLI saved and refuse one that list does not hold before any request (TELMONI_ORG names no organization in the cached list; run telmoni status without it to refresh the list); a refused logout keeps the credentials:

$ TELMONI_ORG=acme telmoni status

A script should carry the ID. Changing an organization's URL moves its slug (a rename does not), and the CLI looks a slug up in the list it saved without asking the server first. The first status after a URL change checks the slug against the server's answer, fails rather than report on another organization, and saves the new list; from then on the old slug names whichever of your organizations goes by it now, if any. telmoni org list shows the slugs the CLI last saved.


CLI Configuration

The CLI stores local preferences in config.json, in the same directory as the credentials file, even on a Mac whose login is in the Keychain.

$ telmoni config list

To point telmoni login at a self-hosted Telmoni instance:

$ telmoni config set endpoint https://telmoni.internal.company.com

To read back a configuration key:

$ telmoni config get endpoint

Configuration keys reference

KeyDescriptionDefault
endpointThe Telmoni server URL telmoni login signs in to: the machine hosthttps://api.telmoni.com
api_key_helperA shell command that prints an API key, such as a secret manager's read, run for each command that acts with a key while TELMONI_API_KEY is unset or its key declined. The file holds the command, never the key.None
use_api_key_envWhether commands at a terminal use the key now in TELMONI_API_KEY ahead of the saved login: true or false, for that key alone. Kept under api_key_answers by the key's SHA-256, never the key; read, set and listed only while the variable holds a key.Asked by the first command that acts with the key
output_formatAccepted and stored. No command reads it: use --json for JSON output.None (config list shows (default: text))

config set checks the key, and the value only for use_api_key_env.


Global options

OptionDescription
-v, --verboseLog to stderr where the CLI read and wrote the saved login (and a missing configuration file), where its endpoint came from, the sign-in and refresh steps it takes, each request's method, address and organization, and each answer's status and content type; no header or body is logged.
-h, --helpPrint help information
-V, --versionPrint version information (telmoni --version, before any subcommand)

telmoni exits 0 on success and 1 on any failure, which it explains on stderr; a mistyped command or flag exits 2. logout exits 0 when nobody is signed in.


Environment variables

The CLI reads the following environment variables:

VariableDescription
TELMONI_ENDPOINTThe endpoint telmoni login signs in to (default: https://api.telmoni.com, the machine host). It comes after --endpoint and ahead of the endpoint configuration key. A saved session keeps the endpoint it signed in to.
TELMONI_API_KEYAn API key for each command that acts with one, ahead of any saved login and never saved, for CI/CD runs. At a terminal, a new key is asked about once first. A blank value counts as unset.
TELMONI_ORGWith a browser session, the organization status, whoami and logout act in instead of the active one, by ID or slug, from the list the CLI saved. A script should give the ID, which nothing moves.

Its requests to any host but this machine also go through a proxy named by the system proxy variables (HTTPS_PROXY, HTTP_PROXY, ALL_PROXY and NO_PROXY), which its HTTP library reads.


Logging out & credentials security

To end your CLI session and remove the saved credentials:

$ telmoni logout

With a browser session, this command:

  1. Asks the Telmoni server to revoke the session.
  2. Removes the saved credentials, from the Keychain on a Mac and from the credentials file, whatever the server answered. If the server did not confirm, the CLI says so and tells you to end the session from Active sessions in the console.

With a saved API key, it only removes the key. The key itself stays valid until it expires or you revoke it. A key in TELMONI_API_KEY was never saved: unset the variable yourself.

Credential storage paths

On macOS the CLI keeps its saved login in your login Keychain, as a password item for the service telmoni, which macOS encrypts and asks you about before another program reads it. Where the Keychain refuses it, as a locked one does over SSH, the CLI writes the credentials file instead and says so on stderr; with a copy in each, it reads the newer, and the next save the Keychain takes removes the file. The Keychain may ask you something only when stderr is a terminal: without one, as on a CI runner or with stderr redirected, a dialog it would need, to unlock it or to let a rebuilt telmoni read the item an older build saved, counts as a refusal. A save then goes to the file, and a login kept only in the Keychain is not read, so the CLI counts as signed out and says note: the Keychain did not answer (…), so a login saved there is not read. On Linux it always writes the file.

macOS ties the item to the program that saved it. A CLI built from source is a new program after every build, so macOS asks once whether it may use the item: enter your login password and choose Always Allow. Over SSH, where it cannot ask, the CLI says the Keychain did not answer and counts as signed out until you allow it at the Mac or run telmoni login again.

The credentials file is written with 0600 permissions (readable and writable only by your OS user) and is not encrypted:

  • macOS: ~/Library/Application Support/telmoni/credentials.json
  • Linux: $XDG_CONFIG_HOME/telmoni/credentials.json, which is ~/.config/telmoni/credentials.json when XDG_CONFIG_HOME is not set

Where that directory cannot be found, such as on a machine with no home directory, the CLI stops with an error rather than keep credentials anywhere else. The file is written as a sibling created with 0600 and renamed over the old one, so a crash mid-write leaves the previous file whole. A directory the CLI creates to save credentials in is 0700; one that already exists, such as one telmoni config set created first, keeps its permissions.

Saved credentials the CLI cannot read count as signed out: the CLI says note: the saved credentials cannot be read; sign in again on stderr, and telmoni login saves new ones.