packages/app/create-effect-simplification-spec.md
Reduce reactive misuse across packages/app.
This work targets packages/app/src, which currently has 101 createEffect calls across 37 files.
The biggest clusters are pages/session.tsx (19), pages/layout.tsx (13), pages/session/file-tabs.tsx (6), and several context providers that mirror one store into another.
Key issues from the audit:
Keep the implementation focused on removing unnecessary effects, not on broad UI redesign.
createEffect usage in the hottest files firstpackages/appUse these rules during implementation.
createMemoUse createMemo when the target value is pure derived state from other signals or stores.
Do this when an effect only reads reactive inputs and writes another reactive value that could be computed instead.
Apply this to:
packages/app/src/pages/session.tsx:141packages/app/src/pages/layout.tsx:557packages/app/src/components/terminal.tsx:261packages/app/src/components/session/session-header.tsx:309Rules:
createEffectUse keyed remounts when local UI state should reset because an identity changed.
Do this with sessionKey, scope(), or another stable identity instead of watching the key and manually clearing signals.
Apply this to:
packages/app/src/pages/session.tsx:325packages/app/src/pages/session.tsx:336packages/app/src/pages/session.tsx:477packages/app/src/pages/session.tsx:869packages/app/src/pages/session.tsx:963packages/app/src/pages/session/message-timeline.tsx:149packages/app/src/context/file.tsx:100Rules:
Use direct handlers, store actions, and async command functions when work happens because a user clicked, selected, reloaded, or navigated.
Do this when an effect is just watching for a flag change, command token, or event-bus signal to trigger imperative logic.
Apply this to:
packages/app/src/pages/layout.tsx:484packages/app/src/pages/layout.tsx:652packages/app/src/pages/layout.tsx:776packages/app/src/pages/layout.tsx:1489packages/app/src/pages/layout.tsx:1519packages/app/src/components/file-tree.tsx:328packages/app/src/pages/session/terminal-panel.tsx:55packages/app/src/context/global-sync.tsx:148packages/app/src/pages/session/review-tab.tsx:122packages/app/src/pages/session/review-tab.tsx:130packages/app/src/pages/session/review-tab.tsx:138packages/app/src/pages/session/file-tabs.tsx:367packages/app/src/pages/session/file-tabs.tsx:378packages/app/src/pages/session/file-tabs.tsx:389packages/app/src/pages/session/use-session-hash-scroll.ts:144packages/app/src/pages/session/use-session-hash-scroll.ts:149packages/app/src/pages/session/use-session-hash-scroll.ts:167Rules:
onMount And onCleanupUse onMount and onCleanup for lifecycle-only setup and teardown.
This is the right fit for subscriptions, one-time wiring, timers, and imperative integration that should not rerun for ordinary reactive changes.
Use this when:
createEffect When It Is A Real BridgeKeep createEffect when it synchronizes reactive data to an external imperative sink.
Examples that should remain, though they may be narrowed or split:
packages/app/src/components/prompt-input.tsx:690packages/app/src/pages/session.tsx:685packages/app/src/pages/session/use-session-hash-scroll.ts:149packages/app/src/context/language.tsx:207packages/app/src/context/settings.tsx:110packages/app/src/context/sdk.tsx:26packages/app/src/components/status-popover.tsx:59packages/app/src/components/dialog-select-server.tsx:273Rules:
Before changing code, tag each targeted effect as one of: derive, reset, event, lifecycle, or external bridge.
Acceptance criteria:
Tackle highest-value, lowest-risk derived-state cleanup first.
Priority items:
packages/app/src/pages/session.tsx:141workspaceOrder in packages/app/src/pages/layout.tsx:557packages/app/src/components/prompt-input.tsx:652 can be removedAcceptance criteria:
Replace reset-on-key effects with keyed ownership boundaries.
Priority items:
sessionKeyscope()Acceptance criteria:
Move event-driven work out of reactive effects.
Priority items:
globalStore.reload effect dispatching with direct callspackages/app/src/pages/layout.tsx:1489Acceptance criteria:
Remove mirrored child-store hydration patterns.
Priority items:
packages/app/src/context/global-sync/child-store.ts:184, :190, :193packages/app/src/context/global-sync.tsx:130, :138packages/app/src/context/layout.tsx:424 if it still mirrors instead of derivingAcceptance criteria:
Clean up remaining targeted hotspots and narrow the effects that should stay.
Acceptance criteria:
createEffect calls in touched files are all true bridges or clearly justified lifecycle syncFiles:
packages/app/src/pages/session.tsx:141Work:
Rationale:
Acceptance criteria:
packages/app/src/pages/session.tsx:141 is removedFiles:
packages/app/src/pages/session.tsx:325packages/app/src/pages/session.tsx:336packages/app/src/pages/session.tsx:477packages/app/src/pages/session.tsx:869packages/app/src/pages/session.tsx:963packages/app/src/pages/session/message-timeline.tsx:149Work:
sessionKey changessessionKey just to clear local state, refs, or temporary UI flagsRationale:
Acceptance criteria:
Files:
packages/app/src/pages/layout.tsx:557Work:
workspaceOrder from live workspace data in an effectRationale:
Acceptance criteria:
packages/app/src/pages/layout.tsx:557 is removedFiles:
packages/app/src/context/global-sync.tsx:130packages/app/src/context/global-sync.tsx:138packages/app/src/context/global-sync.tsx:148packages/app/src/context/global-sync/child-store.ts:184packages/app/src/context/global-sync/child-store.ts:190packages/app/src/context/global-sync/child-store.ts:193packages/app/src/context/layout.tsx:424Work:
globalStore.reload event-bus pattern and call the needed reload paths directlyRationale:
Acceptance criteria:
Files:
packages/app/src/context/file.tsx:100Work:
scope()scope() only to reset file-local stateRationale:
Acceptance criteria:
packages/app/src/context/file.tsx:100 is removedFiles:
packages/app/src/pages/layout.tsx:1489packages/app/src/pages/layout.tsx:484, :652, :776, :1519Work:
:1489 into direct actions and smaller bridge effects only where requiredRationale:
Acceptance criteria:
packages/app/src/pages/layout.tsx:1489 no longer mixes unrelated responsibilitiesFiles:
packages/app/src/pages/session/review-tab.tsx:122packages/app/src/pages/session/review-tab.tsx:130packages/app/src/pages/session/review-tab.tsx:138packages/app/src/pages/session/file-tabs.tsx:367packages/app/src/pages/session/file-tabs.tsx:378packages/app/src/pages/session/file-tabs.tsx:389packages/app/src/pages/session/use-session-hash-scroll.ts:144packages/app/src/pages/session/use-session-hash-scroll.ts:149packages/app/src/pages/session/use-session-hash-scroll.ts:167Work:
Rationale:
Acceptance criteria:
Files:
packages/app/src/components/prompt-input.tsx:652packages/app/src/components/prompt-input.tsx:690 as neededWork:
Rationale:
Acceptance criteria:
packages/app/src/components/prompt-input.tsx:652 is removed:690 still behaves correctlyFiles:
packages/app/src/components/terminal.tsx:261packages/app/src/components/session/session-header.tsx:309Work:
Rationale:
Acceptance criteria:
Run focused checks after each phase, not only at the end.
If available, add or update tests around pure helpers introduced during this cleanup.
Favor tests for derived ordering, normalization, and action extraction, since those are easiest to lock down.
This work is done when all of the following are true:
A reduced raw createEffect count is helpful, but it is not the main success metric.
The main success metric is clearer ownership and fewer effect-driven state repairs.
Main risks:
Rollout notes: