Install
curl -fsSL https://exponential.at/install.sh | shSelf-hosting? Same script, with your instance in EXP_INSTANCE:
curl -fsSL https://exponential.at/install.sh | EXP_INSTANCE=https://issues.example.com shBuilds are published for Linux (x86_64 and arm64) and macOS (Apple Silicon). The script verifies the binary's checksum, installs it to ~/.local/bin/exponential, and then sets the machine up in one go: it turns on automatic updates, signs you in, installs the daemon as a service that starts at boot, and ends with a summary of the account, the device name, the daemon and auto-update. Without a terminal (cloud-init, a provisioning script) it still signs in: it prints the device code and waits until you approve it in a browser.
The web app's Add device dialog gives you the same command with a one-time install token in it, which signs in with no approval step:
curl -fsSL https://exponential.at/install.sh | EXP_INSTANCE=https://issues.example.com EXP_INSTALL_TOKEN=expi_... shOpt out of any step with EXP_NO_DAEMON=1 or EXP_NO_AUTOUPDATE=1, sign in with an existing API key through EXP_TOKEN, and name the machine with EXP_DEVICE_LABEL.
You also need git, plus at least one agent CLI — Claude Code or Codex — for coding sessions. See Coding agents for what each one supports. The installer only warns about missing tools; exponential doctor is the one that checks them properly.
export PATH="$HOME/.local/bin:$PATH" in your shell profile, or set EXP_INSTALL_DIR to install somewhere else.Sign in
exponential loginThis is a device code flow (RFC 8628). The CLI prints a short code and a URL — <instance>/auth/device — you open it in any browser where you're already signed in, type the code, and approve. The terminal picks up the session by itself.
Nothing has to be typed into the machine you're installing on, so this works the same over SSH on a headless server as it does locally, and it works for password and SSO accounts alike. Confirm with exponential whoami.
Non-interactive setups
For provisioning scripts, skip the browser: generate an API key under Settings → Security in the web app and hand it to the CLI as EXP_TOKEN:
EXP_INSTANCE=https://issues.example.com EXP_TOKEN=expu_... exponential loginOr redeem an install token from the Add device dialog. It works once and expires after 15 minutes:
exponential login --install-token expi_...Signing in does not make the machine a device. Only the daemon does that: until it runs, the machine is not listed on your other clients and nothing can be started on it remotely. exponential status tells you which it is.
Commands
exponential login [--instance <url>] [--install-token <t>] [--no-browser]: Sign in to an instance and store the session locally. --install-token redeems a one-time token from the web's Add device dialog; --no-browser only prints the device code.exponential logout: Sign out and drop the local credentials.exponential whoami: Show the signed-in account and its instance.exponential status: Account, this machine's device row, daemon state, auto-update, installed agents, and git in one summary. With no daemon running it says so plainly: the machine is not a device yet.exponential doctor: Check git and the agent CLIs, and say what's missing.exponential code <ISSUE> [--device <label|id>] [--agent claude|codex] [--model <m>] [--effort <e>] [--plan] [--detach]: Start a coding session for an issue, by identifier ("EXP-42") or id. --device starts it on another of your devices instead.exponential run <action> [--device <label|id>] [--team <id>] [--input k=v ...] [--prompt <text>] [--agent <a>] [--model <m>] [--effort <e>] [--plan] [--detach]: Run a team action by name or id, or a builtin (chat, fix-conflicts, create-action). --prompt adds instructions, and is the whole request for chat and create-action. The same agent flags apply.exponential devices [--team <id>]: Your devices (desktop apps and daemons), online or not, with their agents and running sessions. --team adds the servers teammates shared with that team.exponential sessions [--device <d>] [--status running|in_review|ended] [--all] [--limit n]: Coding sessions, newest first: yours, or your teams' with --all.exponential sessions show | log [--follow] | message | kill <id>: One session's details and screenshots, its transcript, a message to its agent, or stop it. An id prefix is enough.exponential mcp list | login <server> [--paste] | set-secret <server> <NAME> | status: The team's MCP servers and the credentials THIS machine holds for them. Values never travel through argv: login runs the OAuth flow locally (or --paste for a machine with no browser), set-secret reads from a no-echo prompt.exponential daemon [--foreground] [--label <name>]: Run the remote-start daemon in this terminal.exponential daemon install | uninstall | status: Manage the systemd user unit (Linux) or launchd agent (macOS).exponential update [--auto on|off]: Self-update from the latest CLI release, or switch automatic updates on or off.exponential uninstall [--yes]: Remove the daemon service and delete the binary. Signed-in accounts are kept — the data dir is shared with the desktop app.exponential version: Print the CLI version.
code and run take the same agent options as the Agent page composer, and fall back to your saved per-agent defaults when you omit them. --plan works on both agents; every run bypasses the agent's permission prompts. See Coding agents.
Run code with a terminal attached and the session prints there as a line transcript — the same narration, tool calls and questions the app shows — and whatever you type is sent to the agent as a message. Without a terminal (in CI, over a pipe) or with --detach, the session runs headless and stays fully steerable from the web, so you can close the laptop and keep watching it from your phone.
exponential code EXP-42 --agent claude --plan
exponential run "Update the changelog" --prompt "version 1.4.0"
exponential run fix-conflicts --input pr=EXP-42Either way it's a real coding session: a worktree on an exp/<IDENTIFIER> branch, the MCP wiring, the agent opening its own pull request, and the issue moving to In Review when it does.
Other devices
The CLI can drive every device you own, not just the one it's on. exponential devices lists them with their online state, agents and running sessions. Add --device to code or run and the run starts on that machine, the way the Agent page starts it. Agent options you leave out come from that machine's own launch defaults:
exponential devices
exponential code EXP-42 --device "build box" --agent claude --follow
exponential run chat --device "build box" --prompt "Why is CI red on master?"
exponential sessions --status running
exponential sessions log 1a2b3c4d --follow
exponential sessions message 1a2b3c4d "Use the staging database instead"
exponential sessions kill 1a2b3c4dA device is picked by its name or id. A start aimed at an offline device is refused. --account picks an agent account on the target. Transcripts live only on the device that ran the session, so sessions log streams them through the steer relay like the app does. That needs the device online, and a live session shows its transcript only to its owner.
Run as a daemon
The daemon turns a machine into a permanent home for agent work — a spare workstation, a VPS, the build box under the desk:
exponential daemon installOn Linux that writes a systemd user unit (exponential-daemon) and enables it; on macOS it writes a launchd agent that starts at login. exponential daemon status tells you whether it's up, and daemon uninstall removes the service again. Name the machine with --label if the hostname isn't what your team would recognise.
daemon install turns it on when your account is allowed to. When it isn't, it prints the one command to run: sudo loginctl enable-linger $USER.The machine then shows up under Devices → My devices in the web app, with its online state and the agents it has installed. Start a coding session or an action there and pick that machine, and it runs on it exactly like it would on the desktop app: the same launcher, the same live activity feed, the same steering from web, iOS, or Android. Batch runs, chat runs, triggers and the built-in Fix merge conflicts action work too.
A run you start on the daemon makes no report, exactly like a run in the desktop app or an attached CLI: when the agent finishes its turn it waits for your next reply, and the daemon keeps its process and worktree alive with no idle timeout. Hit Stop on the run in the web or mobile app when you are done with it. Runs started by a trigger are the ones that end themselves when their work is done.
Sessions belong to you, not to the box — the agent runs under your account, with your own agent subscription and your own GitHub access. A machine with no agent CLI installed registers as offline until you install one; the daemon notices without a restart. A start aimed at a machine that is offline is refused on the spot rather than queued.
Running it from a phone
Everything you would set at the desk is on the machine's row and in its Device settings, from any client:
- Its Name, whether it is your Default device (preselected in every picker, marked with a star in the list), and which team it is Shared with — teammates can then start runs on it. Withdrawing the share ends their running sessions.
- Its launch defaults: Default agent, and per agent the Model, effort, Ultracode and Plan mode a run starts with.
- Each agent's account and rate-limit usage. Login / Switch account runs the agent's own sign-in on the machine and hands you back the code and link as an answerable card, so a headless box never needs a browser on it.
- Its Worktrees, with Prune merged worktrees and Remove worktree; both are queued and run when the machine is next online.
Updating
exponential updateIt checks the latest CLI release, verifies the download against the release checksums, and replaces the running binary in place. It also restarts an idle service-managed daemon onto the new build. If your instance has stopped supporting the version you're on, every command says so and points here — and a daemon that gets locked out this way updates itself right away rather than waiting for its next scheduled check.
You rarely need it, though: the install script turns automatic updates on (EXP_NO_AUTOUPDATE=1 leaves them off), and a CLI installed some other way asks on its first run. exponential update --auto on or --auto off changes it later. With auto-update on, commands check once a day and restart themselves on the new build, and the daemon updates on its own schedule, waiting until no session is running before it restarts. Each machine's row on the Devices page also shows its version with an Update button that asks the daemon to update right away — while sessions are still running the row reads "Queued" and the update applies as soon as the last one closes. The stored choice is cliAutoUpdate in settings.json.
Release notes for the CLI and everything else live on GitHub Releases.