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 can move the current thread to the top of Pinned, Active, or its custom group, including members hidden by filters or collapsed groups. It preserves group membership and excludes drafts, archived, snoozed, and settled threads. New or reopened threads still follow the sidebar's usual placement rules.
-
Custom thread groups. Organize threads across projects and environments. Choose a group on the new-thread view or use New thread in group in the command palette. Move selected threads together from their context menu or the palette. Drag groups in the Thread groups dialog, or use its arrows, to arrange them above or below Active; mobile follows the same order and membership. Forked threads inherit their source group. Pinning, snoozing, and settlement retain the group. Settings → Extras can show a Thread groups toolbar button; the palette always offers group management.
-
Rename and snooze from the command palette. Rename current thread edits the title inside the palette input, and Snooze current thread lists the snooze presets with their wake times and also parses a typed time such as
45m,2pm, orfri 9am. Both are available as unbound keybinding commands (Thread: Rename, Thread: Snooze) that open the palette straight into that step. -
Agent-requested worktree switches. Codex can use
switch_worktreeafter creating a worktree. T3 waits for the turn and final checkpoint, then updates the thread’s checkout and resumes the same conversation there on the next message. Agents can inspect or cancel pending moves withworktree_switch_statusandcancel_worktree_switch, and return to the project checkout with the same switch tool. -
Archive after a turn. Agents can run
t3 thread archive self --after-turn --remove-worktreeto archive after successful completion and background work finishes, then remove a clean worktree. Cleanup preserves project roots and checkouts used by other threads or reserved as a pending move destination. Explicit thread IDs work for other running threads. Requests survive restarts and can be inspected or cancelled through the CLI. Usage and cleanup limits.
-
CLI title ownership and setup control. Explicit
t3 thread new --titlevalues stay protected from automatic renaming. Worktree setup runs alongside the agent by default; mark a setup actionasync: falsewhen it must finish first. CLI action edits preserve this choice. -
Removed worktree recovery. Follow-up messages continue the same conversation in the main project checkout when a worktree is gone. A T3 notice appears as a user message and tells the agent where it is running. Settings → Extras → Skip recreating removed worktrees is on by default. Turn it off to try recreation first, with the main checkout as a fallback if recreation fails. Mobile exposes the same shared setting under Settings → Thread behavior.
-
Snooze until it's done — an "Until it's done" preset in the thread snooze menus, offered only while the agent is mid-turn, hides the thread until that turn ends: it returns when the agent finishes, is interrupted, fails, or asks you something, with the usual Woke marker. These rows sit at the top of the Snoozed section with an "until done" label; the T3 CLI reports them as
Snoozed: until done. Available on web, desktop, and mobile against servers that carry the feature. -
Indefinite snooze — an "Until I wake it" preset in the thread sidebar snooze menus parks a thread on the snoozed shelf with no timer: it comes back when explicitly woken, when you send it a message, or when the thread needs you (a finished or interrupted turn, a failure, or a pending request). Indefinite rows sort after every timed wake and carry a "parked" label; the T3 CLI reports them as
Snoozed: until woken. -
Conversation forking — fork a Codex or Claude thread mid-conversation into a new thread, including immediately after importing an external session. Claude copies the full native history using the same bundled helper as rewind, preserving the selected provider instance and matching conversation turns even when native system records change; forked threads are titled with a 🔱 prefix.
-
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 (between the git actions and the terminal toggle) or the ⌘K "Open thread in split view..." action. While split, hovering the divider reveals its controls near the top: swap the two threads (also ⌘K "Swap split threads", rebindable, default mod+shift+), switch the right pane's thread, and close the split. Sidebar clicks and ⌘K thread picks open into the active pane — picking a thread already on screen just focuses its pane, so neither path can accidentally fold the split — and the sidebar marks both open threads with left/right pane glyphs. A ring marks the active pane, a rebindable shortcut (default mod+) jumps between panes, and window shortcuts — including permission-prompt number keys — act only on the active pane. Each pane's right panel opens as an overlay sheet, terminals stay with the pane that owns their thread, the divider drags and remembers its position, and actions that create a new thread (new thread, implement plan) stay in the main pane.
-
Mobile swipe-right actions — swiping a thread row right reveals Pin (Unpin on a pinned row), Fork, and Archive, in that order. Each action only appears where it applies — pin needs a server that supports pinning, fork needs a forkable Codex or Claude conversation — and every one of them 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 external Claude Code and Codex CLI sessions as native T3 threads from thread-sidebar project settings (choosing the environment when the project is grouped across several) or the desktop project context menu, including strict resume/continuation, Claude-generated and explicit CLI session titles, and explicit instance labels when more than one provider instance can import sessions. Sessions already owned by a T3 thread stay visible as linked candidates; importing one again forks the provider history into a fresh continuation so the original thread keeps sole ownership of its native session.
-
Archived-thread recents, search, grouping & undo — the final thread-sidebar section on desktop and mobile keeps a configurable recent archive close at hand, with one-action restore, archive-aware menus, and automatic restore when a new message is sent; the full archive remains searchable and grouped, and it follows the environment and project selected in the settings breadcrumb, so narrowing to a project, one of its checkouts, or one machine narrows the archive the same way. The open web thread can be archived from the command palette or a configured shortcut, a mobile thread row archives with a full swipe right, and on web the sidebar offers Undo for archive, snooze, settle, and unpin for five seconds. The configurable
mod+zshortcut triggers that notice, including consecutive actions of the same kind. An empty new-thread screen can reopen the restored thread; another active conversation stays in place. The section folds on every client and starts folded, since archived threads are the ones you deliberately put away; the header then reports the archive count, and the thread you have open keeps its row while the section is folded. On web and desktop the section follows the project and environment filters like the rest of the list, so its rows and count only cover the projects you are looking at. -
Offline mobile archive queue — archiving from mobile while an environment is disconnected now persists the desired thread state on-device. The thread moves immediately into recent archives with a Pending marker and an Undo action, then syncs on reconnect once queued messages and active work have cleared; later archive or restore choices replace earlier pending ones.
-
Thread-list filters — the thread sidebar and the native mobile thread list narrow the same list along independent, composable axes:
- Project — show live threads from any selected combination of projects, with a one-click “All projects” scope; individual projects can also be hidden outright, and both choices persist across relaunches.
- Attention — snapshot threads that are working, completed, failed, or waiting on approval, input, or a plan decision. The focused list stays stable as statuses clear, admits threads created from any connected client or the T3 CLI, and refreshes only when the filter is toggled off and on again. A thread that was merely woken while otherwise ready is deliberately left out — its wake indicator already carries that signal — and a setting keeps pinned threads visible while the filter is on.
- Environment — persisted per device. A button beside the search box opens a multi-select menu: pick any combination of environments, jump straight to This environment only or Remote environments only, and clear back to All environments. Every row carries a connection dot and the number of threads that environment currently contributes (already accounting for the project filter), the machine you're on is marked "This device" and takes the display icon while remote environments take the server icon that marks their threads in the list, and the button hides itself entirely when there is only one environment to choose between, staying put whenever a filter is active so a scope is always clearable. A selection survives a disconnect instead of silently widening: an environment T3 Code has lost contact with says it is not connected rather than claiming it has no threads, and its count is withheld while it can't be seen, while one removed from your connections reads as unavailable — the two never look alike. The legacy sidebar keeps its original single-select radio menu left of the sort control (with a "No projects in this environment" empty state, filtering before project grouping, and manual project reorder disabled while it is active), as does the native header on iOS.
- Model (mobile) — once more than one model is in play, the filter menu lists the models your live threads run on, labelled from the environment's catalog; grouped thread rows show the provider's mark on the subtitle line, and a pin that no longer matches any thread falls back to "all models".
Threads and unsent drafts follow the active filters. On web and desktop the archived-recents section follows the project and environment filters too and steps aside only for the Attention filter; on mobile it hides itself while any filter is on. On mobile the menu leads with a Clear filters action that resets environment, project, and model in one tap, and on compact layouts opening a thread clears the search box so returning to the list shows every thread again.
-
Mobile thread prewarming — shortly after each environment connects (and on later app foregrounds), the mobile app fills missing offline detail-cache entries for a few recently active threads per environment using bounded history pages. Existing entries are preserved because they may contain explicitly loaded scrollback; opening them online catches up from the server, while an offline open can remain stale until connectivity returns. A settled-turn trigger likewise helps only when that thread has no local detail entry. Cached conversations paint immediately, and older messages load on demand as you scroll, keeping long conversations responsive without changing desktop/web history behavior. The thread list header shows a spinner beside its title while the app is warming threads, and Settings → Thread behavior adds a manual Sync Threads action with an indicator showing when a full sweep last completed.
-
Message queueing and steering — on web and mobile, sending during a running turn steers at the agent's next step after a recall window; that window defaults to five seconds, is configurable on web (Settings → Extras) and per device on mobile (Settings → Thread behavior), and can be retired early from the visible outbox. On web, pressing Enter again in the empty composer also sends the newest steering message immediately. A message that waits instead — the “Queue for later” send option, or anything that piled up while the thread was unreachable — holds until the turn completes, and then the whole waiting queue is released into the next turn together rather than one message per turn. On web, ArrowUp recalls the newest queued message into an otherwise empty composer. The outbox on both clients also lets queued messages be steered, edited, or deleted; on mobile a delete confirmation holds the message so it cannot send underneath the dialog, and cancelling restores its place in the queue. On web, a queued message whose images no longer resolve offers a recovery action instead of failing silently, and an outbox that is full or unavailable says so rather than dropping the composer's contents. Once a steer is dispatched, its bubble in the timeline is dimmed and marked “Waiting for the agent to pick this up” until the main agent moves on — Claude Code only drains its prompt queue between a tool result and the next model request, so a steer sent behind a long subagent or shell call can genuinely sit unread for minutes. The marker is derived from thread state, so it shows on every device, survives reloads, and is still there when you come back to the thread.
-
Per-project default model — Project Settings can pin the model that new threads pre-select (a selection carried from a thread you're viewing still wins within the same project). Picking a model in an existing thread changes that thread only, without rewriting the project default.
-
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.
-
Composer thread commands let you edit the current title with
/t3-name, set a new title with/t3-rename, or set its status emoji with/t3-statuson web, desktop, and mobile./t3-archivearchives now or after the running turn finishes, with/t3-archive cancelto cancel a pending request. -
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. -
Thread naming & sidebar polish — split thread naming with refined fork titles; the thread sidebar adds optional two-line active-thread cards, the attention filter and New project buttons on the search row with an opt-in placement for the New thread button at the end of the project filter row, per-project color accents shared across connected machines and shown in mobile thread lists (cached on-device so a cold mobile launch paints them instead of flashing them in as environments connect), accent tinting for web thread rows and new-thread project choices plus per-device mobile tinting (Settings → Appearance) — off keeps the accent as a project-header dot on both — one-click project-filter clearing, and a setting to show each thread's provider icon on hover, always, or never. On web and desktop, thread cards' hover actions now lead with a pin/unpin toggle (filled pin while pinned), the Settle button is just the checkmark, and forkable Codex and Claude conversations add a Fork button between Settle and Archive; mobile reaches pin through the swipe action and the row menu. Pinned and Active both fold behind their own headers on web and mobile. Active has an inbox icon and a stronger neutral label to distinguish it from custom groups. Unsent drafts get their own foldable Drafts section at the top of the web and desktop sidebar, shown only while a draft exists. The Drafts, Pinned, Active, Snoozed, Settled, and Archived sections all keep their fold state per device across relaunches.
-
Thread actions beyond the sidebar row — acting on the thread you're reading never means finding its row first. The chat header title (click it, or right-click the breadcrumb) opens a menu with Fork conversation, Archive thread, and Copy thread ID, and the web command palette (⌘K) carries the full set: Archive, Pin/Unpin, Settle/Un-settle, and Fork, alongside Copy thread ID, which stays available when a PR is linked, and Copy PR link when available. On web and desktop, the ID-only action has its own optional “Thread: Copy ID” keybinding; upstream’s combined reference shortcut keeps its existing behavior. Each lifecycle pair shows the one verb that applies, resolved from the same settled and pinned state as the sidebar row menu (so the three surfaces never disagree); Settle stays visible but disabled while the thread still has running or queued work, Pin and Settle appear only on environments advertising those capabilities, and Fork is withheld on archived threads the server would refuse. The palette also gains Open archived threads and a project-scoped Open archived threads in <project>, which open the archived settings page with the settings scope already narrowed to that project.
-
Conversation navigation rails — desktop threads keep the existing left-side user-message navigator and add a mirrored right-side navigator for completed agent responses, with hover previews and click-to-jump navigation. A reading position you scrolled to yourself is kept as the turn streams in, rather than being yanked back by delayed anchoring.
-
Notifications let you choose completion toasts, background-only system notifications, and a minimum turn duration in Settings → Extras. Optional input, approval and failure alerts use the same channels, with distinct completion and attention sounds. Delivered background notifications add a per-thread unread badge, cleared when the app regains focus. Clicking a system notification focuses the app and opens its thread. Existing preferences are preserved; new alerts and sounds start off.
-
Provider usage meter — upstream's Usage page now has a Limits tab for direct Codex and Claude Code subscription windows; the fork keeps its own live, server-owned per-account quota view on top of it, retained per configured account and shared across threads, and it is the only place CLIProxyAPI pools, per-thread account affinity, and failover state are shown. The composer meter nests them: the outer ring is the thread's context window (hidden by default since upstream made the context indicator an opt-in legacy setting — enable “Context window indicator” under Settings → General → Legacy features to bring it back), the ring inside it tracks the subscription session window (weekly for Codex), and Claude-served threads fill the centre with a Fable indicator for the available pooled account that would serve the next Fable turn. The web popover lists every non-disabled account for the thread's provider with freshness and on-demand refresh, scrolls its account list so a large pool stays fully readable, keeps cooldown accounts visible, and can mask account emails; mobile mirrors the account and Fable-next details with full emails in a scrollable bottom sheet that draws each window's bar, percentage, and reset. Both surfaces show one freshness line for the whole panel — the age of its oldest account — and both re-read on open when any listed account is more than a minute old. After automatic rate-limit failover, both clients follow the session's live account rather than the originally picked one. Claude reports its per-window percentages through the same data as
/usage; Codex can read usage before a thread has a live provider session and renders whichever windows it reports. Optional approaching-limit warnings and warning/critical ring thresholds are configurable on web; reaching 100% stays visible in the meter without another toast. An instance routed through a CLIProxyAPI gateway can set a per-instance usage source (management URL + key, stored in the secret store): its meter lists the gateway's pooled Claude and Codex accounts instead of the local login, resolves the active model through the gateway catalog when available, and hides sibling direct accounts while a thread runs on the gateway (and vice versa). Opening the pool popover or the mobile sheet also reads the gateway's own session-affinity table for the active thread, so the account marked "current" is the one the thread's Claude session actually spends; the pool's priority pick, which only applies to new sessions, shows as "next". -
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, so one model no longer appears as two rows split between the providers. 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 (all Claude Code activity as one row); the choice is remembered per device. Spend and tokens regroup exactly either way — every response belongs to one row in each view — while per-row session counts appear only in the app view, because a single session can spend from both pools and cannot be split honestly. The correction is applied when the page merges each environment's answer, so it also covers environments running an older server.
-
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; the credits endpoint rejects regular inference keys) once; the key is applied to every connected environment, stored in each environment's secret store, and used server-side to read
GET /api/v1/creditswith a one-minute cache. A failed read keeps the last balance on screen with the reason under it, the settings page lists each environment's stored-key state and current balance, and the reset button on the key row removes the key everywhere. An optional budget (the balance you started from) turns the balance into a spend bar with the same warning and critical colours as provider quotas. The row sits last in the popover's scrollable account list rather than pinned above the context window. 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/desktop settings page groups the fork's notification, sidebar, composer, accent-tint, and message-listening controls without changing mobile's established defaults. It also hosts the switch for automatic settling: leave it on to settle threads after inactivity or once every linked pull request is merged or closed (an open or unsynced link keeps the thread active), turn it off to settle only by hand. The individual settlement reasons in General can be overridden per project; the master switch stays environment-wide. Mobile carries the same switch in Settings → Thread behavior, where turning it off also hides the merged-thread toggle it governs.
-
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 of assistant messages with playback controls on web, desktop, and mobile. Listening requests run as server-owned jobs, so pending state survives navigation and reconnects and appears on every connected client. A server restart clears interrupted requests so they can be retried. Finished recordings are event-sourced and rebuild with the thread projection. Reopening a thread shows the player on every message that already has a recording, so you can tell which ones have one without hovering each, and each player shows the recording's length before you press play. Playback belongs to the app, not the message row, so audio keeps playing while you switch threads. Mobile adds lock-screen and Control Center controls, while 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, and the icon toggles play and pause. The icon goes away once the recording reaches either end (on web you can also drag it there); the message player still replays it. Per-message summaries keep their existing local behavior.
- Speech providers — synthesis runs on ElevenLabs or OpenRouter. OpenRouter is the default and 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. Gemini only serves raw PCM, so its recordings are stored as WAV (about ten times the size of MP3 per minute) and every other model as MP3; 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. The provider, model, and voice are dropdowns filled from the vendor's own catalog, with list prices per million characters shown next to each model, and supported models take an optional style instruction. Blank model and voice settings use the server's environment defaults, including in the Test dialog. A Test button opens a dialog with an editable sample sentence: generate it with the current selection, listen, and see what it cost (OpenRouter reports the billed amount; ElevenLabs reports billed characters). Agent voice replies can use a separate provider, model, and voice from message listening. Existing installs keep ElevenLabs, including those using its default model and voice. OpenRouter models generate at only a few times real time, so a script longer than about 800 characters is split at paragraph and sentence boundaries, synthesized four pieces at a time, and joined back into one recording; a three-minute Gemini recording lands in under 30 seconds instead of two minutes. - Agent voice replies — agents get a
voice_replytool that turns a script they write for the ear into a recording, attached to their final message when the turn completes; calling the tool again in the same turn appends another segment, and they play in order as one recording. Web and mobile render the recording as an accent-tinted player card below the written reply; a turn that ends with no written message publishes the transcript as the message text. Needs a configured speech provider; the switch in Settings → Extras (on by default) withholds the tool from newly started agent sessions. Claude and Codex sessions give the tool four minutes per call instead of their usual one, since a long script on a slow speech model can take over a minute to synthesize. When the provider refuses a request because the account's quota or credits are used up, the tool error tells the agent, and the "Listening version unavailable" notice on web and mobile says so too instead of suggesting a retry.
- Home-relative provider binaries — explicit Binary path settings for Claude, Codex, Cursor, Grok, Hermes, and OpenCode accept
~or~/…; T3 expands them against the server user's home directory at runtime without rewriting the saved setting. - Claude skill picker — the
$composer skill picker discovers workspace and user-invocable manual-only skills for Claude, and makes references to them work anywhere in a message. Claude Code only parses/nameas a command at the start of a message, so a$namereference to a skill markeddisable-model-invocation: trueis rewritten in the outgoing prompt to/name [Read: <path to SKILL.md>]. The chip you see and the message that is stored are unchanged; the agent gets the intent plus a pointer it loads only if it acts on it. - Hermes ACP provider — use a machine-local Hermes Agent as a first-class provider with native streaming, tool calls, resumable sessions, model and mode selection, slash commands, skills, and steering.
$skillreferences work anywhere in a message, not just at the start; a reference is rewritten to/skillonly when it names a skill Hermes actually reports, so$PATHand other prose survive untouched. - 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 (they live in
.claude.json/ the credential store), while session transcripts, skills, agents, and commands — plus global settings, hooks, plugins, andCLAUDE.mdwhen present — are shared through materialized symlinks. Instances differing only by shadow dir form one continuation group, so live and stopped threads can switch between two Claude subscriptions mid-conversation and resume the same session. - 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 bare slug replaces per-effort model entries. The selected effort is applied by rewriting the model name to
slug(effort)when spawning the CLI — never as Claude-native effort, which some gateways mistranslate — and a slug that already carries 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, Hermes, 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 list and composer trigger, so a gateway-served model (e.g. a Codex model behind a Claude provider instance) reads as its real model family at a glance; the instance accent color and badge stay unchanged. Overrides live in the instance config (
customModelIcons, keyed by the bare slug), so they follow the instance and never leak between instances of the same driver. - Worktree-following Claude sessions — when Claude enters, changes, or leaves a worktree mid-session, T3 tracks the move from the transcript and updates the thread's checkout metadata, so a later resume starts the CLI in the directory the session is actually in rather than the one it began in.
- Automatic rate-limit failover — a provider instance can name a same-driver sibling as its "Failover instance" in Settings. When the instance hits its subscription usage limit (a rejected rate-limit report from the CLI, or a turn failing with a rate-limit error), turns route to the sibling until the limit lifts, then return; both switches are announced in the thread's work log. The two instances must share session state — one continuation group, e.g. the Claude shadow config dir setup or a shared
CODEX_HOME— otherwise failover never runs, for new and existing threads alike. Detection is provider-reported for Claude; other drivers mark an instance limited when a turn fails with a rate-limit error.
t3CLI automation — project and thread automation commands: manage projects and their actions by repository path, create and control threads, send and steer messages, and inspect server/project/thread status, with JSON output kept clean for scripting. Project actions use the same settings as the app, preserve concurrent-edit checks, and save project overrides without replacing other settings. New threads inherit the effective project/environment model, permissions, and workspace defaults. Live reads use configurable phase-specific timeouts (--timeout-ms/T3CODE_CLI_TIMEOUT_MS), commands reuse one auth session,--jsonfailures emit a stable machine-readable error document, and read-only listings require a running server.- CLI thread waiting —
t3 thread waitblocks until a turn settles, can anchor itself after a send sequence and drain native background agents or monitors, and returns outcome-specific exit codes plus diagnostic JSON for reliable shell composition. When only a stale"working"liveness keeps an agents drain pending, the wait self-heals after 3 minutes of observed thread inactivity and reportsdrainStale: trueinstead of timing out. Only a pending approval or a blocking question ends the wait asblocked; a Codex message-mode question keeps the turn running and is reported without ending the wait. - CLI thread questions —
t3 thread input listprints a thread's unresolved questions with their ids, response mode, and options, andt3 thread input respondanswers one with a complete answer map, so an agent driving another thread can answer a Codex question thatthread sendalone would leave open. /t3-waitcomposer command — the web composer's slash menu opens a filterable picker of the workspace's recent threads (activity indicators; running threads first in the unfiltered list) and inserts a ready-made "wait for thread<id>to finish, then …" instruction at the cursor for the user to complete and send — nothing is sent automatically.- CLI thread transcripts —
t3 thread messagesprints a thread's user and assistant messages without tool calls. Use--role reasoningto read provider thinking summaries on supported servers. Output is available as a plain transcript or as--jsonwith ids, roles, creation timestamps, and attachment metadata. It reads archived threads too (marked"archived": true), fetches the full history by default with--limit/--beforepaging and a--rolefilter (falling back to the full thread snapshot on servers without the dedicated messages route), and resolves each attachment to an absolute path on the machine that owns it — the output names that machine's hostname and environment, so an agent reading a remote thread over SSH knows the files live there rather than assuming they are missing. - CLI workspace selection —
t3 thread newmatches the UI's workspace picker: without a workspace flag it honors the configured default environment mode (per-project setting, then the environment setting, then the checked-int3.json, then checkout) like the app clients,--checkoutforces the plain project checkout,--new-worktreestarts the thread in a fresh server-created worktree (with--base,--branch, and--start-from-originoptions, running the project setup action and auto-renaming the temporary branch from the thread title), and--worktree <path>reuses an existing worktree. Thread list/status output reports each thread'sbranchandworktreePath. The server's HTTP dispatch route now runs the same worktree bootstrap as the WebSocket path and advertises it via theturnStartBootstrapcapability, so bootstrap payloads are no longer silently ignored for HTTP clients. - Thread background diagnostics — every T3 terminal knows which thread and which T3 installation it belongs to (
T3CODE_THREAD_ID,T3CODE_HOME, andT3CODE_STATE_DIR, set by the server and not overridable by a client), so a command can address its own thread with no arguments. Building on that, a maintainer script names the background tasks keeping a thread stuck on the Working or Monitoring pill and finds the processes behind them, distinguishing work that is genuinely live from stale bookkeeping left by a dead session — and saying so plainly when a session cannot be probed at all. Records predating the current server start retire themselves, and the orphans left over can be listed in full or dismissed for good. - Session-handover CLI primitives — inspect and import Claude/Codex transcripts (including standard worktrees, explicit model options, and an explicit thread title), create model-specific threads, and archive handed-off source threads. Claude transcript identity comes from the records themselves, so a file renamed in transit still imports; Codex rollouts are retargeted to the workspace they are imported into; and history past the import cap is trimmed with a warning instead of rejected.
- Mobile new-thread image sends compact oversized screenshot payloads before transmission, and a connection drop during thread creation warns the user while preserving the draft for retry.
- Mobile composer drafts and their attachments are persisted as you type and recovered on relaunch: partially written attachment data is salvaged where it can be read, and a failure to prune the cache never takes the current draft with it.
- A saved environment's label or URL can be edited without re-pairing — the stored pairing token survives the edit.
- Bounded catch-up for stale clients reconnecting to the server.
- The session reaper spares provider sessions that still have pending deliverables.
- A turn interrupted by a shutdown or provider exit is reported to the resumed agent as stranded, not as a user rejection, so it continues instead of halting and apologising.
- 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 —
pnpm update:machinesupdates the fork's dev machines, local and remote, in one pass: pick targets interactively or name them (--host,--local-machine), 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.