T3 Code goes quiet at the moment an agent needs you.

T3 is calm and carefully built. I scored the whole app 7 out of 10. The low scores cluster where an agent has stopped: approvals and failures both score 5. Most of the fix is small, and eight patches are already running on branches.

Overall7 / 10 across 21 surfaces
Evidence104 states audited at 1440×900, default dark
Patches8 branches. 6 have After captures, R5 a mock, R10 a measured table
T3 commit337c5858, Nov 5, 2026

This is an unofficial design study. It was not made by or endorsed by T3. All names and data on the images are made up.

Fig. 0.1 A thread waiting on your approval. capture
  1. Still says Working for, though the agent has stopped.
  2. Allow is a 29×16 px text link, Deny 28×16.
  3. The loudest thing on screen is a 32 px red Stop.

1What the sweep covered

I walked apps/web/src/routes and apps/web/src/components first and listed every surface in inventory.md, then ran the real web app against a fake socket with seeded data. The table groups them. Six groups could not be reached, and the reasons are below. Appendix A holds 59 plates of what was captured.

StatusSurfaceWhat that means
CapturedThread statesWorking, streaming, thinking, tool calls, work groups open and closed, tool output, plan, todo list, approvals, questions, secret and link requests, retry, provider error, usage limit, compaction, handoff, interrupt, turn folds, minimap, find bar, markdown blocks, draft hero.
CapturedComposer and menusSlash, at and skill menus, typed text, permission menu, model picker with effort.
CapturedDiff panelCollapsed, stacked, split, maximized.
CapturedTerminalDrawer and right panel tab.
Partly capturedRight panel tabsEmpty state, add menu, files, terminal, diff. Pull request and linked pull requests stay disabled until a thread has a linked record; the same panel is covered on the pull requests page.
Partly capturedFilesTree, source, markdown, CSV, picker and project search. PDF, Office, notebook, audio, font, image and binary previews had no sample files.
Partly capturedPull requestsList, filters, detail, timeline, code, checks popover. Guide tab and stack layers need generation and stack data the harness does not fake.
CapturedSettingsAll 22 routes, settings search, add theme, theme editor, add provider wizard, add environment, new task, add keybinding. Secrets is behind a feature flag and redirects.
Partly capturedTheme importThe add theme control was captured. The capture script did not find the import item, so the import dialog was not seen.
CapturedOnboardingWelcome wizard, three steps. Device setup dialog.
CapturedOverlaysPalette root, search and themes, thread actions, branch picker, snooze menu, hover card, toasts and their stack.
CapturedUsageCost, tokens, limits.
Partly capturedConnection and errorsConnection lost banner, crash screen, boot splash, settings skeletons, link dead end. Pairing and sign-in screens redirect once connected, and this study signs in to nothing.
ReferencedSidebarReferenced from the earlier study. The Boring sidebar option was captured here once.
Not reachedBrowser and previewHosted by Electron or a server browser. The harness has neither, and no page loads.
Not reachedDevice workspacePast the setup dialog it needs simulators.
Not reachedSide chatThe click asks the server to fork a thread, and the fake server does not.
Not reachedMCP app frame, HTML render dialog, worktree setup card, selection toolbar, citationsThe harness does not seed these, so they stayed unseen.
Not reachedDesktop chromeWindow controls, quit overlay, SSH prompt and SnapShot need Electron, which would start T3's real server, so I did not run or review them.
Not reachedapps/mobileIt cannot run here, and I did not review it from code.

Light mode was checked on four screens and showed no serious break. 1024, 1280, 1920 and 2560 px wide showed no horizontal overflow on the screens tested, and 200% zoom held on the approval thread and General settings.

2Scores

Scored on eight design parameters. Scores are my judgment, weighted by what someone running many agents does most. 7 to 8 means small fixes only. 5 to 6 means it works, with visible problems. Questions score 6 and are the third place an agent stops.

