Linux desktop onboarding doesn't mention the AppArmor browser setup step until browser tools fail#22627

opened17d agobyAareidyOTH

What happened

On Ubuntu 26.04.1 with the default kernel.apparmor_restrict_unprivileged_userns = 1, the desktop AppImage installs, onboards and runs normally, but agent browser tools (preview_open, html_preview) and HTML previews fail because AppArmor blocks the bundled chrome-headless-shell sandbox. The need for a one-time privileged t3 browser setup only shows up when an agent first tries browser work. Running sudo ~/.t3/bin/t3 browser setup installed /etc/apparmor.d/t3-chrome-headless-shell and fixed it. The global restriction stayed enabled, and HTML preview and a sandboxed browser launch then worked.

Diagnosis

  • The server already detects this condition cheaply (PreviewBrowserHost.sandboxBlocked: restriction = 1 and no T3 profile), but at startup it only writes a logWarning (apps/server/src/preview/ServerBrowser.ts). The result isn't sent to the client, and the onboarding flow (WelcomeWizard, FirstRunGate, provider readiness) has no step for it.
  • The setup command comes from resolveHostCliCommand (apps/server/src/cli/invocation.ts), which returns a bare t3 whenever any t3 is on PATH. On this machine that was an older npm global install (0.0.46-nightly) rather than the desktop app's own CLI (~/.t3/bin/t3, 0.1.1-nightly). Agents were told to run sudo env "PATH=$PATH" t3 browser setup, which runs a different install's CLI. That happened to work here, because the profile glob doesn't depend on the version.
  • This matches documented behavior (docs/user/remote-access.md), so it's a discoverability improvement rather than a broken contract.

Steps to reproduce

  1. Use a fresh Ubuntu 23.10+ install (tested on 26.04.1) with the default AppArmor userns restriction and no /etc/apparmor.d/t3-chrome-headless-shell.
  2. Install and launch the T3 Code desktop AppImage, then complete onboarding. No browser prerequisite is mentioned.
  3. Ask an agent to use html_preview or preview_open. It fails with "This host blocks the sandbox T3's browser runs in (AppArmor on Ubuntu 23.10+)…".
  4. Optionally, also install an unrelated t3 on PATH, such as an older npm global. The suggested command then names that t3 instead of the desktop app's ~/.t3/bin/t3.

Expected behavior

  • Onboarding on the desktop app, or a notice before the first browser use, detects the blocked sandbox and explains the one-time privileged setup.
  • The notice gives the setup command for the running install, e.g. sudo ~/.t3/bin/t3 browser setup.
  • The command uses the bare t3 only when that t3 is the same install or version.

Version

Desktop AppImage 0.1.1-nightly.20261020.3438 (from the server's /.well-known/t3/environment). The triage CLI was the unrelated npm t3 0.0.46-nightly.20261013.3053.

Environment

Ubuntu 26.04.1 LTS, x86_64, kernel 7.0.0, Wayland. Desktop AppImage launched from the application menu through a user wrapper that passes --no-sandbox to Electron; that flag doesn't affect the separate agent browser.

Evidence

  • Agent tool result: This host blocks the sandbox T3's browser runs in (AppArmor on Ubuntu 23.10+). Run `sudo env "PATH=$PATH" t3 browser setup` on the host once to allow it, then try again.
  • which -a t3 → ~/.local/bin/t3 (v0.0.46-nightly.20261013.3053); ~/.t3/bin/t3 --version → v0.1.1-nightly.20261020.3438.
  • After setup: ~/.t3/bin/t3 browser setup → "This host is ready for T3's browser."; kernel.apparmor_restrict_unprivileged_userns = 1 still.

#18938 (AppArmor message misreported for a root launch; closed), #1482 (AppImage sandbox on Ubuntu 24.04+; closed).

Fix applied or workaround

sudo ~/.t3/bin/t3 browser setup (installs the AppArmor profile; global restriction left on).

Filed by

Claude Code (Claude Opus 5.5) via t3 triage.

Note

Grok responding on behalf of Julius.

Thanks for the thorough report. It has two parts, and they land differently.

Wrong t3 in the suggested command. Current main matches what you saw. resolveHostCliCommand (apps/server/src/cli/invocation.ts:180-182) returns a bare t3 whenever any t3 is on PATH. It never checks whether that t3 is the running install. It only falls back to the desktop app's own launcher (T3CODE_CLI_PATH, lines 155-164) when no t3 is on PATH at all. The package runner path already guards against a different install by requiring an exact version match (lines 44-62), but the PATH check has no such guard. resolveRootCliCommand (lines 197-206) inherits the bare t3 and wraps it in sudo env "PATH=$PATH". That's how an unrelated older install ended up in the AppArmor message. Accepting this part as a bug.

An onboarding step for the AppArmor setup. As you noted, this matches documented behavior: the server detects the blocked sandbox and tells you the command when browser work first needs it. Surfacing it earlier, during onboarding or before the first browser use, would be new behavior rather than a fix. Please open it in Ideas: https://github.com/pingdotgg/t3code/discussions/new?category=ideas

Running the desktop app's own CLI by its full path, as you did, is the right workaround in the meantime.