T3 Code Browser Headless Shell and Sandbox Environment¶
Status: Accepted (Amends ADR 0003 and ADR 0025)
We pre-bake headless Chromium system libraries and fonts into the Shared Base Image, update browser_enabled to treat --t3 as an active browser capability, pre-initialize T3 Code's browser during image build via t3 browser setup, and configure T3CODE_SERVER_BROWSER_SANDBOX=0 inside the container startup script so T3 Code's built-in browser panel functions seamlessly in root sandbox containers.
Context¶
T3 Code (pingdotgg/t3code) ships with a dedicated embedded web preview browser in its right panel backed by headless Chromium (chrome-headless-shell managed under /root/.t3/tools/chrome-headless-shell/).
When developers attempted to open the "Browser" panel inside Modal sandboxes launched with --t3, T3 Code failed with:
This server's host is missing libraries its browser needs. Run this once on the host, then try again:
sudo env "PATH=$PATH" t3 browser setup
Investigation revealed two root causes:
- Missing Dynamic Shared Libraries: The
base_imageinshared/image.py(Ubuntu 24.04) omitted the system libraries and fonts required by headless Chromium/Chrome (libnspr4,libnss3,libatk-1.0,libatk-bridge2.0,libatspi2.0,libxcomposite1,libxdamage1,libxfixes3,libxrandr2,libgbm1,libxkbcommon0,libasound2,fontconfig,fonts-liberation). Whent3 serveprobedchrome-headless-shell --version, the dynamic linker (ld.so) failed immediately witherror while loading shared libraries: libnspr4.so. T3 Code'sPreviewBrowserHostdetected missing libraries vialddand emittedPreviewBrowserLibrariesError. Furthermore,browser_enabled()only checkedbrowser,opencode, andagy, omittingt3. - Root User Sandbox Restriction in Containers: In Modal container sandboxes, all processes run as
root(uid=0). Chrome's security model forbids starting the Linux zygote sandbox asrootwithout--no-sandbox(Running as root without --no-sandbox is not supported). WithoutT3CODE_SERVER_BROWSER_SANDBOX=0set in the server's environment, T3 Code refuses to start the browser and reportsPreviewBrowserRootError.
Decisions¶
- Pre-bake Chrome System Libraries and Fonts in Shared Base Image:
- In
shared/image.py, addlibnss3,libatk1.0-0t64,libatk-bridge2.0-0t64,libatspi2.0-0t64,libdbus-1-3,libx11-6,libxcb1,libxcomposite1,libxdamage1,libxext6,libxfixes3,libxrandr2,libxkbcommon0,libgbm1,libasound2t64,libexpat1,fontconfig, andfonts-liberationtobase_image.apt_install(). -
Pre-baking these packages into the shared base image ensures zero runtime apt overhead and avoids network latency or transient package repository failures on fresh sandbox boots.
-
Expand
browser_enabledto Include--t3: -
Update
browser_enabled(browser=browser, opencode=opencode, agy=agy, t3=t3)inshared/image.pyandsandbox/launcher.py. Launching with--t3automatically implies browser readiness, activatesENABLE_BROWSER=1, and advertisesBrowserin the launch banner. -
Pre-validate Browser Setup during Image Build:
-
In
shared/image.pyunder theif t3:build layer, invoke/opt/t3/t3 browser setup. This ensures T3's browser dependencies are validated and pre-configured at Modal image build time. -
Export
T3CODE_SERVER_BROWSER_SANDBOX=0for Root Containers: - In
shared/startup.sh, exportT3CODE_SERVER_BROWSER_SANDBOX=0beforenohup t3 serve ...and persist it to/etc/environmentand~/.bashrc. This allows Chrome headless shell to execute asrootwithout failing on unprivileged user namespace checks. - Updated
/usr/local/bin/check-t3to print the browser sandbox environment state (T3CODE_SERVER_BROWSER_SANDBOX).
Consequences¶
- The embedded "Browser" panel and preview browser tabs in T3 Code WebUI open immediately without requiring manual
t3 browser setupexecution. - Sandboxes launched with
--t3inherit browser tooling out of the box. - All files remain compliant with universal file line limits (ADR 0027 / AGENTS.md).