Overall7 / 10
Typography7 / 10
Hierarchy6 / 10
Spacing and density7 / 10
Color and contrast7 / 10
Iconography8 / 10
Consistency and polish7 / 10
Clarity6 / 10
Approvals and failures score lowest
0510Thread, working and tools: 8 out of 10Thread, working and tools8Plan and markdown: 8 out of 10Plan and markdown8Usage limit state: 8 out of 10Usage limit state8Onboarding and wizards: 8 out of 10Onboarding and wizards8Command palette: 8 out of 10Command palette8Usage page: 8 out of 10Usage page8Composer and menus: 7 out of 10Composer and menus7Model picker: 7 out of 10Model picker7Diff panel: 7 out of 10Diff panel7Right panel: 7 out of 10Right panel7Files: 7 out of 10Files7Pull requests: 7 out of 10Pull requests7Settings: 7 out of 10Settings7Theme editor: 7 out of 10Theme editor7Connection and crash screens: 7 out of 10Connection and crash screens7Questions: 6 out of 10Questions6Terminal: 6 out of 10Terminal6Toasts: 6 out of 10Toasts6Sidebar (earlier study): 6 out of 10Sidebar (earlier study)6Approvals: 5 out of 10Approvals5Errors and failures: 5 out of 10Errors and failures5
Fig. 2.1 Overall score out of 10 per surface. Reviewer judgment, from review.md. The sidebar score comes from the earlier study.

3Measurements

Every number here comes from the rendered app at commit 337c5858, read through the DOM or Chrome's performance metrics.

Type sizes in use

Thirteen sizes across 104 states, drawn at real size with the number of text nodes under each. It reads as a two-size system, 12 and 14 px, with a tail. The 8.25 px nodes are the project monogram.

CheckMeasuredReading
Contrast172 failures under AA across all 104 states, in 36 of them; 27 are decorative marks such as middle dots. Worst real text: #5c5c5c on #232323, 2.36:1, the 10 px tags in the branch picker.The command palette holds the most, 49 on one screen, mostly #717171 at 4.3:1. Hidden hover controls and shimmer text were excluded as false readings.
TargetsUnder 24 px: Unpin 12×12, Checks 14×14, tab Close 16×16, Allow 29×16, Deny 28×16, Settle 61×20, Snooze 24×20. Up to 30 of 72 controls on one screen.Most are secondary. Allow and Deny are not.
Spacing93 to 98% of padding, margin and gap values on a 2 px grid; 47 to 55% on 4 px. 6 and 10 px are common.T3's scale is consistent and finer than 4 px. The settings column holds 896 px on 21 of 22 pages; Diagnostics widens to 1026 px.
Styles for one jobUp to 22 button combinations of height, size, weight, radius and fill on one screen (model picker open), 21 on pull request detail. Up to 10 radii.The busiest screens carry the most variety. Variety alone is no defect, so I left it.
IconsOne set, lucide. 12, 14 and 16 px nearly everywhere; one 18 px on the thread.This held on every screen I looked at.
KeyboardForward Tab loops 16 stops and skips the conversation. Shift+Tab from the composer lands on Deny, then Allow. F6 moves through 4 named regions; from the conversation region Allow is 5 Tabs in.F6 regions are good. Nothing on screen tells you they exist.
Motion and paintWorking thread: 1 running animation, 62.4 style recalculations per second, 20.2 ms main-thread task per second, over 10 seconds. Idle: 0 animations, 0 recalculations. Reduced motion: 0 running animations. Up to 7 backdrop blur layers with toasts open.The shine runs in 30 steps and pauses off screen, which caps its cost. T3 ships no motion library, though 6 transition-all sites remain.

4Fault finding

Ranked by how much each change helps someone running many agents, then by cost. Every After image labeled capture comes from T3 running that branch. Mocks are labeled mock, and this page has no recreated images.

RankFaultBuiltRouteCarry cost
R1The sidebar buries who needs youEarlier study, variation-aNeeds approvalNot measured
R2Approvals look like a footnotesweep/approval-actionsNeeds approval High
R3The number keys beside each option do nothingsweep/question-keysFocused fix Low
R4A failure banner covers the first messagesweep/error-bannerFocused fix High
R5Nothing tells a background window that an agent waitssweep/title-countNeeds approval Low
R6A retryable failure offers no retryNot built, mock onlyNeeds approvalNone yet
R7Notifications start offNot builtNeeds approvalNone yet
R8Dim text fails AA in the palette and diagnosticssweep/contrastFocused fix Medium
R9Terminal actions cover the first linesweep/terminal-actionsFocused fix Low
R10Small targetssweep/hit-areasFocused fix Medium
R11Settings says Applying settings where nothing appliessweep/settings-scopeFocused fix Medium
R12A dead end at /newNot builtFocused fixNone yet
R1

