Skip to main content

Command Reference

The qumod CLI follows standard POSIX conventions:

Global Flags

These flags can be provided to any qumod command:

Prompts

In a terminal, a command asks for what you didn’t pass instead of failing: which organization or project (picked from a list), which key to revoke, which member to remove, a name or an email. Before something that can’t be undone (keys revoke, members remove, members uninvite) it asks you to confirm, with No as the default. With --yes, --json, or no terminal (a script, CI, a coding agent), it never asks: a missing argument is a usage error (exit code 2), and confirmations are skipped, as they always were.

Version Warnings

When qumod is invoked, it checks if a newer version is available (cached in ~/.qumo/version-cache.json for 24 hours with a 1.5s timeout). Outdated warnings are sent to stderr (in text or as a JSON object with {"warning": "..."} under --json), leaving stdout intact. Set QUMOD_NO_VERSION_CHECK=1 to suppress this check.

qumod login

Initiates the OAuth 2.0 Device Flow to authorize a workstation in the browser.

Usage

Options

  • --api-url <url>: Specify a private control plane or local development cluster.
  • --json: Writes one JSON object per line, each with a status, and does not open the browser:
    Read stdout line by line: the first line arrives as soon as the code is issued, the second when the sign-in is approved. expires_in on the pending line is the seconds left to approve it.

qumod logout

Ends the qumod login session on the control plane and removes the token from ~/.qumo/config.json. A personal access token is not ended by logout; revoke it in the console. With --json, revoked says whether the control plane ended the session:

Usage


qumod whoami

Displays the signed-in user, the active organization, the IAM role in it, the API URL, and every organization the user belongs to. With a personal access token (qumo_pat_…) the control plane does not say whose token it is, so the user is not shown. In --json, auth is "personal_access_token" ("session" after qumod login), user is null, and organization and role are set only when the token’s user belongs to exactly one organization.

Usage

Examples


qumod network

A qumo network you run yourself, for your organization’s dev project. This is how you use Qumo on the Free plan. (Prod projects use Qumo’s managed relay network instead; nothing here creates a managed relay.)
The relay, and any nodes you run beside it, run as plain processes, not in containers. The first start downloads the qumo release the network is pinned to and checks it. To keep them apart from the rest of your machine, run qumod itself in a container or VM. Every subcommand but create acts on the network in the current directory, or the one --dir <path> names. qumod network help lists the subcommands, the endpoints and the files.

Subcommands

qumod network create [directory] [--organization <id|name>] [--prefix <path>] [--nodes <list>]

Sets up a network in a new directory. It uses the organization’s dev project (creating it if there is none), registers a new signing key with it, and writes the settings of the relay and of the nodes you chose to run beside it: start writes each node’s log (.qumod/<node>.log) and run state to .qumod/. In a terminal, it asks for the directory name, which organization to use if you belong to several, and which nodes should run beside the relay (a checkbox list: Space ticks a node, Enter confirms). When you tick rtsp, it also asks for the camera’s URL. With --yes, --json, or no terminal, it asks nothing and uses the defaults: the relay alone.
Arguments and flags:
  • [directory]: where to set up the network. It must be new, or empty apart from files like .git. Default: qumo-network.
  • --organization <id|name>: the organization whose dev project to use. Default: your only organization, or the active one after qumod login.
  • --prefix <path>: confine the signing key to this path under the project’s root. Default: the whole project.
  • --nodes <list>: the nodes to run beside the relay, comma-separated: hls, rtmp, rtsp-push, rtsp, funnel; or none. Default: ask in a terminal, otherwise none.
