cmux NEXT New Tab: the default project is the chat you last picked and started, never an agent's folder
Leo, 2026-10-21: "making a new one we dont wanna have stuff constantly get clobbered by agents making projects and then the new workspace has to keep redoing the default... i mean sometimes we can do stuff but like... your recently PICKED AND STARTED CHAT... makes more sense..."
Leo-ask: default-project
What Leo saw: the New Tab project chip defaulted to leo-workspace · briefs/2026-10-20-gui-push. Only agents had worked in that folder; Leo never picked it.
Now: a New Tab with no folder of its own starts in the project of the chat the person last picked and started. That means a prompt sent from a composer: New Tab's Enter in the picked or kept project, or a new chat's composer after a project pick. Chats and workspaces made by agents, the cmux CLI or the socket (lanes, worktrees, briefs folders) never change this default. If no chat was started this way yet, or the host's project list no longer has that folder, the page falls back to the newest chat's folder, as before.
Root cause
webviews/src/agent-session/acpmux/newtab/NewTabScreen.tsx:242-261(base 56413628bcb):startsRecentpicksmostRecentProject(snapshot.sessions, …)/initialRecentProject(…), which is the folder of the newest chat of any origin on this Mac.webviews/src/agent-session/acpmux/sessionList.ts:332-356:mostRecentProject/recentLocalFoldersorder by chat recency and don't check who started the chat. Every acpmux chat an agent opens counts.webviews/src/agent-session/acpmux/newtab/recentProject.ts:30:rememberRecentFolderskeeps that list for the run's next page.- Introduced by #21693 (b288af6b2a8, "New Tab: start on the most recent project, or in no project") and extended by #22211 (dde0ebbee3a, "the first frame names the project and machine it keeps"). Found with
git log -S "mostRecentProject("andgit log -S rememberRecentFolders. - On the Swift side, nothing keeps a last-used folder for new workspaces. Cmd-N inherits the focused tab's folder (
CmuxNextApp/AppActions+Workspaces.swift:123-126, user origin only), and socket/CLIworkspace.createfalls back to the profile'sdefaults.cwdor home (CmuxNextApp/WorkspaceSpawn.swift:192-193). Nocmux-next.jsonkey names a default project. So the clobbering comes from the web page's chat-recency default only.
Change
- New
newtab/startedProject.tsstores the started project.rememberStartedProjectwrites this run's copy to the pages' shared localStorage and postsnewTab.remember {started}. The app keeps that inNewTabChoiceMemory(UserDefaultsnewTab.startedProject, next to the existing last agent and model picks) and hands it back in every local New Tab context asstartedProject. Pages on another machine get none. - Writers, all from a person's send:
screenActions.onAsk: the New Tab's Enter with a prompt or attachments, in a local folder. Not for "Do not work in a project", not on another machine's page.- App's composer
onSend: only when the folder was picked in this pane's project picker (chooseProject) and the send goes there. - The classic page's
chatFromNewTabwith text.
- Not written by:
chat.newitself, the handshake's start folder, socket or CLI chat creation,workspace.useFolder, or chat-list updates. - Reader:
NewTabScreenreads it once as the page mounts (this run's copy, else the app's). It wins over the latched or most-recent folder, filtered by the host's project list (firstProject).
Tests
Red on base, green on head:
cd webviews && bun test test/new-tab-started-project.test.tsx
- Base src with the test commit (b20427f7eec): 5 fail / 1 pass. Failing: "a project the person picks and starts a chat in is the next New Tab's default"; "chats agents, the CLI or the socket start in another folder never change the default"; "the app's copy names it after a relaunch…"; "the app is told the started project…"; "the New Tab context's started project reaches the page…". The fallback test passes on both, as it should.
- Head: 6 pass. All New Tab web tests (
test/new-tab*.test.ts*, 67 files): 279 pass, 0 fail.bun run checkpasses, andprepush-gate.pyreports no new violations. test/new-tab-ask-attachments.test.tswas updated for the extranewTab.remember {started}call.- Swift:
Packages/macOS/CmuxNext/Tests/CmuxNextAppTests/NewTabStartedProjectTests.swiftcoversnewTab.remember {started}→NewTabChoiceMemory→ the next launch's New Tab context. A pick that only names a folder, or a relative path, never sets it.
Observed / Not run
- Observed: the web red/green above and
bun run checkon huge-blue. - Not run yet: the Swift package test and
cmux-ci compile-check --app(queued after this PR opens). No real-app capture.
No capture: the visible change is which folder the existing chip names; there is no new UI. Before = Leo's screenshot (private, not attached).
Changelog
- Fixed: a New Tab starts in the project of the chat you last picked and started, not in a folder an agent last worked in.
Overlap: pr-overlap lists #22775, #20598, #22230, #23961, #24247 as touching the same files, but none changes the default project. #23863 (project-picker batch lookups) is closed and touches different files. The project-picker icons/dedupe lane has no pushed branch; this PR doesn't touch ProjectChooser or the picker rows.
Agent session: cosmic-gray
🤖 Generated with Claude Code
![View with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v3-3x.png)
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Fixes the New Tab default project so it starts in the project of the chat the person last picked and started, not the newest chat's folder (which agents move). Only a prompt sent from a composer in a picked project records it, and only once the chat actually starts; refused or failed starts, and chats agents, CLI, or sockets start, never change it. On this Mac only, while the host still lists the project (an answered empty list counts as no project), both the New Tab page and the classic page use it, else they fall back to the newest listed chat folder, then the tab's own folder. The default is kept across launches.
Details
- A page's known project list is now that page's machine's (keyed by the page's generation); a later page on another machine never reads this Mac's list or starts on this Mac's folder.
- An empty project list that answered (all projects removed) means no folder counts; a list that hasn't answered yet still lets chat folders count.
- A refused or failed start does not record a new default.
- Added tests for the remote page's project list, the empty-list answer, and the classic page's fallback.