The sidebar buries who needs you

Symptom
Threads change sections when their state changes, and a thread blocked on you reads quieter than a finished one.
Cause
Covered in the earlier study, with its own captures and two built variations.
Remedy
Keep threads in place and make needs-you the loudest thing in the list. The earlier study built this (Fig. 4.1), so I did not rebuild it.

Built in the earlier study, carry cost not measured here. Needs approval. variation-a, earlier clone

Before capture

After capture

Fig. 4.1 Both from the earlier study at the same T3 commit: the default sidebar and its variation A, branch variation-a.

Variation A adds a Waiting on you list at the top, keeps threads under their projects when their state changes, and puts Allow, Deny and question options on the row.

It remains the biggest single change for someone running many agents, which is why it stays first here. The study compares two variations in full: the sidebar study. Its branches live in that study's clone and were not touched. Its numbers are not repeated on this page.

R2

Approvals look like a footnote

Symptom
Allow and Deny are 16 px tall text links. The headline says Working for. The red Stop is the loudest control while the agent waits for you.
Cause
The inline row uses InlineButton, and WorkingTimelineRow ignores the awaitingUser flag it already receives.
Remedy
Use T3's own Button size xs, which the composer presentation already had. Headline says Waiting for you. Stop turns neutral while waiting and goes red on hover (Fig. 4.2 to 4.4).

Carry cost: High. Needs approval. sweep/approval-actions

Before capture main

After capture sweep/approval-actions

Fig. 4.2 The approval row. (1) The headline stops saying Working for. (2) Allow and Deny go from 29×16 and 28×16 px to 45×24 and 44×24 px, and keep their place in the Shift+Tab order.

Before capture main

After capture sweep/approval-actions

Fig. 4.3 Stop goes neutral while the thread waits on you.

Before capture main

After capture sweep/approval-actions

Fig. 4.4 The same fix where a parent shows a worker's approval above the composer.
R3

The number keys beside each option do nothing

Symptom
Each option shows a badge, 1, 2, 3. Press 1 on a fresh thread and a 1 lands in the answer box.
Cause
The composer takes focus on load, and the shortcut handler returns early for any contenteditable target.
Remedy
Skip the shortcut only when the answer box holds text. Typing after any other character still works: Use 2 fields stays intact (Fig. 4.5).

Carry cost: Low. Focused fix. sweep/question-keys

Before capture main, 1/3

After capture sweep/question-keys, 2/3

Fig. 4.5 Pressing 1 on a three-question prompt. Before, the digit goes into the box and the prompt stays on 1/3. After, CSV is chosen and the prompt moves to 2/3. (1) The digit in the box. (2) The counter.
      if (target instanceof HTMLElement) {
        const editor = target.closest('[contenteditable]:not([contenteditable="false"])');
        if (editor?.textContent?.trim()) return;
      }
R4

A failure banner covers the first message

Symptom
After a provider error, a floating banner sits on top of the first user message and repeats the row already in the timeline.
Cause
The banner lane is absolutely positioned at the top of the thread, and only usage limits were excluded from it.
Remedy
Skip the floating copy when a classified failure already has its timeline row. ChatGPT limit banners keep their action buttons (Fig. 4.6).

Carry cost: High. Focused fix. sweep/error-banner

Before capture main

After capture sweep/error-banner

Fig. 4.6 A provider error. (1) The banner over the message. (2) The row that already says the same thing.
R5

Nothing tells a background window that an agent waits

Symptom
With T3 in another tab or behind another window, the title stays T3 Code (Beta) however many agents wait.
Cause
startThreadNotifications only watches threads when a notification mode is on, and both default to off, so the favicon badge stays off too.
Remedy
Put the count of threads waiting on you in the title. It needs no permission and works with notifications off (Fig. 4.7).

