Core concepts
Chats and sessions
A chat in Termdeck is a session belonging to one of your coding CLIs. The browser and the terminal are two windows onto the same thing, which shapes almost everything on this page.
Setting this up for the first time? Continue a Claude Code session on another computer walks through it in order, start to finish.
Starting a chat
Choose New chat and pick three things: the machine, the folder, and the engine. The folder is the working directory the agent runs in, so it decides which repository the agent can see, which environment it inherits, and which project context files it reads.
The folder picker browses the real filesystem on the machine you selected, so you can point at a directory that has never had a chat in it. Model, thinking level, and permission mode default to what you set in Settings, then General, and can be changed per chat afterwards. The thinking level the page shows is the one your first message is sent with, and the chat keeps showing and using it.
You can type your message before you pick a folder. If you press Send with no folder chosen, the folder menu opens and your message waits; it sends as soon as you pick one. Changing the folder, machine or engine keeps what you typed. If the folder is set and the box is empty, the page asks for a first message or an attachment.
On a machine with no projects yet, the folder menu suggests where to start under Suggested: folders the machine already has chats in, or, when your home folder holds just one folder of your own, that folder. Click one to use it. Browse folders opens with that folder highlighted, so Choose folder takes it.
On the New chat page the message box sits in the middle, with the model, thinking level, permission mode and Plan switch along its bottom edge. Under it is a row showing where the chat will run: the machine (a green dot means it is connected), the folder, and the checkout. Click any of them to change it. Until you pick a machine yourself, the page starts on the machine of your most recent chat, with the last folder you used there. Starter buttons such as Explain this codebase or Fix a bug fill in the box for you to finish, and when the folder already has chats, the most recent three are listed underneath so you can pick one up instead of starting over.
The options follow what the engine and model you picked can do. Thinking levels appear only for a model that has them, New worktree is offered only on Claude, and a choice the new engine cannot honour is cleared when you switch. A checkout you already picked from Checkout stays picked, since every engine can run in one. On a phone the box sits at the bottom of the screen, the rows above it scroll sideways, and every picker opens as a sheet from the bottom edge.
You can also start a chat inside a pane on the Terminals page: click +, choose the machine, folder and agent on the welcome banner, and type the first message. It is the same chat as one started here, and it appears in the sidebar the same way.
To start over from a chat you are in, type /clear and press Enter. The chat stops if it was working and is archived, so it leaves the sidebar, and a new chat opens in the same folder on the same machine with the same agent, model and thinking level. Change any of them before your first message. Unarchive the old chat to bring it back. In a view-only chat the old chat is left as it is.
When the machine you picked cannot run a chat at all, the page says why above the box and holds the send button. That covers a machine that is offline, one with no CLI installed, one that was never signed in, and one whose saved login the provider has since refused. Each of those ends with a link into Machines and accounts, opened on the machine in question.
Point a chat at the smallest folder that contains the work. It bounds what the agent can reach, it makes the risk scoring on approvals sharper, and it keeps the diff view focused.
Titles and organisation
Chats title themselves from the first prompt. Rename any chat from its row menu; the new name is yours and does not get overwritten.
- Pin puts a chat in the tab strip along the top.
- Archive moves it to the Archive page. Nothing is deleted and it can come back.
- Hide takes it out of the list without archiving, for chats you want to stop seeing.
In Settings, then Chats you can auto archive anything untouched for 7, 30, or 90 days, and choose whether chats started in a terminal appear alongside the ones you started here.
Working across the browser and the terminal
Because both read and write the same session files, a chat can move between them freely.
- Start in a terminal, walk away, and the chat is already in your sidebar. Continue it in the browser.
- Start in the browser and later resume it locally with
claude --resumeorcodex resume. - Read a chat on your phone that is running on a machine you are not sitting at.
View-only mode
The one rule is simple: two writers on one transcript would fork it, so Termdeck prevents a second writer. If a session is attached to another process, usually a terminal running the CLI on the same chat, the composer locks and the chat becomes read only in the browser. You still see everything as it happens, and the composer unlocks when the other process lets go. A Claude Code process that Termdeck started never locks you out of your own chat, even after the server restarts or the connection to your machine drops for a moment.
While Codex is answering, the status reads Working in Codex CLI. Between turns it reads Controlled by Codex CLI until that CLI closes the chat, instead of calling a still controlled chat idle.
If you want to send a prompt immediately, the lock names what controls the chat and offers the appropriate takeover:
- Take over closes an idle terminal client. The terminal can reclaim the session later by resuming it.
- Force take over reaches any other holder, busy or idle, such as a desktop client, editor chat, scripted
claude -p, or another Termdeck. Termdeck asks it to exit and kills it if necessary, so a running turn is interrupted and anything not written to disk is lost. - Take over anyway is the last resort when there is no process to signal or a force attempt did not land. Nothing is closed. Termdeck stops enforcing the lock, which means the other client may still write and fork the transcript. Termdeck asks you to confirm this risk.
For Codex, Termdeck checks the writer lock held by the local Codex process. A completed turn stops the working indicator, but the chat stays controlled and read only while that process keeps the thread open. Grok still uses recent transcript activity and unlocks once it goes quiet.
A Codex sub-agent working for another chat cannot be taken over. Codex refuses direct input to that thread, so reply in the chat that spawned it.
Codex can also report that a thread already has an active writer when a send races with another client. Termdeck treats that refusal as exact control evidence and locks the chat immediately. The refusal proves control, not that a turn is currently generating. The chat unlocks when the holder releases the thread.
Starting a fresh chat in the same folder is often the clearest option when the other session is somebody else's work.
The same chat on two devices
Open one chat on your laptop and your phone and both are you, so neither is locked out the way another program would be. What changes is that each one now says the other is there. A row in the tray above the message box reads Also open on iPhone, and it goes away when you close that tab.
One device drives at a time, and it is whichever opened the chat first. The other shows the chat live with the composer locked and a Take over button. Pressing it moves the driving seat to the device you are holding and locks the first one, which then says who took it. Nothing is closed and nothing is lost, so you can pass a chat back and forth as often as you like.
Close the driving tab, or let that laptop sleep, and the chat hands itself to whatever is still open. No reload and no button press. If you had three devices on it, the one that opened the chat earliest gets it.
A terminal on the machine still wins over any of this. When a process is holding the chat, that is what the lock describes and Take over acts on it, because a program on the machine is the one holder you cannot reach from the device in your hand.
While a turn is running
The composer's round send button becomes Stop, drawn as a square, whenever the message box is empty. Stopping asks the engine to end the turn cleanly; what it has already written to disk stays written. The line above the message box reads stopping… from the moment you press it until the turn has ended, which can take a few seconds while the agent finishes the step it is on. A turn whose work was already done when you pressed Stop is recorded as finished, not as stopped. A command the turn was running when you stopped it, a build, a test run or a dev server, is stopped with it, on every engine.
A stopped turn shows a small Stopped line where it ended, with its cost and time under the prompt you stopped, and any tool call it cut off reads interrupted with how long it ran. The same happens to a turn whose process goes away mid-call, for example after Force take over, and the call reads the same when you open the chat again later.
Closing the tab does not stop the run. Neither does losing your connection, putting the laptop to sleep, or a Termdeck release. The agent keeps the process alive across a dead link and replays what you missed when you come back. A run only ends when it finishes, when you stop it, or when nobody reconnects for several minutes.
With a chat open, Termdeck downloads that chat and nothing else. Other chats show their status in the sidebar, and each one catches up on what it missed when you open it, so a busy chat elsewhere costs no bandwidth while you read this one. Pointing at a sidebar row does not load it either; clicking does.
From Home, where you have not picked a chat yet, every chat you have opened or previewed keeps catching up as it changes, pinned and running ones first, and pointing at a card loads it ahead of the click, so the one you open shows where things got to instead of a fresh load. Switching to another browser tab does not stop that. Once the tab is in the background it keeps only your pinned chats and the ones running now current. Browsers do slow a background tab down, and some pause one that has been alone for several minutes, so a tab left for a long time catches up in one step on your return rather than staying current the whole time.
Queueing follow up turns
Send while a turn is running and the message is queued rather than rejected. Queued turns run in order as the current one finishes, so you can line up three follow ups and leave. The queue survives a server restart and holds up to 20 messages per chat.
On engines that support steering, a queued message can be delivered into the running turn instead of waiting for the next one. Type during a run and a second button appears beside Send, labelled Steer where the engine can take the message now and Queue where it cannot, so the behaviour is never a surprise.
A steered message shows in the tray above the message box the moment you send it, marked as sent, and moves into the chat when the agent takes it up. On Claude that is after whatever step it is on, which can take a few seconds, so there is no need to send it again. If you stop the turn before the agent has taken the message up, the turn ends at once, the agent never runs that message, and it goes back into the message box so you can send it again.
On Claude, a message sent while sub-agents are running is queued rather than delivered at once, because delivering it would cancel them and throw their work away. It shows in the tray above the message box as queued, with discard beside it, and runs as soon as the turn finishes.
Per turn spend ceiling
A turn can be given a maximum spend. The engine enforces it itself and ends the turn when the ceiling is reached, which is the only way a ceiling is actually a ceiling. Checking between operations always overshoots.
This is a safety rail you set for yourself against a runaway agent, not a plan limit. The tokens are yours, billed to Anthropic, OpenAI, or xAI under your own subscription, and Termdeck has no interest in rationing them. Machine operators can also set a hard ceiling with TERMDECK_MAX_BUDGET_USD, and the smaller of the two always wins.
Images and files
Attach files from the composer with the paperclip, drag them onto the message box, or paste a screenshot straight into it. This is the fastest way to hand an agent a failing UI, a spec, a CSV of results, or a design.
A file goes to the machine the chat runs on, not to Termdeck. It is saved under ~/.termdeck/uploads there and the agent is given the path, so the CLI opens it with its own file tools, the same way it opens anything else in your project. Termdeck never reads what is inside it. Images are the one exception: they ride in the message itself so the model can see the picture without opening anything.
In the chat, your message shows the words you typed with a chip for each attached file, and a thumbnail for each image. Hover a file chip to see where it was saved on the machine.
Uploads are inputs to a turn, not storage. Anything in that folder that has not been touched for a week is deleted the next time you attach something on that machine. Nothing is ever written into your project folder, so an attachment never shows up in git status.
What you can attach
Each engine is offered what it can actually read, so the file picker in a Grok chat does not list file types Grok would have to refuse.
| File | Claude | Codex | Grok |
|---|---|---|---|
| Images: PNG, JPEG, GIF, WebP | Yes | Yes | No |
| Yes | No | No | |
| Notebooks: .ipynb | Yes | Yes | Yes |
| Text and data: md, txt, csv, tsv, json, yaml, toml, xml, log, diff | Yes | Yes | Yes |
| Source: html, css, js, ts, py, go, rs, java, sql and the rest | Yes | Yes | Yes |
Images are capped at 5 MB each and everything else at 10 MB, with ten attachments to a message. Archives, executables and scripts (.zip, .exe, .dll, .sh, .bat, .ps1) are not uploadable: no engine reads an archive on its own, and the rest have no business being written to your machine by a web app. To get a folder of files to an agent, put it in the project and ask.
A file has to finish uploading before the message can be sent. Its tile in the tray above the message box shimmers while it uploads, and turns red and reads FAIL if the upload did not make it; remove it with the cross on its corner and attach it again. Switching the chat to another engine or another machine drops the attachments the new one cannot use, and says which. On Codex, images attached to a new chat or to a queued send are not yet carried through.
When an agent's reply includes an image from a web address, the chat shows a link to it rather than the picture. Click the link to open the image in a new tab. Images from your project folder still show inline.
Pointing at a file with @
To name a file that is already in the project, type @ in the message box, the same as in the CLI. A list of the project folder opens under the caret. Keep typing to filter it, press the arrow keys to move, and press Enter or Tab to take a row. Taking a folder adds its / and lists what is inside it, so @src/ then comp narrows to the files in src that match. Taking a file puts its path in the message, like @src/composer.js, and the agent reads it from your machine. Escape closes the list. It works on the New chat page too, over the folder the chat will start in, once that folder has had at least one chat. Hidden files such as .env only appear when you have turned them on for that project in Settings.
Once sent, each file you named shows in your message as a chip with the file's path. Click the chip to open the file in the files panel. A path outside the chat's folder still shows as a chip but does not open.
Managing the context window
The strip above the composer shows how much of the model's context window this chat is using, measured against the window the CLI itself reports rather than a hardcoded number. When it gets full, Compact asks the engine to summarise the conversation so far and continue with the shorter version, which is the same thing /compact does. Once it finishes, the strip drops to the new, smaller size straight away, and the chat shows /compact followed by the summary it produced. The summary starts folded; open it to read what the engine carried forward.
On a Codex chat, Compact and /compact sent on its own run Codex's own compaction rather than asking the model in words. The chat shows a compacting bar while it works, then a line marking the compaction. Sent while a turn is running, /compact waits for that turn to end. Codex also compacts on its own when a turn runs out of room. A Codex chat marks each compaction with a line in the transcript at the point it happened, saying how large the context was going in.
Compacting is lossy by design. If a chat has drifted far from what you actually want, starting a fresh chat in the same folder is often better than compacting a long one.
The conversation, the code the agent reads, your attachments and every tool result share that one window, so a long transcript and a large pasted file compete for the same space, and a smaller window compacts sooner.
When a Claude or Codex chat has sat idle long enough for the engine's prompt cache to expire, a note above the composer says so, and a Terminals pane says so on the line under its prompt. Your next message then re-reads the whole conversation at the full input price instead of the cached one, so a fresh chat is usually cheaper. Claude keeps the cache for an hour on a subscription and five minutes on an API key; Codex keeps it for about 30 minutes. The note is worked out in your browser from the time of the last reply, so it costs nothing to show.
Claude's 1M context window
Every Claude model that can run on a 1M window runs on it, always. There is no 200k setting and nothing to switch: the model picker lists each of those models once, under its 1M name, and every turn Termdeck starts is launched on that name, including chats that were first started at 200k, chats started in a terminal, and chats left on default model.
Claude Code takes the window as part of the model's name, so the row you pick shows it: claude-opus-5[1m] rather than claude-opus-5. A chat on default model keeps the model it already ran on, and a brand new one starts on Opus. Your plan has to include Claude's 1M context for these models to run.
Models whose only window is 200k, such as Haiku 4.5, keep it: that is the model's limit rather than a setting, and Anthropic refuses a 1M request for them. Codex and Grok are unaffected.
Showing the agent's reasoning
Claude can write a summary of how it reasoned into each turn, one click down from the reply. The thinking control in the message box sets it for the open chat, Shown or Hidden. Hidden is not a display filter: the engine stops producing the text at all, so a turn that runs while it is off has no reasoning to go back for afterwards.
Each thought is a Thought line showing its title or first sentence. Click it to read the rest. A thought that is a single sentence is all on the line and does not open.
Settings, then General holds the default every Claude chat follows until it says otherwise. It is stored on your account rather than in the browser, so it reads the same on your laptop and your phone, and the thinking control badges whichever answer the account is on. A chat that has chosen for itself keeps its own answer.
Both take effect from the next turn. A turn already running keeps the setting it started with, whichever way you move the control while it runs, and turns already on disk keep what they recorded. That is the engine's behaviour rather than a Termdeck limit, measured against the CLI in both directions.
Codex and Grok have no equivalent thinking control. Codex chats request the provider's reasoning summaries on each turn, including chats started in Termdeck and chats resumed from another Codex client. When the provider supplies a summary, it appears in the chat's activity. Availability depends on the model and provider; private reasoning is not displayed. Older turns keep only the summaries their client originally recorded. Each part of a Codex summary is a thought of its own, labelled with the heading Codex gave it.
Recap
Recap, in a chat's own menu, produces a factual summary of what it did: how long it ran, how many turns, which files it touched, what commands it ran, and what it cost. It is derived from the transcript rather than generated by a model, so it costs nothing, is instant, and cannot be wrong about which files were edited. It deliberately does not attempt to say why, since that is the part a summary would have to invent.
Copying replies, code and output
Hover any reply, tool call, thought, or fenced code block and a copy button appears in its corner. An assistant reply's button takes the whole message; a fenced code block inside one has its own, so you don't have to pick it back out of the prose. A code block that names its language shows the language in its top left corner and is coloured the way the files panel colours that language. Open a tool call and its command and its result each get a copy button too, for taking a path, an error, or a build's output somewhere else. Open a thought and it reads like a reply, not like a command's output, with the same copy button on hover.
Replies, thoughts, and tool calls stay in the order the engine produced them. When a turn ends with a final answer after its tools, that answer appears below the tool activity.
A message shows the time it was sent when more than five minutes passed since the one before it. A prompt you sent sooner than that shows its time when you hover over it.
A run of tool calls sits under one header line that says what it did. It names the files when there are one or two, for example Edited style.css (2 edits), names the command when it ran just one, and counts the thoughts in the run. A run of a single call shows that call's row on its own, with no header over it, since the row already says what ran, how it ended and how long it took.
A tool call that failed stays in sight. Its row turns red and is never tucked behind the +N earlier line, and the run's header line adds how many failed, for example Ran 9 commands, 1 failed, with a red dot even when the run is folded. An edit that failed says not applied where its line counts would be, its diff is dimmed, and it does not count toward the files edited or the lines added and removed. When the engine refuses a call before it runs, the row shows the engine's reason in plain words.
A command or sub-agent the engine started in the background reads background on its row, with a still amber dot, instead of a check: starting it is not finishing it. When it ends, the row takes its outcome, a check, a red failure or a grey stop, and how long it ran. A failed one counts in the run's header line like any other failure.
A command row shows how long the command took, a quick one included, and a red exit N when it exited with an error. A search that finds nothing is not an error: its row says no matches. While a command runs, its row counts the seconds and the line above the message box keeps naming it until it returns. Edit rows show no time, because the engine writes the change before the edit runs.
A command that is still running shows its output under its row as it prints, the newest lines in view, so a long build or test run does not look frozen. Once it is longer than a dozen lines, Show all under it opens everything that has arrived so far. When the command ends, its full result takes the place of the live output. If you stop the turn while a command is running, the output it printed before the stop stays on its row. Very fast output may skip ahead to the newest lines, which the box says with Earlier output not shown.
When Codex checks back on a command that is still running, that check does not get a row of its own: the later output and the exit land on the command's row. When Codex looks at an image, its row shows a small copy of the picture. A row that starts a Codex sub-agent names the agent, and a wait names the agents it waited on and shows what they answered.
When the model's provider answers instead of the model, for an expired sign in, a usage limit, a model the account cannot use or a dropped connection, the chat shows a notice in place of a reply. It gives the engine's own sentence and the next step: sign in again, wait for the reset or switch account, pick another model, or send again to retry.
Opening a long chat
Coming back to a chat continues where you left off. If you had scrolled up to read something, the chat opens on that same line, whether you switched to another chat, reloaded the page, or opened it in another tab of the same browser. If you were at the bottom, it opens at the bottom, with anything new already there. Each chat remembers its own place, so opening a chat you have not read here never starts where some other chat left you. The same place is used in a Terminals pane showing that chat.
A chat with no place to go back to opens on its newest messages, back to the prompt that started the last turn when that turn is short. When the last turn ran long, tens of tool calls deep, the chat opens on the tail of it and a Show the whole turn control sits above the first message, saying how many earlier messages belong to that turn. One tap brings them in above what you are reading, without moving it. Above that, Load earlier messages pages further back, and scrolling up does the same on its own. A chat shows at most its most recent 5,000 messages; in one longer than that, the top of the chat says how many of its first turns are not shown.
Finding an old chat
The board filter matches prompt text, project, and machine at once, and works across the whole fleet on Pro. The Archive page holds everything you or the idle rule put away. Chats are never deleted by Termdeck: the records belong to the CLI and live on your disk.
Turn limits
Starter and Pro have no cap on turns you send from Termdeck. Starting turns needs a plan, including during the 14-day free trial; Plans and limits has the details.