Tenux CLI
Tenux runs an agent on the computer you want to reach. The tenux CLI is that agent — install it, pair it, and your computer appears on your phone.
Install
Install the CLI globally with npm (Node.js 22+; supported on Windows and Linux, with macOS experimental):
npm i -g @tenux/cliThen pair this machine with your Tenux account — this opens a browser link to authorize and stores a long-lived device credential locally:
tenux loginOnce paired, start the agent:
tenux starttenux start runs the long-lived agent — heartbeat plus tunnel / peer-to-peer bring-up — so the machine stays reachable from your phone. Leave it running. Prefer to install from the web? See the install page.
Command reference
Every tenux command is listed below. Run tenux --help or tenux <command> --help for the same list from the CLI itself.
Authentication
tenux login [--url <url>]Pair this machine with your Tenux account: opens a browser link to authorize, then stores a long-lived device credential locally. Pass --url <url> to point at a specific Tenux app endpoint (for self-hosted or staging setups); without it the CLI uses its built-in default app URL.tenux logoutUnregister this device and clear the local config — revokes the device credential server-side and removes ~/.tenux/config.json. Run tenux login again to re-pair.Running the agent
tenux start [-d] [--plain]The one command: starts the agent in the background (if it isn't already running) and opens its command center — a full-screen view of the agent's status, terminals, and live activity. Press q to leave; the agent keeps running, so your phone stays connected after you close the terminal, disconnect SSH, or lock the screen. Run tenux start again anytime to reopen the same screen. From inside it: r restarts the agent (the screen rides through), x stops it (with a confirm). Pass -d to start the background agent and get your prompt back without the command center; --plain runs the agent in this terminal with plain line logs (scripts and CI get that automatically). Background logs go to ~/.tenux/logs/agent.log (kept on your machine, never uploaded).tenux stop [--force]Stop the running agent cleanly — the supervisor stops too, so nothing respawns. Verifies the agent actually went down before reporting success. --force kills the process tree instead of asking, for a wedged agent.tenux status [--debug]The human answer to "is my agent up, and where do I open it": whether it's running (version, uptime, and whether it's a background daemon or foreground), its tunnel, how many terminals are open, your device name, whether you are authenticated, which device-local AI provider keys are configured (see tenux ai keys below), and the workspace URL to open on your phone. Pass --debug to also show infra internals — config path, device/user IDs, the Supabase URL, and the projects directory — that a user checking on their agent doesn't need day to day. Never prints secret values.tenux tasks [--app <name>]Your task list per app — the same list as the workspace's Tasks screen — with each task's status (not started, ADR written, in progress, blocked, done) and a flag when something in progress has nobody working on it or a task has gone stale. Reads the list on this machine directly, so it works even while the agent is stopped.--app shows one app only. To add or change tasks, ask Tenux Chat.tenux agents create [--app <name>] [--name <n>]Start an agent: your own Claude Code, running in a Tenux terminal in an app's folder and signed in with your own subscription (Tenux never sees the login). An API key in your shell is ignored inside an agent, so it always runs on your subscription. Codex agents come next. Needs the agent running. tenux agents list shows each agent, whether it is running, the task it holds, and what it last did; tenux agents stop <agent> closes its terminal and keeps the record; tenux agents remove <agent> forgets a stopped one.AI provider keys
Tenux chat is provider-agnostic: Anthropic, OpenAI, Z.ai (GLM), DeepSeek, Moonshot (Kimi) and Alibaba (Qwen) are supported. On tenux.dev your key lives on your computer, not on our servers. Set it with tenux ai keys set, and chat uses it for models from that provider; for anything else, chat runs on Tenux credits.
Keys are stored in your local config at file mode 0600 and are never printed back in full. Tenux chat picks the local key matching the requested model’s provider and never substitutes a different provider’s key.
If ANTHROPIC_API_KEY is set in the environment the Tenux agent runs in, Tenux chat treats it as your Anthropic key: Claude models run on it, billed by Anthropic to you, not on Tenux credits.
tenux ai keys set [key] [--provider <id>]Add or replace a device-local provider key. Pass the key inline, or run with no argument to be prompted (hidden input, so it never reaches shell history). Tenux detects the provider from the key’s shape and verifies it live against that provider before saving — on success it prints where that provider processes your prompts (its data region) so you know the destination. Pass --provider <id> (one of anthropic, openai, zai, deepseek, moonshot, alibaba) to force the provider and skip the live check instead — useful offline, or when detection can’t disambiguate.tenux ai keys clear [provider]Remove a stored device-local key. With exactly one provider stored, the provider argument is optional; with more than one, name which provider to remove.tenux ai keys listShow which providers have a device-local key set (alias: tenux ai keys status). Never prints key contents.Configuration
The tenux config command group reads and writes individual settings in your local config. Note the asymmetry: get can read six keys, but only three of them are writable with set — the other three are issued at login and are read-only.
tenux config set <key> <value>Set a writable config value. Writable keys: projects-dir (base directory for cloned projects), device-name (the display name for this device), and app-url (the Tenux app URL this device links against).tenux config get <key>Read a config value. Readable keys are the three writable ones above plus three read-only keys set at login: device-id, supabase-url, and user-id. These three can be read but not changed with config set.MCP — bring any AI into your workspace
tenux mcp [--print-url]Stdio bridge that exposes this workspace to any MCP-capable AI you run on this machine (Claude Code, Codex, or any other MCP client) — not just Tenux Chat. Requires the agent to already be running (tenux start). Pass --print-url to print the local /mcp endpoint URL (no token) for clients that speak Streamable HTTP directly, instead of starting the stdio bridge.Watching the agent live
tenux attach [-v] [--plain]The agent's command center: a full-screen view with its status (device, version, uptime, tunnel, peer-to-peer link) and a live, curated activity feed — the operator narrative plus anything flagged a warning or worse; press v for every forensic line, or pass -v to start that way. Press q to detach — the agent keeps running. Pass --plain for simple line output instead (piped output gets it automatically, so scripts see plain lines either way). Works inside a Tenux workspace terminal too, so you can watch your agent from your phone.tenux open <terminal>Mirror one of your workspace terminals in this console, tmux-style: what you see on your phone appears here, keystrokes from either side reach the same shell, and both stay attached. Name the target by its tab label, its id, or its tab-bar position (terminal 2). Press Ctrl+] to detach — the terminal keeps running in your workspace. Everything else, Ctrl+C included, goes to the mirrored shell. Refuses to mirror a terminal into itself (running tenux open from inside a workspace terminal at its own target would just echo).Restarting
tenux restart [--worker-only]Restart the agent on this machine onto the installed version (after an upgrade, or if it stops responding). A background helper brings it back once the old one has stopped cleanly — no admin rights, no tenux start. Open terminal sessions end; the workspace reconnects on its own. --worker-only restarts just the agent process, leaving its supervisor up.The AI's own browser
tenux browser resetWhen your workspace's Browser tab isn't open, the AI checks your dev servers in its own headless browser — a separate session on your machine, localhost only, whose logins persist between runs. tenux browser reset wipes that profile; the AI starts logged out next time.Cross-device — a shell on your other machine
tenux ssh <device-id> [--p2p] [--relay] [--debug]Open an interactive shell on another of your own machines. Both must be signed in to the same account, and the target must be running tenux start. Takes the target’s device id — run tenux status on that machine to read it. The first request per device pair waits for your approval; after that the pair is remembered until you revoke it. By default the connection races a direct peer-to-peer attempt against the relay and bridges whichever answers first — the printed transport: p2p or transport: relay line tells you which one you got. Pass --p2p to require the direct path (fails rather than falling back to the relay), --relay to skip the direct attempt entirely, or --debug to print the connection steps to stderr.While a request is waiting, the CLI prints an awaiting-approval line and keeps polling. Approve it from the Tenux dashboard under Devices → Access requests, or from any open workspace — a request stays answerable for 15 minutes. Approving asks you to type the target device’s name, and it can only be done from a signed-in browser session: an AI with a shell on either machine cannot approve its own access.
The session shows up as a tab in the target’s workspace. That is deliberate — you can watch it from your phone, type into it, or close the tab to kill it. Type ~. at the start of a line to disconnect from your end, the same escape OpenSSH uses. Revoking the pair from the dashboard drops every live session within seconds.
Voice — on-device speech models
Tenux voice mode runs speech-to-text and text-to-speech entirely on this machine — the models below do the work, and no audio is ever stored on Tenux’s servers. Where the audio travels depends on your connection: on a direct peer-to-peer link it never touches Tenux infrastructure at all, and when your phone has to fall back to the relay, voice travels through it in memory exactly as your terminal keystrokes already do. These two commands manage the local install from the terminal.
tenux voice installs the speech models and reports on them; there is nothing to talk to yet.tenux voice install [--model <tier>]Downloads a pinned speech runtime and the speech models into ~/.tenux/voice — an opt-in download, separate from the CLI itself, which ships zero speech bytes. The default tier pulls ~830 MB (a ~482 MB speech-to-text model, CC-BY-4.0 and attribution-required, plus a ~349 MB text-to-speech model, Apache-2.0) and prints each model’s license before its first byte downloads. The text-to-speech archive also includes eSpeak NG data, licensed GPL-3.0. The models are downloaded from the k2-fsa/sherpa-onnx releases and the runtime from npm (sherpa-onnx-node), which is also built with eSpeak NG; Tenux hosts neither. Pass --model tiny or --model multilingual to name a different tier — only default ships pinned models in this build, so the other two currently refuse instead of guessing. Safe to re-run: it skips whatever is already installed.tenux voice statusShows whether voice is installed, which voice is currently selected (a stock voice or a saved custom blend) and at what speed, and where the models live on disk. Prints a reminder to run tenux voice install when it isn’t installed yet.Android — the local emulator
Android mode runs a real Android emulator on this computer and shows it in your workspace. These two commands get it installed and tell you what is missing.
tenux android setup [--yes]Checks what is already here (Java 17+, Google’s Android command-line tools, platform-tools, the emulator, an Android 15 system image, a tenux-pixel Pixel 7 virtual device, hardware acceleration and free disk space), shows the download size (about 2.4 GB on a fresh machine) and asks before downloading. Everything comes from Google’s own servers and the command-line tools are checked against a pinned SHA-256. You read and accept Google’s Android SDK license yourself — --yes only skips the size question. Safe to re-run: it only installs what is still missing. If acceleration is off it prints the exact fix (on Windows, turning on Windows Hypervisor Platform, which needs a restart) instead of running it for you.tenux android statusPrints the same checklist without installing anything, and whether the running agent will find a virtual device.winget install EclipseAdoptium.Temurin.21.JDK); Android Studio’s bundled Java is found automatically.Bring any AI into your workspace
Your running Tenux agent exposes its workspace — every terminal tab, the workspace file API, and the localhost preview — as an MCP server. Any MCP-capable AI you run on that machine can use it, not just Tenux Chat.
The server name is tenux, so its tools show up under an mcp__tenux__ prefix (e.g. mcp__tenux__terminal_read). Ask the client to list them for the current set — the surface is owned by the agent, not by this page.
The short version
tenux mcp is the server — a stdio bridge to whatever agent is running on this machine. Any stdio MCP client registers it the same way: point it at the command tenux with the single argument mcp. The snippets below are that one fact, spelled out in each client’s own config format — with the agent running (tenux start) first.
Claude Code
claude mcp add tenux -- tenux mcpCodex CLI
Add a [mcp_servers.tenux] table to ~/.codex/config.toml:
[mcp_servers.tenux]
command = "tenux"
args = ["mcp"]Cursor
Add to .cursor/mcp.json (project-local) or your global Cursor MCP config:
{
"mcpServers": {
"tenux": {
"command": "tenux",
"args": ["mcp"]
}
}
}VS Code (Copilot)
Add to .vscode/mcp.json — VS Code’s top-level key is servers, not mcpServers:
{
"servers": {
"tenux": {
"command": "tenux",
"args": ["mcp"]
}
}
}Gemini CLI
Add to settings.json (project .gemini/ or user-level):
{
"mcpServers": {
"tenux": {
"command": "tenux",
"args": ["mcp"]
}
}
}Any other stdio client
The pattern above is universal: any stdio MCP client runs the command tenux mcp — the command is the server, so there is nothing else to configure.
Streamable HTTP clients
A client that speaks Streamable HTTP directly, instead of stdio, can skip the command entirely and point at the endpoint:
tenux mcp --print-url # → http://127.0.0.1:8765/mcpThat prints the URL only. Those clients must send the workspace Bearer token themselves; tenux mcp never prints it.
Approving a client
The first time a client actually attaches, your Tenux workspace asks:
Until you answer, the client can list the tools but every tool call comes back telling it to ask you to approve. “Always allow” is remembered per client in ~/.tenux/mcp-consent.json; “Allow once” and “Deny” last only for that session. A small chip appears in the workspace while a client is attached.
What you are granting
Registering this MCP gives that AI eyes and hands on every workspace terminal plus the localhost preview and the workspace file API. That is the same trust class as giving it a shell — which, if it is running inside a Tenux terminal, you already did — but it widens the blast radius from its own tab to all of them.
If this machine runs an Android emulator that Tenux manages, the AI also gets its screen and its touch/keyboard input — including any app you are signed in to on it.
What it does not get:
Anything on the network. The endpoint binds
127.0.0.1 (on a Tenux cloud VM, the VM’s own single-tenant interface) and sits behind the same Bearer gate as every other agent route.Your other devices. v1 is per-device; driving a sibling device from one AI session is a later addition.
Only terminal_create may open a shell — a read/type/wait against a terminal that doesn’t exist returns an error instead of quietly spawning one.
Claude connector — the off switch
If you connected this computer to the Claude app as a custom connector, these commands turn that access off and on instantly, on this computer. Your own workspace and local MCP clients are not affected.
tenux connector offRefuses every Claude connector request from now on — reading and messaging alike — and closes any connector session that is open. Takes effect on the next request; no restart.tenux connector onLets the connectors you approved reach this computer again.tenux connector statusShows whether connector access is on. If the switch file (~/.tenux/connector-local.json) is ever damaged, access stays off until you run on or off again.Handing a secret to your agent
When an agent needs a key only you hold (a bot token, an API key), it sends you a link to a page in your Tenux workspace and a short verification phrase. Open the link, sign in, check the phrase, and paste. The value goes straight to your computer, into ~/.tenux/secrets.local.json or the file the agent named. It is never stored on Tenux servers, emailed, or shown back to you. Each link works once and expires (15 minutes by default, at most an hour).
The file gets owner-only permissions on macOS and Linux; on Windows it inherits your user folder’s permissions.
Questions?
Email [email protected].