Carry cost: Low. Needs approval. sweep/title-count

mock Tab strip drawn for this page. The title strings are measured from document.title.

Fig. 4.7 Five seeded threads wait on approval or input. Settling one drops the count to 4 in the running app. Workers shown under a parent do not count twice.
R6

A retryable failure offers no retry

Symptom
The provider error is marked retryable, yet the row offers only copy and fork.
Cause
The timeline row has no action. The usage limit banner next to it shows what this can look like.
Remedy
Add Retry to the failed row. I did not build it, because it needs a decision on what retrying a run sends to the server (Fig. 4.8).

Not built, so no carry cost. Needs approval.

Before capture main

After mock Drawn in T3's colors for this page.

Fig. 4.8 The failed row, with a Retry action in the mock. The Before crop comes from the branch that removes the banner, so the row reads alone.
R7

Notifications start off

Symptom
A fresh install has thread notifications off and in-app notifications off (Fig. 4.9).
Cause
Both defaults in settings.ts. Sounds, toasts and the badges all depend on them.
Remedy
Ask once, the first time a thread needs you while the window is unfocused. I did not build it, because a product default is T3's to choose.

Not built, so no carry cost. Needs approval.

capture Before. After: not built.

Fig. 4.9 Settings, General, as a new user finds it.
R8

Dim text fails AA in the palette and diagnostics

Symptom
Thread rows in the palette, the keybinding When labels and Diagnostics read at 2.9 to 4.3:1.
Cause
text-muted-foreground/55 to /70 on 10 to 12 px text.
Remedy
Raise those to /75. In a sample of 11 surfaces, a subset of chapter 3's 104 states, failures fall from 82 to 30. 20 of the 30 are middle dots, left alone as decoration (Fig. 4.10).

Carry cost: Medium. Focused fix. sweep/contrast

Before capture main

After capture sweep/contrast

Fig. 4.10 Palette results. Subtitles go from #717171 to a lighter step that passes 4.5:1, a difference you measure more than see.
R9

Terminal actions cover the first line

Symptom
In the right panel the Split, New and Delete group sits on top of the first terminal line and cuts it off.
Cause
The group is absolutely positioned over the terminal, always visible.
Remedy
Show it when the pointer is in the terminal or a button has focus. 100 ms opacity, hover gated, keyboard still reaches it (Fig. 4.11, 4.12).

Carry cost: Low. Focused fix. sweep/terminal-actions

Before capture main

After capture sweep/terminal-actions

Fig. 4.11 Pointer outside the terminal. (1) Before, the group cuts off the command. After, the command reads in full.

capture sweep/terminal-actions, hover

Fig. 4.12 The same panel with the pointer inside the terminal: the actions fade in over the same spot. The overlap remains while hovering.
R10

Small targets

Symptom
Several secondary targets are under the 24 px minimum.
Cause
Compact sizes from a dense row layout.
Remedy
Grow them with pseudo-elements, with no visual change. Measured by walking elementFromPoint out from each center.

Carry cost: Medium. Focused fix. sweep/hit-areas

TargetDrawnHit area beforeHit area after
Allow, inline29×1630×1634×24
Deny, inline28×1629×1633×24
Unpin thread12×1212×1224×24
Snooze thread24×2024×2024×24
Close tab16×1616×1624×24
Settle thread61×2041×2041×20, unchanged

Pixels, from a script on the running app. Images would look identical, so none are shown. Settle's pseudo-element did not extend its hit area, and part of its width is taken by Snooze. Checks (14×14) and setting source (20×20) were measured before and left alone.

R11

Settings says Applying settings where nothing applies

Symptom
Open source licenses, Archive and Diagnostics all open with Applying settings for All projects across All environments.
Cause
The sentence shows on every route not in its device-only list.
Remedy
Drop it on licenses. Say Showing on Archive and Diagnostics, where it filters a list (Fig. 4.13, 4.14).

Carry cost: Medium. Focused fix. sweep/settings-scope

