Get started
Install a coding CLI
The Termdeck agent is a relay. It does not bring a coding agent with it, so every machine needs at least one of Claude Code, Codex, or Grok installed and signed in. You can install all three and pick per chat.
Setting this up for the first time? Use Claude Code and Codex in one UI walks through it in order, start to finish.
Why these are separate installs
Termdeck drives the official CLI, unmodified, under your own subscription. That is what keeps your local repository, environment variables, credentials, MCP servers, and model access working exactly as they do in a terminal. It also means Termdeck never sees your provider password: each CLI stores its own credentials in its own config directory, and Termdeck reads the state rather than the secret.
Installing from Termdeck
A CLI that is missing from a machine can be installed without going to that machine. Open Settings, then Machines & accounts, open the machine, and press Install on the CLI's row. The machine runs the same npm install -g line shown below, with the npm that came with its own Node.js, and the row turns ready when it finishes. Then sign in from the same row. If the machine's global npm folder is not writable, the CLI goes into ~/.local instead, where Termdeck finds it. You can still run the command yourself in a terminal; both end up in the same place.
Claude Code
npm install -g @anthropic-ai/claude-code
claude
Anthropic's recommended installer works too, and Termdeck finds what it installs: curl -fsSL https://claude.ai/install.sh | bash on macOS, Linux, and WSL, or irm https://claude.ai/install.ps1 | iex in Windows PowerShell. It updates itself in the background. The npm package needs Node.js 22 or later.
Running claude once starts the login flow. Sign in with the Anthropic account whose plan you want the turns billed against.
- Sessions on disk:
~/.claude/projects/<project slug>/<session id>.jsonl - Resume in a terminal:
claude --resume - Config directory:
~/.claude, or whereverCLAUDE_CONFIG_DIRpoints
Claude is the engine with the deepest Termdeck integration: live permission prompts, sub agent status, checkpoint restore and MCP server state all come from Claude's own stream. Slash commands come from two places. The CLI names them, and Termdeck reads their descriptions and argument hints off disk, including any your project defines.
Claude in Chrome follows the machine's own setting. If you turned on "Enabled by default" with /chrome in a terminal on that machine, every Claude chat you start from Termdeck gets the browser tools too, and browser actions still ask for approval like any other tool. To keep it off for Termdeck chats only, set CLAUDE_CODE_ENABLE_CFC=0 in the agent's environment.
OpenAI Codex
npm install -g @openai/codex
codex login
- Sessions on disk: rollout files under
$CODEX_HOME/sessions - Resume in a terminal:
codex resume - Config directory:
$CODEX_HOME, defaulting to~/.codex
Codex has native plan mode, and Termdeck exposes it in the same picker as the other engines. The slash palette lists the skills installed for a Codex chat with their descriptions, but Codex has no slash commands of its own. Picking one writes it into the composer as text for the model to act on, rather than running a command. /compact sent on its own is the exception: it compacts the chat.
When Codex asks you something, the question opens as a card with its choices, exactly like a Claude Code question, and it notifies you as a question rather than an approval. Outside plan mode Codex treats its questions as optional: it waits for you, and Don't answer lets it carry on with its own best guess. Reading the chat back, the question shows the choice you picked, or not answered.
Codex can also ask a question and keep working. That question appears in the chat as a Codex asked card, and it notifies you as a question too. Click one of its choices, or type an answer and press Send. If Codex is still working, your answer goes into the running turn; if it has finished, the answer starts a new one. Each question on the card is answered separately, and the card shows the answer once Codex has it. Until then Codex works from its own best guess, so answer early if the choice matters.
xAI Grok
npm install -g @xai-official/grok
grok login
- Sessions on disk: Grok's own session files, shared with the terminal
- Protocol: Agent Client Protocol, driven through
grok agent stdio
This is xAI's own Grok CLI. A different program, @vibe-kit/grok-cli, also installs a grok command but cannot run Termdeck chats; a machine that has it shows Grok as not installed, and Install on its card removes it and installs xAI's. By hand: npm uninstall -g @vibe-kit/grok-cli, then the command above.
Use grok login so turns run against your SuperGrok subscription. Grok has no plan mode of its own, so Termdeck's Plan option behaves as read only there and the interface says so under the picker.
How Termdeck finds a CLI
The agent asks the operating system the same question your shell asks: where on Windows, command -v on macOS and Linux. Anything on the path counts as installed, which matches what happens when you type the command yourself.
The agent also looks in the folder its own Node.js lives in and in the usual npm install folders (Homebrew's on a Mac, %APPDATA%\npm on Windows). That matters on a Mac, where the agent starts in the background with a short path that leaves those folders out.
A CLI installed after the machine connected is picked up without restarting anything. Press Recheck on the machine and it shows as installed; starting a chat on that engine finds it too.
If a binary lives somewhere unusual, name it explicitly in the agent's environment:
| Variable | Points at |
|---|---|
TERMDECK_CLAUDE_EXE | The Claude Code executable |
TERMDECK_CODEX_EXE | The Codex executable |
TERMDECK_GROK_EXE | The Grok executable |
Add them to ~/.termdeck/agent.env and restart the agent. Note that a background service does not inherit your login shell's environment, so a CLI that only works after your shell profile runs is exactly the case these variables exist for.
A machine can hold more than one copy of the same CLI, for example an npm global and a package manager install both on the path. When that happens, Termdeck and your shell can disagree about which one is the binary, which shows up as a sign in that appears to hang. Removing the copy you do not want, or naming the right one with the variables above, resolves it.
Confirming a CLI is signed in
Open Settings, then Machines & accounts. Click a machine's row; its page lists the three engines under Coding agents, each in one of five states:
| State | Meaning | What to do |
|---|---|---|
| Ready | Installed and holding a usable login. | Nothing. It can run turns. |
| Sign in needed | Installed, no usable login. Turns will not start. | Run the engine's login command on the machine. |
| Sign in expired | A login is saved, but the machine tried it and the provider refused it. Turns will not start. | Run claude on the machine once to refresh it, or switch to another saved account under Accounts on the machine's page. |
| Not installed | The binary is not on the path. | Install it, or point at it with an executable variable. |
| Couldn’t verify | The machine did not answer. | Nothing is broken by this alone. It is never treated as signed out. |
A machine you have just connected shows the same states in the last step of the connect wizard, with the fix next to each one: the install command to copy for Not installed, a Sign in button for Sign in needed or Sign in expired (Claude Code and Codex; Grok shows its login command to run on the machine). The wizard checks again every few seconds until one engine is ready, so a CLI you install in a terminal shows up there without a refresh.
The distinction in the last row matters more than it looks. "We could not tell" and "it is fine" are the two answers a diagnostic must never confuse, so Termdeck reports the uncertainty rather than guessing in either direction.
Ready and Sign in expired are two different readings of the same row, and the difference is who was asked. Ready means a login is saved on the machine. Sign in expired means the machine went and used it and the provider said no, which is the answer that counts. Termdeck only says expired when the machine established that itself, so a request that merely timed out is never reported as a login problem.
Where the engines differ
Termdeck uses one vocabulary across all three so switching engine mid project does not rename every control under you. The mapping is honest about the places where an engine behaves differently, and the interface prints the caveat under the picker.
| Capability | Claude Code | Codex | Grok |
|---|---|---|---|
| Live tool approvals | Yes | Yes | Yes |
| Image attachments | Yes | Yes | No, its protocol takes no images |
| File attachments | Text, data, source, PDF, notebooks | Text, data, source, notebooks | Text, data, source, notebooks |
| Plan mode | Native | Native | Behaves as read only |
| Accept edits mode | Yes | Not offered | Yes |
| Slash commands from the composer | Yes | No | Yes |
| Output of a running command | As it prints (one command at a time) | As it prints | When it returns |
| Checkpoint restore | Yes | No | No |
| Sub agent status strip | Yes | Rows in the transcript | No |
| Saved account switching | Yes | Yes | Use the CLI |
| Terminal resume | Yes | Yes | Yes |
Permission mode names and their per engine behaviour are covered in full on Approvals and permissions.
The model picker differs the same way. What a row can show is whatever that engine's own catalog publishes, so the same picker carries more detail for one engine than for another. Nothing is held back to the levels Termdeck already knew about either: a model released after your last update arrives with whatever thinking levels it ships with.
For Codex, the default thinking level is the one your Codex config sets. If ~/.codex/config.toml has a model_reasoning_effort line, a chat left on the default runs at that level, and the picker names it. Pick a level in the picker to override it for one chat. Whatever level you pick is the one the chat runs at, including the one marked Default: picking it pins that level even if your config changes later.
Running more than one at once
Nothing stops you from having a Claude chat, a Codex chat, and a Grok chat running at the same time, on the same machine or on different ones. They are separate processes with separate transcripts. A common split is a premium subscription on the hard problems and a cheaper engine on the routine work, with the usage dashboard showing whether the split is paying off.
Two agents writing the same transcript would fork it, so Termdeck never does that. If a session is attached to another process, for example a terminal running the CLI on the same chat, the composer stays locked and the browser follows along read only until the terminal lets go.