Reference

Security and privacy

You are installing a program that can drive a coding agent on your machine. That deserves a straight account of what it can do, what it cannot, and what you are trusting.

The design in one sentence

The agent is a narrow set of typed capabilities rather than a remote shell, so the worst a compromised Termdeck could do to your machine is bounded by that list rather than by your file permissions.

What the agent will do

This is the complete surface. Everything Termdeck does is composed from these.

CapabilityBounded by
Read, stat, list, and watch filesThe transcript directories of the installed engines, and nothing above them.
Browse and read project filesThe folder the chat was opened in, read only, enforced on both ends.
List folders for the folder pickerFolder names only, one level at a time. No file names and no contents.
Start a processThe three known engines only. There is no capability that runs a command of the caller's choosing.
Write to a process, read it, stop itProcesses it started itself, and their children. The one exception is Take over: it may stop a Claude Code terminal session that registered itself on your machine. Any other process is refused, whatever Termdeck asks.
Report machine factsInstalled CLIs, login state, rate limit percentages, agent log.
Rename, tag, duplicate, or remove a chat, and save its settingsFiles inside the transcript directories. A removed chat is moved to a trash folder in the same directory, not deleted.
Restore a checkpointFiles that the engine itself snapshotted for that session.
Write the project instruction fileA fixed two entry filename table, resolved from a real session's own record. The caller names a session and an engine, never a path.
Save a file you attach~/.termdeck/uploads, one folder deep. The agent computes the folder itself and is only told a name and an allowed file type. Nothing is written executable, nothing overwrites anything that already exists, and nothing lands inside your project.
Switch saved accountMoving a credential file the CLI itself wrote.
Create a folderOne empty folder, named by you in the folder picker, directly inside a folder that already exists. It never overwrites and never writes a file.
Open a pull requestRuns gh pr create in the chat's own checkout, with your title and body and your own GitHub login.

A request that is not on this list has no handler. There is no escape hatch, no generic exec, and no path parameter that reaches outside its confinement.

What the agent will not do

  • Run a command on its own. There is no capability for it. Commands run only inside a coding agent's turn, under that chat's permission mode, and a machine with TERMDECK_FULL_ACCESS=off refuses the mode that runs them without asking.
  • Read an arbitrary file. Reads are confined to transcript roots and the open chat's project folder.
  • Write an arbitrary file. The only writes are the narrow ones in the table above: chat housekeeping inside the transcript directories, checkpoint restore, the project instruction file, an attachment, a saved account switch, and one empty folder. An attachment and the instruction file you edit are the only ones whose bytes come from the browser.
  • Accept an inbound connection. It dials out and listens for nothing.
  • Send your source code anywhere. Repository content crosses the wire only when you open a file or a diff in the dock, and then only to your own browser.

What crosses the wire

CrossesDoes not cross
Transcript content for chats you open, streamed on demandYour provider passwords, API keys, or subscription tokens
Live turn output while you are watchingRepository content you have not opened
File contents and diffs you explicitly open in the dockMCP auth headers, environment values, and credentials in URLs
Rate limit percentagesThe tokens those percentages were read with
Token counts for the usage pageThe transcripts those counts were derived from

Rate limits are read on your own machine against the provider's endpoint, and only the resulting percentage is sent. Usage totals are computed on your machine as well; the scan does not upload the transcripts it scans.

What the master stores

  • Your account: email, authentication, subscription, and plan grants.
  • Your machine list, with each machine's token stored as a hash rather than the token itself.
  • Push subscriptions for the devices you enabled notifications on.
  • Per chat preferences you set here, such as a custom title, pinned state, or archived state.
  • The chat list itself: each chat's title, its project folder and when it last moved, kept so the sidebar is there right after a Termdeck update instead of being read from every machine again. A title comes from a chat's first prompt or from a rename, so a few words of a prompt can sit in this list. The rest of the transcript never does.
  • Aggregate operational counters, for example turns per day, used for billing and for the admin console.

It does not store transcripts, source code, provider credentials, or diffs. Nothing is persisted from a chat you open beyond what is listed above.

Your browser keeps its own copies to load faster: recent transcripts, your preferences, and the words you typed but did not send. Clear local data under Settings, Data & reset removes the transcript copies and preferences, including each chat's remembered permission mode. It keeps unsent drafts and each chat's prompt history, because those are your own work. On a shared computer, clear the site's data in the browser's own settings to remove those as well.

Product analytics

On signed-in dashboard and Settings pages, Termdeck shares a small set of product-use events with Microsoft Clarity. This is on by default. You can turn off Share product-use signals under Settings, Data & reset. The choice is local to this browser and survives Clear local data. Global Privacy Control and Do Not Track also keep it off. When it is off, the browser does not load Clarity.