Before capture main

After capture sweep/settings-scope

Fig. 4.13 Open source licenses. (1) The sentence with nothing to apply is gone.

Before capture main

After capture sweep/settings-scope

Fig. 4.14 Archive says what the control does.
R12

A dead end at /new

Symptom
Opening /new with no prompt shows Could not open the link. This link has no prompt, with no way forward (Fig. 4.15).
Cause
The route is a prompt link landing, and its empty case has no action.
Remedy
Add a New thread button. I did not build this one.

Not built, so no carry cost. Focused fix.

capture Before. After: not built.

Fig. 4.15 The empty link landing.

5What T3 already does well

Keep all of this. I would guess several of these took more work than anything in chapter 4.

capture

Fig. 5.1 The usage limit state names the reset time and offers Resume at reset and Snooze until reset. It is the best-resolved blocked state in the app, and the model for R2 and R6.

capture

Fig. 5.2 Losing the server gets a plain banner above the composer, not a takeover.

capture

Fig. 5.3 An empty panel teaches itself: every surface listed with its shortcut.

capture

Fig. 5.4 The palette puts shortcuts next to actions and scopes New thread to the current project.
  • State is never color alone. Approval, Input, Failed, Limited and Done each have an icon and a word.
  • Work folds into one sentence. Ran 2 commands, changed 3 files, and performed 4 other actions beats any list.
  • F6 moves between named regions. Sidebar, conversation, composer, details.
  • The composer warns before it acts. Send feedback to decline this request states the consequence in the placeholder.
  • Layouts survive. No horizontal overflow from 1024 to 2560 px, and the composer folds labels before it clips them.
  • Motion is cheap and respectful. Stepped shine, paused off screen, no motion library, nothing running under reduced motion.
  • The onboarding wizard is short and honest. Three steps, and it says what is ready.

6What each change costs to carry

T3 moves fast. The request for this study counts 4,151 commits in the four weeks to Nov 5. My clone counts 4,407 first-parent commits since Oct 8, and I did not reconcile the two. Either way, a patch held outside T3 meets new code every day, so I measured how often T3 touched the same files and whether each patch still applies to older commits.

Applies back shows the oldest of four commits, 7, 14, 21 and 28 days back, where the patch still applies. Fails at 7 means those lines changed in the past week. Carry cost is a rule, not a feeling. High means a touched file took 90 or more commits in four weeks. Medium means the patch fails at 7 days. Low means it applies at 7 days or further.

T3 could accept as a focused fix

T3's guide says "Focused bug fixes, reliability fixes, performance improvements, and maintenance work are the most likely to be accepted," and that a very small fix for an obvious bug can go without a prior issue. That route still needs before and after screenshots, one problem per PR, and evidence of how it was checked. This grouping is my reading of the guide. T3 decides, and it may close or reimplement anything.

RankChangeFilesLinesBusiest touched file, commits in 4 weeksApplies backCarry cost
R3sweep/question-keysAn empty answer box can no longer take a leading digit as text. T3 may want a say on that.1+4 / −516 ComposerPendingUserInputPanel28 days Low
R4sweep/error-bannerA small change, in T3's busiest file.1+8 / −1200 ChatViewFails at 7 High
R8sweep/contrastA mechanical change that should stay in one PR about one problem.5+34 / −3412 KeybindingsSettingsFails at 7 Medium
R9sweep/terminal-actionsHides actions until hover or focus, which T3 could read as a behavior choice.1+2 / −225 ThreadTerminalDrawer7 days Low
R10sweep/hit-areasNothing changes visually, and Settle stays 20 px tall.3+5 / −525 SidebarThreadRowFails at 7 Medium
R11sweep/settings-scopeThis changes wording and nothing else.1+9 / −19 SettingsScopeSentenceFails at 7 Medium
R12Not builtIt would add one button to an empty page, and T3 would need before and after screenshots.This clone has no patch for it, so there is nothing to measure.

Needs T3's approval first

The guide says "features and intentional changes to product behavior require a prior discussion with explicit maintainer approval of the direction and scope." These change what the product does or how it ranks a decision.

