Uh oh!
There was an error while loading. Please reload this page.
feat(environments): draw each environment as the machine it runs on - #9299
Conversation
Every remote environment used to wear the same cloud or server glyph, so a Mac mini, a laptop, and a Hetzner VM were indistinguishable in the sidebar, the Run on picker, the pull request filters, and the mobile lists. In the hosted app, where every environment is remote, rows carried no marker at all. Servers now detect their hardware at startup (IOKit product name or hw.model on macOS, DMI chassis type and virtualization markers on Linux) and publish it as platform.machine. A nullable environmentIcon server setting lets the user override it from Settings -> Connections, stored on that server so every device agrees. resolveEnvironmentMachineKind in contracts holds the precedence so web and mobile cannot drift, and platform.machine decodes forward-compatibly so a kind from a newer server falls back to a server glyph instead of failing the descriptor. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
Web previewhttps://t3code-673kpkord-pinglabs.vercel.app (for ca9f250) Open this exact URL — the hosted-app origin is baked in at build time. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
Bugbot Autofix is ON, but a cloud agent failed to start.
Reviewed by Cursor Bugbot for commit b74b5f6. Configure here.
Uh oh!
There was an error while loading. Please reload this page.
ApprovabilityVerdict: Not approved Macroscope's review found this PR not approvable — This PR adds a new persisted environment-icon capability and server-side hardware detection, then changes default icon behavior across web and mobile thread, connection, run-on, and pull-request surfaces. Because existing users receive changed defaults and the implementation spans multiple runtime layers, human review is warranted. Not approved because:
Review your spending limits in Billing settings. You can add or adjust custom eligibility rules. Learn more. |
The environmentIcon setting was a closed NullOr(EnvironmentMachineKind), so an override picked on a newer server would fail the whole ServerSettings decode for an older client, while platform.machine already tolerated unknown kinds. Both now degrade to the generic server glyph. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The picker was live on every connected environment, including servers that predate the setting (which drop the key on write) and sessions without the operate scope. It now stays visible so the current icon still reads, but goes inert with a tooltip in those cases, gated the same way the provider settings are: a new environmentIcon capability on the descriptor, plus the session's scopes for that environment. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.
## What's Changed * chore(ci): only run check-run agents on vouched contributors by @juliusmarminge in pingdotgg/t3code#9298 * fix(web): stop remounting markdown on every activity delta by @juliusmarminge in pingdotgg/t3code#9306 * fix(pull-requests): keep cached PR chrome on reopen by @maria-rcks in pingdotgg/t3code#9294 * feat(environments): draw each environment as the machine it runs on by @juliusmarminge in pingdotgg/t3code#9299 * feat(web): apply and remove labels from the pull request tab by @juliusmarminge in pingdotgg/t3code#9313 * fix(sidebar): collapse settled and snoozed shelves by default by @maria-rcks in pingdotgg/t3code#9314 * refactor(media): unify file and media previews across clients by @juliusmarminge in pingdotgg/t3code#9253 * fix(chat): keep live tool labels in present tense by @maria-rcks in pingdotgg/t3code#9316 * chore: audit lint directives and move plugin allowlists into config by @juliusmarminge in pingdotgg/t3code#9300 * chore(ci): narrow the Effect conventions check-run agent by @juliusmarminge in pingdotgg/t3code#9321 * refactor(mobile): style plain views with Uniwind classes instead of the theme bridge by @juliusmarminge in pingdotgg/t3code#9322 * fix(dev): share dev servers on the loopback Vite actually binds by @juliusmarminge in pingdotgg/t3code#9324 * fix(web): line up the titlebar wordmark label and version pill by @tristanmanchester in pingdotgg/t3code#9255 * fix(web): make the diff layout toggle a persisted setting by @juliusmarminge in pingdotgg/t3code#9326 * chore: dedupe lightningcss and tailwind node bindings by @juliusmarminge in pingdotgg/t3code#9331 * chore: upgrade vite-plus to 0.3.0 by @juliusmarminge in pingdotgg/t3code#9327 * feat(web): add a file tree to the diff panel and pull request code tab by @juliusmarminge in pingdotgg/t3code#9330 * feat(web): add PageUp/PageDown chat navigation by @Yash-Singh1 in pingdotgg/t3code#9315 * fix(web): collapse PR header actions to icons when narrow by @maria-rcks in pingdotgg/t3code#9334 * fix(web): resolve Vite sourcemap and supports warnings by @juliusmarminge in pingdotgg/t3code#9343 * feat(web): choose whether links open in the default browser or in T3 Code by @juliusmarminge in pingdotgg/t3code#9339 * fix(web): add press feedback to buttons by @maria-rcks in pingdotgg/t3code#9349 * feat(web): add customizable project icons by @saphid in pingdotgg/t3code#9137 * fix(mobile): stop indented code overflowing Android chat bubbles by @Adamulek123 in pingdotgg/t3code#9347 * fix(web): let the pull request list use wide screens by @juliusmarminge in pingdotgg/t3code#9351 * feat: display native app and browser icons in work logs by @Yash-Singh1 in pingdotgg/t3code#9093 ## New Contributors * @tristanmanchester made their first contribution in pingdotgg/t3code#9255 **Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260903.1262...v0.0.39-nightly.20260903.1265 Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260903.1265

