feat(cmux-next): Labs flags, one registry for opt-in looks and behaviors (hq#1980, no bead)
Summary
Labs (hq#1980): new looks and behaviors ship behind a flag that a person turns on, not in the defaults. This builds on the existing labs.previewFeatures and keeps it as the only mechanism. Its users (#20429's Now Playing card) keep reading snapshot.previewFeatures.
- Registry: each row of
schemas/settings/source/labs.jsonis aLabsFlagwithowner,created,expires(about 14 days),cohort(off/nightly-next/default) and a one-line intent (itshelp).gen-settings-sources.pychecks the fields and generates the SwiftLabsFlagenum andwebviews/src/experiments/labs.generated.ts. It printswarning: labs.<name> ... expiredfor any flag past its expiry, including under--check; the warning never fails the run. - Defaults: every flag defaults off.
nightly-nextflags are on in nightly and dev builds only. Promoting a flag todefaultis a one-line PR, and that PR is the design call. - Where flags show up: Settings > Experimental > Labs (a toggle with the intent line), the palette's settings scope, Help > Feature Flags (now bound, opens that list), cmux.json, MDM, and the agent policy.
- New Tab page, team builds only: one quiet line, "Labs" (or "Labs (N on)"), on the page's column edges and type scale, collapsed by default and remembered per viewer. Open, it lists each flag as a 28px row: name, one-line intent (truncated before the badge), a "New" or "Expires soon" hint, and a switch; recently toggled first, else newest. Right-click a row for Turn On/Off and All Labs…. "All Labs…" opens Settings > Labs. A toggle is
newTab.setLab, saved through the schema. Release and RC builds show nothing. Variant A of three, picked by cg-design-judge (https://github.com/manaflow-ai/cmux/pull/20452#issuecomment-6180365005). - Palette: "Labs…" (Help > Feature Flags is now Help > Labs…; "feature flags" stays a search keyword) opens Settings > Labs.
- One helper per side:
- Swift:
snapshot.lab(.name). - Web:
useLabsFlag("name")/labsFlag("name"), which readdata-labson<html>. EveryPageWebViewpage gets that attribute, kept current.labsTeamBuild()readsdata-labs-team.
- Swift:
- Docs:
skills/cmux-architecture/references/labs-flags.mdexplains how to put a change behind Labs.
Testing
-
Swift
LabsFlagTests: the cohort and file decide a flag, a bad value is off with a diagnostic, and every flag is a toggle with its fields.NewTabLabsTests: a page toggle is saved in cmux.json, and a name that is not a flag writes nothing; All Labs… runshelp.featureFlags.- Red: the fleet
run-swift-testing-suites.shat the red commits fails (no member 'lab'; the New Tab red is a compile red, since its API did not exist yet). - Green: fleet
run-swift-testing-suites.shon the merged head 18a0888e: 288 suites passed, 0 failed (the step exits 1 only becauseAcpmuxBundleReplacedTestsskips without a published same-tree cmux-tui for that SHA). - Settings export on the merged head: no diff (
exportIsFreshpasses).
-
Web:
bun test test/new-tab-labs.test.tsxwas red at e59433fd (no section) and is green now.src/experiments/labs.test.tspasses. -
Checks:
gen-settings-sources.py --check,gen-strings.mjs --check agentPane, ui-rules, and scopedvp checkpass.- In
bun run check, every step before the final whole-repovp checkpasses. That last lint was killed on big-red (143); CI react-apps-check covers it. - crash ratchet, concurrency, system-blue and the scoped god-file check pass. App size is at the cap (113801).
-
Review (subagent): the agent pane's own web view (
agent.pageHostoff, the default) never gotdata-labs; fixed withAgentPaneLabs. The generator now rejects a key that is notlabs.<name>. Known limit: a page's first moments can carry the flag list from when its web view was made;useLabsFlagfollows the live value. -
Localization: the two new New Tab strings are in all 21 locales. Flag intents show in English on the New Tab page (team builds only); Settings shows them localized.
-
Redesign (variant A):
test/new-tab-labs.test.tsxwas red first (3a5f675, 3a48dc6) and is green: collapsed by default as "Labs" / "Labs (N on)", rows with intent and switch, New / Expires soon hints, recently toggled first with a storage fallback, remembered open state, row menu.agent-pane-no-capsules,theme-colors,subtle-elevationand ui-rules pass locally. Release compile BUILD SUCCEEDED on d69557f.
Changelog
Added: Labs: opt-in flags for new looks and behaviors, listed in Settings > Experimental > Labs, the palette ("Labs…") and, in nightly and dev builds, a quick-toggle line on the New Tab page
Proof
Real cmux NEXT DEV builds from the fleet (--builder mac), on capture slots; host chip masked. Base: the New Tab page and palette before this PR. Head: this branch. The switch knob in these stills is white; since then it takes the page's theme color (theme-colors/subtle-elevation rules), otherwise unchanged.
| Light | Dark | |
|---|---|---|
| Before: New Tab | ![]() | ![]() |
| After: Labs collapsed | ![]() | ![]() |
| After: Labs open | ![]() | ![]() |
| After: row right-click menu | ![]() | ![]() |
| Before: palette "Labs" | ![]() | ![]() |
| After: palette "Labs…" | ![]() | ![]() |
Open, close, reopen, then turn the flag on and off (head, light):

Full quality:
🤖 Generated with Claude Code