Clarity does not run in the dashboard or Settings document. It runs in a hidden, empty sandbox that cannot read the product document. The sandbox has a fixed, queryless URL, an empty referrer, and a fixed title. The product can pass it only an allowlisted event name, with no properties or free-form values. Termdeck does not call Clarity's identify API.

Signals includedExamples
NavigationHome, chat, New chat, Approvals, Terminals, Usage, Archive, and each Settings section
Feature useTurn submit, queue, steer, attachments, dictation, search, model or effort change, files, subagents, shells, terminal reply, permission decisions, MCP, and feedback
Outcomes and frictionRun completed, errored, or aborted; stale run, connection loss, chunk load failure, or client error

Chat and terminal content, prompts, output, code, filenames and paths, credentials, account and session identifiers, model names, error text, page titles, product URLs and hash routes, link attributes, data attributes, and product CSS are excluded. Marketing, docs, login, signup, admin, and demo pages do not start product analytics.

Termdeck sends Clarity Consent V2 with both advertising and analytics storage denied, and the Clarity project has cookies switched off. This is limited, cookieless tracking rather than zero collection: Microsoft still receives the empty sandbox's page view, fixed event names, timing and browser or device fields produced by Clarity, and normal network metadata. Termdeck adds no account identifier. Without analytics storage, Clarity treats each page view separately, so it cannot reliably count unique people or join a journey across reloads and separate documents.

This boundary has a deliberate coverage cost. Clarity recordings and heatmaps contain only the empty sandbox, so they cannot show the real interface or replay a user's work. The useful coverage is aggregate counts for the fixed navigation, feature, outcome, and friction events above. Microsoft documents the underlying behavior in its Clarity client API, Consent V2, and masking guide.

What you are actually trusting

Two things, and it is worth naming them plainly rather than burying them.

The agent updates itself from the master

The master delivers updates, but it cannot write one. Every release is signed offline with a key the master never holds, and the agent installs a release only when the signature checks out, every file matches it, and the version is not older than the one it runs. A master that was broken into could hold updates back; it could not push its own code. Your first install is the exception: it trusts what it downloads, which is why the installer offers to print the whole source before running it. A bad release still rolls itself back and quarantines the version rather than needing hands on the machine.

If you want to inspect what your machines are running, the same files the installer downloads are readable at any time:

Terminal
curl -fsSL https://termdeck.io/download/agent/manifest.json
curl -fsSL https://termdeck.io/download/agent/signature.json
curl -fsSL https://termdeck.io/download/agent/capabilities.js

The coding agent is the powerful part

Termdeck's own capability list is narrow. The coding agent it drives is not: an agent in full access mode can do anything you can do in a shell. That is what the permission system is for, and it is the layer that deserves your attention.

Prompts and approvals reach your machine through the master, so the master is also trusted to pass on only what you typed and what you approved. To take the unattended case off the table for a machine, set TERMDECK_FULL_ACCESS=off in its agent settings: it then refuses Full access whatever the master asks for, and every action waits for an approval. See Turning Full access off.

The refusals that do not depend on you

A set of guards refuse certain calls before any of your settings are consulted, and before the default read only auto allow list gets a look. The motivating case: Read is auto allowed because reads cannot mutate anything, and reading an SSH private key is a read.

Credential files, remote scripts piped into a shell, sudo, shell startup files, system paths, deleting outside the project, and broad recursive deletes are all refused by default. Each can be switched off individually, only from the settings page, and no auto allow rule can override one. Full detail on Approvals and permissions.

Notification actions

The Allow and Deny buttons on a push notification work without the app being open, so the notification carries its own authorisation: a single use token that expires after 5 minutes, when the prompt it answers is denied anyway, and is invalidated on first use. It authorises exactly one answer to exactly one pending prompt.

Account isolation

Every route is addressed by machine name and scoped to the owning account. Nothing is ever keyed on a bare session id, because session ids are generated locally and can collide between users. Message fan out is scoped the same way.

Rendering your code

File contents and diffs are built as document nodes, never as markup, on every path and for every file type. A file that contains HTML is displayed as text.

Practices worth adopting

  1. Open chats in the narrowest folder that contains the work. It bounds what the agent can reach and sharpens the risk scoring on every approval.
  2. Leave the hard denies on. They cost nothing on a normal day.
  3. Keep auto allow rules tight, with a specific glob and a low risk cap.
  4. Use full access only in a repository you would be happy to delete.
  5. Treat the machine token like an SSH key. Regenerate it if it has been anywhere it should not.
  6. Remove machines you no longer use, which revokes their tokens.

Reporting a vulnerability

Email [email protected] with the detail. Please do not open a public issue for a security report.