Problem
Every remote environment wore the same glyph (a cloud in the sidebar, a server elsewhere), so a Mac mini, a MacBook, and a Hetzner VM were indistinguishable in the thread list, the "Run on" picker, the pull request server filter, and the mobile lists. In the hosted web app, where there is no local environment, thread rows carried no marker at all.
Fix
Each environment is now drawn as the machine it runs on, from a fixed set: server, cloud VM, desktop, laptop, Mac mini, Mac Studio.
hw.modelon Intel Macs) or, on Linux, the DMI chassis type plus vendor/product strings, with hypervisor and cloud markers mapping to "cloud". The result ships asplatform.machineon the environment descriptor; absent when there is no signal (Windows, containers, unknown DMI).environmentIconserver setting, picked in Settings → Connections. It lives on the server rather than the client so every device connecting to that environment sees the same icon. The picker reads "Automatic (Mac mini)" so you can tell whether detection got it right before overriding.resolveEnvironmentMachineKindin contracts holds the precedence (override → detected → generic server) so web and mobile cannot drift.platform.machinedecodes forward-compatibly: a kind from a newer server falls back to the generic glyph instead of failing the descriptor.Lucide has no Apple desktops, so Mac mini and Mac Studio are drawn in its grammar. On iOS the SF Symbols
macminiandmacstudioare used; Android falls back to the closest Tabler silhouettes.Icons
Server · Mac mini · Mac Studio · Desktop · Laptop (cloud is lucide's stock icon)
Verification
mac-mini, a GMKtec NucBox on Linux resolvesdesktop.Built with Claude Fable 5 in Claude Code.
🤖 Generated with Claude Code
Note
Low Risk
Presentation and optional server settings with best-effort hardware probes that fail safely to null; forward-compatible schema handling limits version-skew breakage.
Overview
Environments are no longer shown as a generic cloud/server everywhere. Each one can display a machine glyph (server, cloud VM, desktop, laptop, Mac mini, Mac Studio) derived from hardware detection, an optional user override, or a generic server fallback.
Server & contracts: Startup detection fills
environment.platform.machine(macOS IOKit/hw.model, Linux DMI with VM→cloud heuristics) and advertises anenvironmentIconcapability. A nullablesettings.environmentIconoverride is stored on the server so all clients agree.resolveEnvironmentMachineKindcentralizes precedence (override → detected →"server"), with forward-compatible decoding for unknown kinds.Clients: Web and mobile add shared icon components (
EnvironmentMachineIcon/EnvironmentMachineSymbol) plus an Environment icon picker in Connections (gated on connect, server version, and operate access). Thread sidebars, connection rows, composer “Run on”, and pull-request server pickers/filters now use these glyphs instead of one-size-fits-all icons; remote-thread markers also apply when the primary environment differs (including hosted/mobile where every row is remote).Reviewed by Cursor Bugbot for commit ca9f250. Bugbot is set up for automated code reviews on this repo. Configure here.