feat(desktop): open Home on New task's composer
Merged
DA
13d ago+482+482+012345678901234567890123456789-98-98-01234567890123456789
Summary
PR 8 of the "New task, prompt first" redesign: Home now opens on New task's composer, inline, the way Codex and ChatGPT open on a prompt box. This is question 5 of the approved design, done as the follow-up the developer approved. #3717 added NewTaskComposer.
- Home (
desktop-home.tsx): onmain'sDetailPage, the greeting is the page title. The composer sits at the top of the content, in.home-composer, in place of the "New task" header action. Inbox and Recent stay below it. The composer starts tasks in the workspace Home is showing.- It replaces the button rather than sitting beside it. The card already is New task on this page, so a button next to it would be a second way to do the same thing. ⌘N, the title bar, the sidebar, the command palette and a repository group's "+" still open the dialog. Only Home has the inline card.
- The press that opened the dialog only picks a repository for the dialog. Home's card starts with no preset, so it never picks that repository up.
- Signed out, there is no card.
- Welcome page: an account with no task yet keeps
main's centred welcome, with the card under Luke's face and line. - One composer for every state: while the task list loads, the page shows the card itself, since the card doesn't depend on the list. Home renders one composer, through a portal, into a box of its own (
useComposerSlot). The loading page, the loaded page and the welcome each place that box where it belongs. So nothing typed while the list loads is lost when it lands, including when it lands as a brand-new account's welcome. The caret moves with the words. - Focus: the card doesn't set
focusedByOwner, so it decides likeagent-composer.tsxdoes. Its words take the caret when the editor mounts, unless a field or editor elsewhere already has it. - Keys:
use-row-keys.tsalready ignores any key not pressed from the window itself or from one of its rows, so ↑, ↓ and Return in the composer belong to the composer. Tests now pin this down. Escape in the card, when nothing in it needs closing, gives up focus. The arrows then reach Home's rows again. - Home's card and the dialog's stay in step on the mode. Both can be mounted at once (Home under ⌘N's dialog), so
new-task-mode.tsis now one store that every card reads (useSyncExternalStore). Turning Plan on in the dialog turns it on in Home's card too. - Model sync dropped: an earlier round kept the cards' model chips in step through a write of the account default.
main(#3718) now changes the default only in Settings, and #3717 followed. Each card starts on the default as read, and a pick applies to that card's agent alone. So the sync code and its tests are gone. - Draft not kept, by choice: the card's words, files and issue do not survive leaving Home.
NewTaskComposerkeeps them in its own state. Keeping them would need acomposer-drafts.tsplace and a controlled draft on the composer; the orchestrator is tracking that as a follow-up.
Screenshots
These come from the real DesktopHome with fake data in headless Chromium, dark theme, not from the packaged app (evidence.sh only runs on macOS).
Home, with tasks:

A new account's welcome:

Evidence
pnpm check:affectedruns out of memory in this sandbox, so its parts were run one at a time on the head commit:pnpm oxlintand biome on the changed files: passed.tsc --project apps/desktop/tsconfig.json --noEmit: passed.pnpm knip: passed../scripts/repository-checks.sh: passed.NODE_OPTIONS=--max-old-space-size=6500 pnpm discarded-effect: passed.
pnpm exec vitest runoverdesktop-home.test.ts,desktop-shell.test.tsanddesktop-tasks.test.ts: 78 tests passed. The new welcome-draft test fails without the shared composer box.
Tests
desktop-home.test.ts goes from 23 to 29 tests: one removed and seven added.
- Removed: "↑ and ↓ pressed on New plan leave the focus on it". The button is gone, and the composer key test below covers the same ground.
- Added:
- the composer takes the caret, and ↑/↓/Return typed in it move no row (Return starts its task);
- it leaves the caret in a field that already has it;
- Agent mode start (listed workspace,
planning: false, agent on the words with the chip's model and the card's idempotency key, no dialog asked for); - Plan mode start (Shift+Tab,
planning: true, Untitled, the words handed to Luke as the brief, no agent); - words typed while the list loads survive it landing, both as the page and as a new account's welcome;
- with the dialog open over Home, Plan turned on in the dialog is Home's mode once the dialog closes.
- Changed: the skeleton, greeting and welcome tests now check for the composer instead of the button. The welcome test also starts a task from it. The arrow-key test presses Escape in the composer first. The row-press test no longer clicks the button.
desktop-shell.test.ts: the welcome test checks that Home holds the composer, and opens the dialog from the title bar's New task.
Invariants
-
./scripts/check.shgreen. (CI) - JSON Schema goldens unchanged. (CI)
- Every behavior change has, in this PR, the test that fails without it; no change-detector test added.
- Gateway envelope goldens unchanged. (CI)
- No new
astype assertion. - No
Effect.runPromise/runSync/runForkoutside the runtime edges (the test file'sbeforeAlllands the editor bundle as the dialog's test and 18 others do). - No new
setTimeout/setInterval/new Promise/AbortController/fs.watch. - No Effect, Stream, or Layer dropped.
- Test count delta listed above.
- No hand-rolled file replaced.
- No
CLAUDE.md/AGENTS.mdsentence names a changed part. -
PRIVACY.mdunchanged (the composer's box isph-no-capture, as the dialog's is). - No dependency changes.
- No barrel/door change.
Notes
- Out of scope, as asked: the composer's own behavior (#3717), the one-call start (PR 7), the brief (PR 5).