This is a personal fork of pingdotgg/t3code. Everything about the base project — what T3 Code is, installation, documentation, and contributing — is covered by the upstream README. This file only documents what the fork adds on top. Upstream's project-icon customization is covered in project settings.
dev— the fork. All fork work lands here; this is the branch you want.main— a clean mirror ofpingdotgg/t3code, deliberately kept free of fork commits so it can be fast-forwarded on every upstream sync. Syncedmainis merged intodevregularly.
-
Switch back to the previous thread. In the desktop app, Ctrl+Tab toggles between the current and previously viewed thread, including across projects and environments. It works while typing in the composer or terminal and follows the focused pane in split view. The pair lasts for the current app session.
-
Move a thread to the top. The command palette moves the current thread to the top of Pinned, Active, or its custom group, counting members hidden by filters or folded groups, and keeps its group. Drafts and archived, snoozed, or settled threads can't be moved this way.
-
Custom thread groups. Organize threads from any project or environment into named groups. Pick a group on the new-thread view or with New thread in group in the command palette, and move threads (several at once with Cmd/Ctrl-click) by dragging, from their menu, or from the palette. The Thread groups dialog places each group above or below Active; mobile shows the same groups and order, and Arrange threads moves threads between them. Forks join their source's group, and pinned, snoozed, settled, and archived threads return to their group. Settings → Extras can add a Thread groups toolbar button. The T3 CLI lists groups, starts threads in one, moves threads between groups, and pins, unpins, and lists pinned threads. CLI usage.
-
Rename and snooze from the command palette. Rename current thread edits the title inside the palette input. Snooze current thread lists the snooze presets with their wake times, including Until it's done and Until I wake it, and also parses a typed time such as
45m,2pm, orfri 9am; a snoozed thread offers Wake current thread instead. Both are available as unbound keybinding commands (Thread: Rename, Thread: Snooze) that open the palette straight into that step. -
Agent-requested worktree switches. After creating a worktree, a Codex agent can call
switch_worktree(Claude follows worktrees on its own; see Worktree-following Claude sessions). T3 waits for the turn, its final checkpoint, and any subagents or monitors it left running, then moves the thread's checkout; your next message continues the same conversation there. Agents inspect or cancel a pending move withworktree_switch_statusandcancel_worktree_switch, and return to the project checkout with the same switch tool. A new message, archiving, or a failed turn cancels it. -
Open threads from links. The desktop app opens
t3code://app/<environmentId>/<threadId>links (t3code-dev://for Dev builds) from other apps, whether it is already running or starts from the link. Useprimaryas the environment ID for the desktop's own environment. Archived threads open too, with an archived notice and an Unarchive button above the composer. A link to an unknown environment or thread shows a short error instead. -
Archive when done. Archiving a working thread, from its menu, the command palette, the archive shortcut, mobile, or the
/t3-archivecomposer command, waits until the turn, its checkpoint, and any subagents or monitors it left running finish. Automatic follow-ups such as subagent results don't cancel it; a new message does. A pending archive shows an archive icon on the thread's row, and the same actions cancel it. Agents can archive their own thread witharchive_thread(inspected or cancelled witharchive_thread_statusandcancel_thread_archive), optionally removing its clean worktree while keeping the branch; the CLI offerst3 thread archive self --after-turn --remove-worktree. Requests survive restarts. Sending a message to an archived thread unarchives it first. Usage and cleanup limits. -
Open a project's dev server from an action. In the desktop app, give an action a Preview URL and turn on Open in browser, reusing a running dev server. If a web server is already running from the project or worktree directory, clicking the action opens it in the in-app browser without running the command again. Otherwise it runs the command, waits up to a minute for the server, and opens it. Only the URL's path matters, so Vite moving to another port is fine. Detection uses
lsofon macOS and Linux; on Windows, or for servers in Docker, the action runs the command and opens the configured URL.
-
Snooze until it's done — an "Until it's done" preset, offered while the agent is mid-turn or its subagents are still working, hides the thread until that work ends, including the agent's follow-up on the subagents' results. Watch loops such as a dev server don't hold it. The thread returns when the agent finishes, is interrupted, fails, or asks you something. These rows sit at the top of the Snoozed section; the T3 CLI reports them as
Snoozed: until done. Web, desktop, and mobile. -
Indefinite snooze — on web and desktop, "Until I wake it" parks a thread on the Snoozed shelf with no timer. It comes back when you wake, pin, settle, or message it, or when it needs you (a finished turn, a failure, or a pending request). Automatic settlement skips it, and undoing a settle restores it. The T3 CLI reports it as
Snoozed: until woken. -
Working and Monitoring — when a turn ends while work it started keeps running, the thread list on web, desktop, and mobile shows Working for live subagents and workflows and Monitoring when only watch loops such as a monitor or a pull request watch remain; a dev server left running on its own lets the thread complete.
t3 thread wait --drainwaits for the agents;--drain=allwaits for monitors too. -
Conversation forking — fork a whole conversation into a new thread from the thread menus, the chat header, the command palette, or mobile. Providers that can fork their native session, such as Claude, Codex, and OpenCode, keep the full history in the new thread; the others carry the conversation over as context. An imported Claude or Codex session can be forked right away; a thread carried over from before the v2 upgrade can be forked after its first new message. Forks are titled with a (🔱) prefix and join the source thread's group.
-
Two-pane split view — web and desktop can show a second thread beside the routed one, including a thread from a different environment. Open it from the chat header button or the command palette's "Open thread in split view..." action. Hovering the divider reveals controls to swap the two threads (also
mod+shift+\), switch the right pane's thread, and close the split. Sidebar clicks and palette picks open into the active pane, the sidebar marks both open threads with pane glyphs,mod+\jumps between panes, and window shortcuts act only on the active pane. Each pane's header keeps its own panel toggles, andmod+wwith no panel tab open closes the active pane's thread, leaving the other one as the only pane. The divider drags and remembers its position. -
Hideable panel toggles — Settings → Extras → Panels can hide the terminal drawer and right panel toggles from the thread header, in single and split view, for keyboard-driven use; the header then stops reserving room for them and the shortcuts keep working. They show by default.
-
Mobile swipe-right actions — swiping a thread row right reveals Pin (Unpin on a pinned row), Fork, and Archive, in that order. Pin needs a server that supports pinning and Fork a conversation that can be forked; each has a twin in the row's long-press menu. Pin and Archive keep you on the list; Fork opens the new copy. Archive stays innermost, so a full swipe right still archives.
-
Session import — import an external Claude Code or Codex CLI session as a native thread in a project checkout from Project Settings; the native session continues in T3. Sessions already owned by a T3 thread show as linked; importing one again forks it into a fresh thread, so the original keeps its session.
-
Recent archived threads and archive browser — the thread list ends with a folded Archived shelf of your most recently archived threads on web, desktop, and mobile; set its size in Settings → Extras (Settings → Thread behavior on mobile). Opening one shows it as archived, and Unarchive or a new message restores it. On web and desktop the shelf follows the sidebar's project and environment filters, and the full archive in Settings groups threads by repository across environments, follows the Settings scope, and is searchable by title, project, path, environment, or model. The command palette adds Open archived threads, also scoped to the current project.
-
Offline mobile archive queue — archiving or unarchiving on mobile while an environment is disconnected takes effect immediately on the phone: an archived thread moves to the Archived shelf marked Pending, with an Undo action, and the change syncs on reconnect. A later choice for the same thread replaces the pending one.
-
Thread-list filters — the thread sidebar and the mobile thread list narrow the same list along independent axes:
- Project — show any combination of projects, or hide individual projects; both choices persist across relaunches.
- Environment — persisted per device. Pick any combination of environments, or jump to this environment only, remote environments only, or all environments. Each entry shows its connection state and thread count. A selected environment that stops responding stays selected and is marked disconnected; one removed from your connections is marked unavailable.
- Model (mobile) — once more than one model is in play, filter by the models your live threads run on.
Threads and unsent drafts follow the active filters. On mobile, Clear filters resets environment, project, and model in one tap.
-
Mobile thread prewarming — shortly after each environment connects, on app foregrounds, and when a running thread finishes, the mobile app caches a few recently active threads it hasn't stored yet, so they open instantly and can be read offline. A spinner beside the thread list title shows the warm-up, and Settings → Thread behavior adds a manual Sync Threads action with the time of the last full sync.
-
Message queueing and steering — on web, desktop, and mobile, a steer waits a few seconds before it reaches the running agent, so you can still edit, remove, or send it at once; the window defaults to five seconds and is set in Settings → Extras on web and per device in Settings → Thread behavior on mobile. On web, Enter in an empty composer sends the newest waiting steer, and ArrowUp edits the newest queued message. When a turn ends, consecutive queued messages with the same model settings go into the next turn together: the first starts it and the rest join as steers. A different model or effort, or a maintenance command, starts its own turn, and messages queued after the release wait for the next one. A dispatched steer is dimmed with "Waiting for the agent to pick this up" until the agent moves on, on every device. A queued message you are editing (or deleting on mobile) doesn't start, and an interrupted edit returns to the composer with its attachments, model, and context. On web, a text message sent while the server is offline or the page reloads waits in the browser and sends on reconnect. Queued messages also keep a thread from settling automatically.
-
Linear issue panel — on web and desktop, a
linear.app/<workspace>/issue/KEY-123link in any message opens the issue as a tab in the right panel instead of the browser, and bare identifiers likeSP-123do the same for the team keys you list. The tab shows the title, description, and comments, with the issue's properties as a row of chips that use Linear's own status and priority glyphs; the assignee, creator, project, and team open their Linear pages, and the parent, sub-issues, blocking and related issues, and attached links each get a section when the issue has them. Sub-issues and relations open as further tabs, the git branch name copies with one click, it refreshes on demand, and you can post a comment. Unsent comments survive tab switches within the same browser session; hovering a link shows a preview card. The personal API key (stored server-side, one per environment) and the team keys live in Settings → Extras → Linear. Mobile keeps opening these links in the system browser. -
File path actions. The open-in menu on a file tab ends with Reveal in Finder (File Explorer or Files on other hosts), Copy relative path, and Copy full path. Right-clicking the file name in the breadcrumb, the file tab, a file in the tree, or a diff header offers the same copy pair. Reveal, and the right-click menu's Open and Open with, only appear while you are on the machine that hosts the environment, since launching an app on another computer helps nobody. The menu's default-app entry is now called "Default app" rather than "Finder", because a file opens in whatever app owns its type.
-
Saved prompt library — reusable prompts (title + content) managed in Settings → Prompts and synced across connected environments with whole-library last-write-wins, including catch-up for environments that were offline during an edit.
/promptin the composer opens a filterable picker (titles and content previews) that inserts the prompt at the cursor without sending; the command palette's Prompts... submenu inserts the selected prompt into the composer on Enter and copies it on Cmd+Enter on macOS or Ctrl+Enter on Windows and Linux. Web and desktop. -
Sidebar polish — the Active section has its own named, foldable header with an inbox icon, and unsent drafts get a foldable Drafts section at the top of the web and desktop sidebar; Pinned, Active, Snoozed, Settled, and Archived keep their fold state per device. Thread rows add hover buttons to pin or unpin and to fork the conversation. Settings → Extras adds compact two-line thread cards (row details move beside the title), a choice of when rows show their provider icon, and an option to put the New thread button in the project filter row. Projects carry color accents shared across connected machines and shown in mobile thread lists, with optional row tinting (Settings → Extras on web, Settings → Appearance on mobile).
-
Thread actions in the command palette — the palette acts on the open thread: Archive, Pin or Unpin, Settle or Un-settle, and Fork, each shown only where it applies, plus Copy thread ID and Copy PR link. Copy thread ID and Archive also have their own keybinding commands.
-
Final-response navigator — beside the navigator for your own messages, web and desktop threads add a mirrored navigator for the agent's final responses, with hover previews and click-to-jump.
-
Provider usage meter — the composer meter nests the thread's context window (outer ring, behind Settings → General → Legacy features → Context window indicator), the subscription session window (weekly for Codex), and, for Claude threads served by a gateway pool, a Fable indicator for the account that would serve the next Fable turn. Its popover lists every account for the thread's provider with freshness, refresh, and optional email masking, and mobile shows the same in a bottom sheet. A provider instance routed through a CLIProxyAPI gateway can set a usage source (management URL and key, kept in the secret store): its meter then lists the gateway's pooled accounts and marks the one the thread's session actually uses as "current" and the pool's pick for new sessions as "next". Warning and critical ring thresholds are configurable on web.
-
Gateway-aware usage attribution — the Usage page can credit each model to the subscription it actually spends rather than to the transcript it was found in. A Claude Code session that a CLIProxyAPI gateway routed to an OpenAI model counts towards Codex, and a Codex session that reached an Anthropic model counts towards Claude Code. A "By subscription" / "By app" toggle in the page header switches between that pool view and grouping by the app whose transcripts recorded the usage; the choice is remembered per device. Per-row session counts appear only in the app view, because a single session can spend from both pools.
-
OpenRouter credit balance — the usage meter popover can show your remaining OpenRouter credits. Opt in under Settings → Extras → Provider usage and paste an OpenRouter management key (created at openrouter.ai/settings/management-keys; regular inference keys don't work) once; it is applied to every connected environment and stored in each environment's secret store. A failed read keeps the last balance on screen with the reason under it, and the reset button removes the key everywhere. An optional budget turns the balance into a spend bar with the same warning and critical colours as provider quotas. Web and desktop only.
-
Message font — Settings → Appearance → Typography (Advanced) adds a Message font row beside the Prompt font. It sets the family and pixel size of agent replies and your own messages in the thread. The interface size is untouched, so the conversation can run at 18px while the sidebar and tool rows keep the interface size. Markdown headings, inline code, tables, and footnotes inside messages scale with it. Web and desktop only.
-
Extras settings — a dedicated web and desktop settings page groups the fork's provider usage, Linear, sidebar, composer, accent tint, and voice controls.
-
Terminal close confirmation — upstream asks before every individual terminal close. Settings → General adds a switch that turns the prompt off; it stays on by default, and bulk tab closes and auto-exit cleanup never prompted either way.
- Voice dictation — ElevenLabs-powered voice transcription in the web and desktop composer. On mobile it backs the dictation control as the fallback wherever Apple's on-device transcription is unavailable (Android, older iOS, unsupported locales), so every device keeps a working mic.
- Message listening — optional spoken versions and summaries of assistant messages, with playback controls on web, desktop, and mobile. Requests run on the server, so their progress survives navigation and reconnects and shows on every connected client. Reopening a thread shows the player on every message that already has a recording, with its length. Playback belongs to the app, not the message, so audio keeps playing while you switch threads; mobile adds lock-screen and Control Center controls, and web and desktop support OS media controls and media keys. While a recording plays or sits paused mid-way, its thread shows a speaker icon in the web sidebar and the mobile thread lists that toggles play and pause.
- Speech providers — synthesis runs on OpenRouter (the default) or ElevenLabs. OpenRouter reaches every model on its speech endpoint (Gemini 3.1 Flash TTS out of the box, plus Deepgram, MiniMax, Microsoft, Fish Audio, and others) at a fraction of ElevenLabs' price; paste a regular inference key in Settings → Extras → Voice and it is stored in each environment's secret store. ElevenLabs keeps working from
ELEVENLABS_API_KEY, and dictation still uses it. Provider, model, and voice are dropdowns filled from the vendor's catalog with list prices per million characters, and supported models take an optional style instruction. A Test button generates an editable sample with the current selection and shows what it cost. Long scripts are split and synthesized in parallel, so long recordings arrive much sooner. - Agent voice replies — agents get a
voice_replytool that turns a script written for the ear into a recording attached to their final message once the turn completes; calling it again in the same turn appends another segment. Web and mobile show the recording as a player card below the written reply, and a turn that ends without a written message shows the transcript as its text. It needs a configured speech provider and can use its own provider, model, and voice; the switch in Settings → Extras → Voice (on by default) withholds the tool from newly started sessions. When the speech provider refuses a request because the account's quota or credits are used up, the agent and the "Listening version unavailable" notice say so.
- Home-relative provider binaries — Binary path settings for Grok and OpenCode accept
~or~/…; T3 expands them against the server user's home directory at runtime without rewriting the saved setting. - Claude shadow config dirs (multi-account) — a Claude instance can pair a shared config dir with an account-specific "shadow" dir (like Codex shadow homes): credentials, MCP server registrations, and per-project prompt history stay per account, while session transcripts, skills, agents, commands, and global settings are shared. Instances differing only by shadow dir can continue each other's sessions, so a thread can switch between two Claude subscriptions mid-conversation.
- Reasoning effort for custom Claude models — custom (gateway-served) models on a Claude provider instance show a Low/Medium/High/Extra High reasoning control in the model picker (default High), so one slug replaces per-effort model entries. The effort is sent as a
slug(effort)model name rather than Claude-native effort, which some gateways mistranslate; a slug that already ends in a parenthesized suffix is passed through unchanged. - Custom model display labels. Give custom models a name in provider settings. Existing
slug=Labelentries still load with the label shown in the picker and the bare slug sent to the provider. - Custom model icons — each custom model on a provider instance can carry one of the built-in glyphs (Codex, Claude, OpenCode, Cursor, Grok, Antigravity, plus Z.ai for GLM models), picked per model in the instance's Models settings. The icon replaces the driver's glyph in the model picker and composer, so a gateway-served model reads as its real model family at a glance. Overrides belong to the instance, so they never leak between instances of the same driver.
- Worktree-following Claude sessions — when Claude enters, changes, or leaves a worktree mid-session, the thread's branch and checkout follow it, so later turns and resumes start where the session actually is.
- Codex home identity — a Codex instance whose home comes only from its
CODEX_HOMEorHOMEenvironment keeps the right session history, usage, and continuation identity.
t3CLI automation — manage projects and their actions by repository path, create and control threads, send and steer messages, and inspect server, project, and thread status, with JSON output kept clean for scripting. Project actions use the same settings as the app and preserve concurrent-edit checks;project add,remove, andrenamealso work without a running server. New threads inherit the effective project and environment model, permissions, and workspace defaults. Live reads use configurable timeouts (--timeout-ms/T3CODE_CLI_TIMEOUT_MS), and--jsonfailures emit a stable machine-readable error document.- CLI thread waiting —
t3 thread waitblocks until a turn settles, can anchor itself after a send and drain background agents (--drain) or monitors too (--drain=all), and returns outcome-specific exit codes plus diagnostic JSON for shell composition. A pending approval or blocking question ends the wait asblockedunless--on-blocked waitis set. - CLI thread questions —
t3 thread input listprints a thread's unresolved questions with their ids, response mode, and options, andt3 thread input respondanswers one, so an agent driving another thread can answer a question thatthread sendalone would leave open. - CLI thread transcripts —
t3 thread messagesprints a thread's user and assistant messages without tool calls, with--role reasoningfor the provider's thinking. Output is a plain transcript or--jsonwith ids, roles, timestamps, and attachment metadata. It reads archived threads too, pages with--limit/--before, and resolves each attachment to an absolute path on the machine that owns it, naming that machine so an agent reading a remote thread knows where the files live. - CLI workspace selection —
t3 thread newmatches the app's workspace picker: without a workspace flag it honors the configured default (per project, then environment, then the checked-int3.json);--checkoutforces the plain project checkout,--new-worktreestarts in a fresh server-created worktree (with--base,--branch, and--start-from-origin), and--worktree <path>reuses an existing one. Thread list and status output report each thread'sbranchandworktreePath. - Thread self-addressing — every T3 terminal and agent process knows which thread and T3 installation it belongs to (
T3CODE_THREAD_ID,T3CODE_HOME, andT3CODE_STATE_DIR, set by the server), so a command run there can address its own thread asself. Cursor agents are the exception: they reach their thread through T3's MCP tools instead. - Session-handover CLI primitives — list and import Claude and Codex transcripts (
t3 session candidatesandt3 session import, with worktree, model, effort, instance, and title options), create model-specific threads, and archive the handed-off source thread. A renamed transcript still imports, Codex sessions are retargeted to the workspace they land in, and history past the import cap is trimmed with a warning instead of rejected.
- A saved environment's label or URL can be edited without re-pairing — the stored pairing token survives the edit.
- Projects keep their repository identity after their checkout is deleted, so their archived threads stay grouped with the repository.
- Pull request writes (merge, review, comment) first confirm that the checkout still points at the target repository, fall back to another checkout of the same repository when the original is gone, and refuse otherwise.
- Automatic worktree cleanup also spares checkouts with background work, a pending archive or worktree move, or another thread reaching them through a symlinked path, and a turn never starts in a checkout that is being removed.
- A turn cut off by a server restart is reported to the next turn as stranded, not as a user stop, so the agent continues instead of halting and apologising.
- Unsaved edits on a provider settings card survive resets, rejected writes, and saves from other cards.
- Escalating desktop process termination and an interactive sidebar resize rail.
- Dev app flavor — a separate Dev flavor of the desktop app with isolated state directories (shared provider homes), a Linux Dev AppImage build, personal-team iOS builds, and internal TestFlight uploads for the fork's production app. macOS Dev builds require a verified Developer ID signature so permission grants can survive rebuilds. See local signing setup. Remote Mac builds can automatically unlock a dedicated signing keychain.
- Fleet updater —
vp run update:machinesupdates the fork's dev machines, local and remote, in one pass: pick targets interactively or name them (--host,--include-local-desktop,--include-local-ios), see dirty or off-branch checkouts before rebuilding and cancel or continue the eligible remainder, build the local desktop and iPhone at the same time, let Expo prompt when a local iPhone needs unlocking, rehearse with--dry-run, and reread captured failures with--show-failure-logs. - Upstream sync workflow — a scripted
sync-upstreamflow that fast-forwards themainmirror from upstream, merges it intodev, and runs the required checks before pushing.scripts/check-upstream-sync.shreports whether a sync is due; it is also offered as the Check Upstream Sync action int3.json.