RankChangeFilesLinesBusiest touched file, commits in 4 weeksApplies backCarry cost
R1Built in the earlier studyA new list and new row actions. Its size is in that study, not measured here.This clone has no patch for it, so there is nothing to measure.
R2sweep/approval-actionsChanges the hierarchy of a core decision.6+20 / −1095 ChatComposerFails at 7 High
R5sweep/title-countAdds a new behavior, however small.1+41 / −117 appInit7 days Low
R6Not builtIt first needs a decision on what a retry sends to the server.This clone has no patch for it, so there is nothing to measure.
R7Not builtIt would change a product default.This clone has no patch for it, so there is nothing to measure.

Commits per file: git rev-list --count --since=2026-10-08 337c5858 -- file. Apply check: git apply --cached --check --recount against first-parent commits. The check measures recent churn around the lines, which is a proxy for future conflicts, not a prediction. Bars share one scale, 0 to 200 commits. Upstream main was still 337c5858 when I last fetched. Nothing was pushed, and no PR, issue or discussion was opened.

7Method and limits

How the captures were made. T3's web app ran from a sealed clone with a temporary home, no telemetry and no agent logins, in headless Chromium at 1440×900. A fake socket adapted from apps/web/test/fakeEnvironment.ts supplied the seeded threads, diffs, pull requests and usage. No agent ran.

Labels. Capture is a screenshot of the running app. Mock is drawn for this page: two here, the tab strip in R5 and the retry row in R6. This page has no recreated images.

Checks on the patches. On the combined branch sweep/all, TypeScript and the formatter pass. T3's ThreadErrorBanner unit test passes. I did not run T3's full test suite or its browser tests.

Known limits. Type renders in a fallback font on Linux, since T3's stack starts with -apple-system. Seeded data is tidier than real use. Scores are one reviewer's judgment. No user was watched and no screen reader was run.

Sources. inventory.md, review.md, shots/ and patches/ in ~/presentations/.work/t3-sweep. T3 Code is pingdotgg/t3code, MIT license, commit 337c5858c33bc7f8f6dfd391a2c279fa0f7e4d17.

This is an unofficial design study. It was not made by or endorsed by T3.

APlates

Every plate is a capture from the running app at commit 337c5858. Select one to see it at full size.

Thread

Plate 1 Streaming
Plate 2 Thinking
Plate 3 Work group, tool output
Plate 4 Plan
Plate 5 Question
Plate 6 Secret and link requests
Plate 7 Retrying
Plate 8 Compaction and handoff
Plate 9 Turn folds, minimap
Plate 10 Markdown blocks
Plate 11 Parent with workers
Plate 12 Find bar

Composer and pickers

Plate 13 Draft hero
Plate 14 Slash menu
Plate 15 Permissions
Plate 16 Model picker
Plate 17 Branch picker
Plate 18 Thread actions

Panels

Plate 19 Diff, stacked
Plate 20 Diff, split
Plate 21 Diff, maximized
Plate 22 Right panel, empty
Plate 23 Files tree
Plate 24 Markdown preview
Plate 25 CSV preview
Plate 26 Terminal drawer
Plate 27 Device setup

Pull requests and usage

Plate 28 List
Plate 29 Filters
Plate 30 Detail
Plate 31 Timeline
Plate 32 Code
Plate 33 Checks
Plate 34 Usage, cost
Plate 35 Usage, tokens

Settings

Plate 36 General
Plate 37 Appearance
Plate 38 Keybindings
Plate 39 Providers
Plate 40 Threads
Plate 41 Source control
Plate 42 Scheduled tasks
Plate 43 Diagnostics
Plate 44 Labs
Plate 45 Theme editor
Plate 46 Add provider
Plate 47 New task

Global and edge states

Plate 48 Welcome, connect
Plate 49 Welcome, agents
Plate 50 Palette
Plate 51 Palette, themes
Plate 52 Project search
Plate 53 Toasts
Plate 54 Hover card
Plate 55 Connection lost
Plate 56 Crash screen, forced by bad harness data
Plate 57 Boot splash
Plate 58 Settings skeleton
Plate 59 Boring sidebar option