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.
Overall
7 / 10 across 21 surfaces
Evidence
104 states audited at 1440×900, default dark
Patches
8 branches. 6 have After captures, R5 a mock, R10 a measured table
T3 commit
337c5858, 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
Still says Working for, though the agent has stopped.
Allow is a 29×16 px text link, Deny 28×16.
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.
Status
Surface
What that means
Captured
Thread states
Working, 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.
Captured
Composer and menus
Slash, at and skill menus, typed text, permission menu, model picker with effort.
Captured
Diff panel
Collapsed, stacked, split, maximized.
Captured
Terminal
Drawer and right panel tab.
Partly captured
Right panel tabs
Empty 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 captured
Files
Tree, source, markdown, CSV, picker and project search. PDF, Office, notebook, audio, font, image and binary previews had no sample files.
Partly captured
Pull requests
List, filters, detail, timeline, code, checks popover. Guide tab and stack layers need generation and stack data the harness does not fake.
Captured
Settings
All 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 captured
Theme import
The add theme control was captured. The capture script did not find the import item, so the import dialog was not seen.
Captured
Onboarding
Welcome wizard, three steps. Device setup dialog.
Captured
Overlays
Palette root, search and themes, thread actions, branch picker, snooze menu, hover card, toasts and their stack.
Captured
Usage
Cost, tokens, limits.
Partly captured
Connection and errors
Connection 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.
Referenced
Sidebar
Referenced from the earlier study. The Boring sidebar option was captured here once.
Not reached
Browser and preview
Hosted by Electron or a server browser. The harness has neither, and no page loads.
Not reached
Device workspace
Past the setup dialog it needs simulators.
Not reached
Side chat
The click asks the server to fork a thread, and the fake server does not.
The harness does not seed these, so they stayed unseen.
Not reached
Desktop chrome
Window 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 reached
apps/mobile
It 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.
Overall
7 / 10
Typography
7 / 10
Hierarchy
6 / 10
Spacing and density
7 / 10
Color and contrast
7 / 10
Iconography
8 / 10
Consistency and polish
7 / 10
Clarity
6 / 10
Approvals and failures score lowestFig. 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.
Aa8.25583
Aa1092
Aa11173
Aa11.953
Aa123,430
Aa13305
Aa142,533
Aa1674
Aa1827
Aa209
Aa2412
Aa304
Aa362
Check
Measured
Reading
Contrast
172 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.
Targets
Under 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.
Spacing
93 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 job
Up 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.
Icons
One set, lucide. 12, 14 and 16 px nearly everywhere; one 18 px on the thread.
This held on every screen I looked at.
Keyboard
Forward 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 paint
Working 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.
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
Beforecapture
Aftercapture
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).
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.
Beforecapturemain
Aftercapturesweep/approval-actions
Fig. 4.3 Stop goes neutral while the thread waits on you.
Beforecapturemain
Aftercapturesweep/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
Beforecapturemain, 1/3
Aftercapturesweep/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
Beforecapturemain
Aftercapturesweep/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
mockTab strip drawn for this page. The title strings are measured from document.title.
BeforeT3 Code (Beta)
After(5) T3 Code (Beta)
One answered(4) T3 Code (Beta)
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.
Beforecapturemain
AftermockDrawn in T3's colors for this page.
Provider error
The model provider returned an internal error (500). Your work up to this point is saved.
RetryFork from here
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.
captureBefore. 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
Beforecapturemain
Aftercapturesweep/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).
Fig. 4.11 Pointer outside the terminal. (1) Before, the group cuts off the command. After, the command reads in full.
capturesweep/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
Target
Drawn
Hit area before
Hit area after
Allow, inline
29×16
30×16
34×24
Deny, inline
28×16
29×16
33×24
Unpin thread
12×12
12×12
24×24
Snooze thread
24×20
24×20
24×24
Close tab
16×16
16×16
24×24
Settle thread
61×20
41×20
41×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).
Fig. 4.13 Open source licenses. (1) The sentence with nothing to apply is gone.
Beforecapturemain
Aftercapturesweep/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.
captureBefore. 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.
Not 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.
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 StreamingPlate 2 ThinkingPlate 3 Work group, tool outputPlate 4 PlanPlate 5 QuestionPlate 6 Secret and link requestsPlate 7 RetryingPlate 8 Compaction and handoffPlate 9 Turn folds, minimapPlate 10 Markdown blocksPlate 11 Parent with workersPlate 12 Find bar