rtsp needs a camera to pull from. Unless you gave one when asked, rtsp.env holds a placeholder (QUMOD_RTSP_SOURCE=rtsp://SET-YOUR-CAMERA/stream), and start won’t run rtsp until you set it. With --json, stdout carries the directory, the project, the registered key, the nodes and the file paths; the private key itself is never printed.

qumod network start [node...] [-d] [--dir <path>] [--qumo-bin <path>]

Runs the network’s nodes, in this terminal (Ctrl-C stops them) or with -d in the background. Without arguments it starts them all, the relay first and the others once the relay answers on /health; name nodes (qumod network start hls) to start only those. A node other than the relay needs the relay running. In the terminal, each line of output is prefixed with its node ([hls]) when several run. The first time, it downloads the qumo release named in network.json into your cache directory and checks its SHA-256 against the release’s checksums.txt: If certs/ holds no certificate, it makes a self-signed ECDSA one for localhost, 127.0.0.1 and ::1, valid for 14 days, and remakes it after 12; the running nodes then restart, since each reads the certificate only when it starts. Its SHA-256 hash is in certs/server.crt.sha256, for a browser to pin over WebTransport (serverCertificateHashes). To use your own certificate, such as one from mkcert, put it in certs/ and delete certs/self-signed; qumod then leaves it alone:
Flags:
  • -d, --detach: run in the background.
  • --qumo-bin <path>: run this qumo binary instead of downloading the release (also the QUMO_BIN environment variable).

qumod network stop [node...] [--dir <path>]

Stops the running nodes, the relay last, or only the ones named.

qumod network status [--watch] [--dir <path>]

Shows each node’s state (running, starting or stopped), pid and port, and every node’s endpoints; for the relay, its uptime, sessions, broadcasts and subscribers, how many credentials it admitted and refused, its traffic, the paths it carries, and the certificate’s age. --watch redraws it every 2 seconds; with --json, stdout carries the same as JSON.

qumod network logs [node] [-f] [-n <lines>] [--dir <path>]

Prints a node’s log (.qumod/<node>.log), the relay’s by default. -f follows it; -n sets how many lines to print (default 100). When the relay refused a credential, it prints a hint to stderr about what to check.

qumod network token --publish <patterns> | --subscribe <patterns> [--root <path>] [--ttl <duration>] [--key <file>] [--dir <path>]

Signs a test credential with a signing key, for a client to connect with (?jwt=<credential>). Run it in the network directory, or pass --dir, and it uses that network’s signing-key.jwk:
It prints only the credential, so TOKEN=$(qumod network token --subscribe /) works; what it grants goes to stderr. Your app signs its own credentials the same way, with the key on its server (see Signing Keys). Flags:
  • --publish <patterns>, --subscribe <patterns>: what the credential grants, as comma-separated patterns relative to the root: /cam is that broadcast, /cam/ every broadcast beneath it, / everything. At least one is needed.
  • --root <path>: the directory the patterns are relative to, within the key’s prefix. Default: the key’s prefix.
  • --ttl <duration>: how long it lasts, such as 90s, 15m or 1h. At most 1h. Default: 15m.
  • --key <file>: the signing key. Default: signing-key.jwk.
With --json, stdout carries the credential, its kid, root, patterns and expires_at.

Endpoints

The relay listens on port 4433 and admits only credentials signed by a key in config/keys.json: The plain-HTTP routes share the relay’s TCP port. RELAY_ADDR in relay.env moves them all.

Nodes

Beside the relay, a network can run qumo’s other nodes, each as its own process with its settings in <node>.env, reaching the relay on localhost. Choose them with create (--nodes); qumod network help lists them too. The ports are the defaults; each .env file moves its node’s. <prefix> is the signing key’s prefix (--prefix), the directory these nodes publish beneath.
  • The publishing nodes (rtmp, rtsp-push, rtsp, funnel) connect to the relay as clients and sign their own credentials with signing-key.jwk, granting publish beneath the key’s prefix (RELAY_PUBLISH). Those that listen admit only credentials signed by a key in config/keys.json, as the relay does. funnel keeps records in memory, and loses them when it stops, unless you set LEDGER_URI in funnel.env.
  • The HLS egress serves a broadcast once something opts it in (below); players need a credential (?jwt=). It reads every announcement under /.hls/, which a credential confined to one project can’t grant, so it joins as a relay peer instead: create makes a local CA (certs/peer-ca.crt) and a peer certificate for it, and points the relay at the CA (CA_FILE in relay.env, set only when you choose hls).

Serving a stream over HLS

The stream stays at its own path, such as <prefix>/cam. To have the hls node serve it, announce the same path beneath /.hls/ (/.hls/<prefix>/cam). That announcement carries no media; it is a pointer, and the egress follows it to the real broadcast. So publishing a stream and opting it into HLS are separate rights: the opt-in needs a credential rooted at the key’s HLS mirror, which your app signs with the same key.
Players then fetch http://localhost:8080/<prefix>/cam/master.m3u8?jwt=<viewer credential>. The playlists carry the credential on to every URL they name.

qumod project

Manage the projects in an organization. Both subcommands take --organization <id|name>. Without it they use your only organization, or, after qumod login, the active one that qumod whoami shows. A personal access token whose user belongs to several organizations must pass --organization.

Subcommands

qumod project list [--organization <id|name>] (alias: qumod project ls)

Lists the organization’s projects.
Sample table output:

qumod project create <name> [--env <environment>] [--organization <id|name>]

Creates a project.
Flags:
  • --organization <id|name>: the organization to create it in (see above).
  • --env <prod|dev>: prod uses the managed relay network and needs the Pay as you go or Enterprise plan; dev is for a relay you run yourself (one per organization, and every organization starts with one). Default: asked in a terminal; otherwise prod.

qumod keys

Manage the Ed25519 keys your app signs relay credentials with. See Signing Keys. Every subcommand takes --project <id> (from qumod project list).

Subcommands

qumod keys create <name> --project <id> [--prefix <path>] [--out <file>]

Generates a signing key on this machine, registers its public half with the project, and writes the private key to a file. The private key is never sent anywhere, and the file is its only copy: keep it on your app’s server.
Flags:
  • --prefix <path>: confine the key to this path under the project’s root. Default: the whole project.
  • --out <file>: where the private key is written (owner-only). Default: signing-key.jwk. An existing file is never overwritten, and then nothing is registered.
With --json, stdout carries the registered key and private_key_file; the private key itself is never printed.

qumod keys list --project <id> (alias: qumod keys ls)

Lists the project’s keys, newest first, revoked ones included.

qumod keys revoke <kid> --project <id>

Revokes a key. This is final: within about a minute it ends every session the key admitted, however old. Before rotating, read Rotation and revocation.

qumod keys export --project <id> [--out <file>]

Writes the project’s active keys as the key set a relay you run trusts (its QUMO_AUTH_KEYS file), replacing the file in one step. Run it after you create or revoke a key; a running relay picks the change up within 30 seconds. In a directory qumod network create made:
Flags:
  • --out <file>: where the key set is written. Default: keys.json.
A project with no active key is refused, and the file is left as it was: a relay refuses an empty key set.

qumod members

Manage who belongs to an organization. Every subcommand takes --organization <id|name>, resolved as for qumod project. Managing members needs the Organization Admin role (organization.admin).

Subcommands

qumod members list [--organization <id|name>] (alias: qumod members ls)

Lists the organization’s role bindings: its members, and any identities granted an organization role. Each row’s Binding id is what remove takes.

qumod members invitations [--organization <id|name>]

Lists invitations that have not been accepted yet.

qumod members invite <email> [--role <role>] [--organization <id|name>]

Emails an invitation, valid for 7 days, and prints its link so you can send it yourself too.
Flags:
  • --role <role>: the role the invitee receives, by id (roles/project.editor) or short name (project.editor). The CLI checks it against the organization’s roles before inviting. Default: project.viewer.

qumod members remove <binding-id|email> [--organization <id|name>] (alias: rm)

Takes away a member’s organization role. With an email, the member’s binding is looked up first; if they hold several roles, pass the binding id instead.

qumod members uninvite <invitation-id|email> [--organization <id|name>]

Withdraws a pending invitation.

qumod usage

Shows usage over time: the organization’s across all its projects, or one project’s with --project <id>. By hour it covers the last 24 hours; by day, the last 30 days.
Flags:
  • --project <id>: one project’s usage.
  • --metric <name>: gateway.ingress_bytes or gateway.egress_bytes. Default: ingress and egress bytes side by side. Only egress is billed; ingress is shown for information.
  • --granularity <hour|day>: the bucket size. Default: day.
  • --organization <id|name>: the organization, when not --project.
The table shows bytes in decimal units (1 GB = 10⁹ bytes). With --json, stdout carries one series per metric with its raw values.

qumod billing

Subcommands

qumod billing summary --project <id> (the default)

Shows the organization’s plan and the current billing period: egress so far (the billed direction; qumod usage shows ingress too), organization-wide and the project’s share, and the metered cost (no plan has a monthly fee).

qumod billing invoices [--organization <id|name>]

Lists the organization’s invoices, newest first, with a link to each PDF. Changing the plan or the payment method happens in the console.

qumod audit

Shows who changed what, newest first: the organization’s audit log, or one project’s with --project <id>.
Flags:
  • --project <id>: one project’s entries.
  • --action <action>: only this action, e.g. project.create.
  • --actor <id>: only entries by this user or identity.
  • --type <resource-type>: only entries about this kind of resource, e.g. project, signing_key, identity, organization.
  • --since <time>, --until <time>: an age such as 30m, 24h or 7d, or an RFC 3339 time.
  • --limit <n>: at most this many entries, up to 1000. Default: 100.
  • --organization <id|name>: the organization, when not --project.

qumod update

Updates the installed CLI to the latest release. It reads https://dl.qumo-deploy.com/qumod/latest, downloads this platform’s binary, verifies it against the release’s SHA256SUMS, and replaces the running executable. A failed download or a checksum mismatch installs nothing, and a binary that is already the latest is left alone.
With --json, stdout carries one object with previous_version, version, updated (false when it was already latest) and path. QUMOD_DOWNLOAD_URL points it at a mirror. The install directory must be writable by your user. On Windows the replaced executable is held until the process exits; it remains as qumod.exe.old-<pid> and the next update removes it.

qumod version

Displays the installed CLI version and platform. qumod --version is the same.