You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
#3439 was closed when the R1 foundation (#4088, corrected by #4249) merged, with 9 of its 12 checklist items still open. Four controller migrations (#4315, #4316, #4491, #4498) and the Usage slice (#4425 / #4440) currently reference a closed issue. This issue is the successor and carries the remaining work.
The definition of done changes, following the evidence Astro-Han posted on #3439 and #4109: extracting a feature into features/<name>/ does not change the scope of any state. A slice is done when
none of its hooks is called in the render body of AppShell or AppShellContent (the entry disappears from scripts/check-app-shell-hooks.mjs, or shrinks to a single equality-selected read that the shell genuinely needs);
its window.maka.* paths are gone from app-shell.tsx (the bridgePaths entry in renderer-architecture.json shrinks);
For reference, app-shell.tsx had 23 bridge references when #3439 opened; the five extraction PRs did not stop new product work (#3427, #3497, #3635, #3764, #3798) from landing bridge calls in the shell. The R1 ratchet has held the count since 2026-08-30.
Checklist
Each item names the hooks and bridge paths that must leave AppShell/AppShellContent. Claim an item by commenting; one slice per PR.
Controllers already extracted, call site still in the shell
Workbar — useWorkbarController; WorkbarHost still receives model from the shell
Session Navigation residue — useSessionNavigationReads (a selector read; keep only if the shell body still needs it after Conversation/Session controls move)
Raw shell state — useState (15 + 2), useEffect (14), useLayoutEffect (2), useStableActions (6) converge to the region/provider that reads them; this item closes last
Shared infrastructure (do before the next three slices)
Collapse the per-slice join cost (Astro-Han, refactor(desktop): make AppShell a renderer composition root #3439). Provide one createServicesContext<S>(name) outside the renderer zones (checker treats packages/ui and src/shared as external) and reduce Desktop adapters to { ns: bridge.ns } or { ...bridge.ns, <real adaptation> }. Measured on 6c8e749d3 with tsc -p tsconfig.renderer.json: 81 of 119 adapter forwarders are identity. Replacing identity forwarders with ...bridge.<ns> and keeping the real adaptation verbatim produced zero new type errors for goals, module-hub (skills, scheduledTasks), session-navigation, task-entry, and workbar (terminal, todo, browser, attachments); together that is about 80 lines removed across 5 adapters. The blocks that mix identity forwarders with multi-line adaptation (workbarreview/artifacts/inspector/sideChat, module-hubdailyReview, runtime-host-managementpeerMesh) need a hand pass; connection-settings, session-collaboration, and session-settings do real adaptation and stay as they are. Bridge namespaces are plain objects (no this in preload), so passing them whole is runtime-safe.
One gate for AppShell hooks (needs @Astro-Han's agreement — the hook gate's no---write friction is deliberate). Proposal: the ledger gains a component-scoped hookCalls for AppShell/AppShellContent with exact-match semantics, controllerOwners (refactor(desktop): move Module Hub controller below AppShell #4315) is the provenance authority, and scripts/check-app-shell-hooks.mjs retires. Until then both gates run in CI.
No product, visual, IPC, storage-schema, copy, or shortcut changes. Composer mount semantics, bootstrap behavior, streaming isolation, Session-switch races, and Workbar resource lifecycles stay compatible. Performance evidence, where given, is measured in one running Electron instance with alternating configurations and paired trials, and the claim is bounded to what was measured.
Non-goals
No new global state library or service locator; no IPC redesign; no packages/ui extraction; no mechanical moves into features/ that leave the hook call site in the shell.
Why a new issue
#3439 was closed when the R1 foundation (#4088, corrected by #4249) merged, with 9 of its 12 checklist items still open. Four controller migrations (#4315, #4316, #4491, #4498) and the Usage slice (#4425 / #4440) currently reference a closed issue. This issue is the successor and carries the remaining work.
The definition of done changes, following the evidence Astro-Han posted on #3439 and #4109: extracting a feature into
features/<name>/does not change the scope of any state. A slice is done whenAppShellorAppShellContent(the entry disappears fromscripts/check-app-shell-hooks.mjs, or shrinks to a single equality-selected read that the shell genuinely needs);window.maka.*paths are gone fromapp-shell.tsx(thebridgePathsentry inrenderer-architecture.jsonshrinks);controllerOwnersentry once refactor(desktop): move Module Hub controller below AppShell #4315 lands;Baseline (upstream/main
6c8e749d3, 2026-09-03)app-shell.tsxAppShell+AppShellContentrender bodiescheck:app-shell-hooks)window.maka.*paths inapp-shell.tsxbridgePaths)connection-settings,goals,module-hub,runtime-host-management,session-collaboration,session-navigation,session-settings,task-entry,workbar)For reference,
app-shell.tsxhad 23 bridge references when #3439 opened; the five extraction PRs did not stop new product work (#3427, #3497, #3635, #3764, #3798) from landing bridge calls in the shell. The R1 ratchet has held the count since 2026-08-30.Checklist
Each item names the hooks and bridge paths that must leave
AppShell/AppShellContent. Claim an item by commenting; one slice per PR.Controllers already extracted, call site still in the shell
useModuleHubController→ refactor(desktop): move Module Hub controller below AppShell #4315 (approved, pending merge)useGoalController→ refactor(desktop): move Goal controller ownership below AppShell #4316 (merged 2026-09-01)useTaskEntryController→ refactor(desktop): move Task Entry controller below AppShell #4491 (open)useWorkbarController;WorkbarHoststill receivesmodelfrom the shelluseSessionNavigationReads(a selector read; keep only if the shell body still needs it after Conversation/Session controls move)Shell-owned state that has no slice yet
useEffect/useState; bridgeapp.installUpdate,app.retryUpdateDownload,app.subscribeUpdateStatus,app.updateStatus→ refactor(desktop): move App Update controller below AppShell #4498 (open)settings/usage-settings-page.tsx→ refactor(desktop): extract Usage settings into a renderer feature slice #4425 / refactor(desktop): move Settings → Usage into a renderer feature slice #4440 (open; extraction only, pricing editor separate)useAppShellTurnPresentation,useShellLiveTurn,useActiveSessionEvents,useTurnActionRegistry,useActiveExecutionBoundary,useSessionEventHealthPolling,useShellRunUpdates,useShellResume,useShellMemoryPill,useShellChatModel; bridgetranscripts(2),sessions.listActiveInteractions,sessions.subscribeActiveInteractions,sessions.listTurnLandmarks,sessions.compact,notifications.runEndeduseTaskSubmissionReadiness,useComposerAttachments,useAppShellComposerQuotes,useNewTaskChoice; bridgeattachments,attachments.readBytes,sessions.updateQueueEntry,sessions.retractQueueEntry,sessions.promoteQueueEntry,sessions.reorderQueueEntriesuseSessionSettingIntent,useSessionCollaborationDialog,usePlanModeState,useSettingsModal; bridgesessions.getPlanState,sessions.abandonPlanProposal,sessions.setCollaborationModeuseAppShellSessionWorkspace,useAppShellSessionUiReads,useAppShellProjectContext,useAppShellNavRefSync; bridgesessions(whole namespace handed down)workHub.resolveCoordinationSession,workHub.record,workHub.candidates,workHub.act,settings.getClient,settings.subscribeClientChanged,runtimeHostProfiles.subscribeChanges,connections.subscribeEvents(coordinate with tracking(desktop): evolve WorkHub into a per-Runtime-Host conversational coordinator #3492)useAppShellBootstrapSubscriptions,useAppShellHostEffects,useAppShellPersistenceEffects,useOnboardingSnapshot,useShellConnections(3),useShellAppearance,useSystemUiLocale; bridgediagnostics.copyReport,diagnostics.copyPreviousMainProcessInterruption,diagnostics.takePreviousMainProcessInterruption,onboarding.setMilestoneuseCommandPalette,useKeyboardHelp,useShellSearch,useToastuseState(15 + 2),useEffect(14),useLayoutEffect(2),useStableActions(6) converge to the region/provider that reads them; this item closes lastShared infrastructure (do before the next three slices)
createServicesContext<S>(name)outside the renderer zones (checker treatspackages/uiandsrc/sharedas external) and reduce Desktop adapters to{ ns: bridge.ns }or{ ...bridge.ns, <real adaptation> }. Measured on6c8e749d3withtsc -p tsconfig.renderer.json: 81 of 119 adapter forwarders are identity. Replacing identity forwarders with...bridge.<ns>and keeping the real adaptation verbatim produced zero new type errors forgoals,module-hub(skills,scheduledTasks),session-navigation,task-entry, andworkbar(terminal,todo,browser,attachments); together that is about 80 lines removed across 5 adapters. The blocks that mix identity forwarders with multi-line adaptation (workbarreview/artifacts/inspector/sideChat,module-hubdailyReview,runtime-host-managementpeerMesh) need a hand pass;connection-settings,session-collaboration, andsession-settingsdo real adaptation and stay as they are. Bridge namespaces are plain objects (nothisin preload), so passing them whole is runtime-safe.--writefriction is deliberate). Proposal: the ledger gains a component-scopedhookCallsforAppShell/AppShellContentwith exact-match semantics,controllerOwners(refactor(desktop): move Module Hub controller below AppShell #4315) is the provenance authority, andscripts/check-app-shell-hooks.mjsretires. Until then both gates run in CI.CI; run the base commit's checker against the head tree as a cross-check so a PR cannot lower both sides by weakening a rule; add the two-commit git-fixture test fix(desktop): ratchet renderer debt against the base tree, not its ledger #4249 deferred.Invariants (unchanged from #3439)
No product, visual, IPC, storage-schema, copy, or shortcut changes. Composer mount semantics, bootstrap behavior, streaming isolation, Session-switch races, and Workbar resource lifecycles stay compatible. Performance evidence, where given, is measured in one running Electron instance with alternating configurations and paired trials, and the claim is bounded to what was measured.
Non-goals
No new global state library or service locator; no IPC redesign; no
packages/uiextraction; no mechanical moves intofeatures/that leave the hook call site in the shell.