Repository navigation
General optimization sweep — reduce memory use and improve app-wide performance #103
Copy link
Copy link
Closed as not planned
Closed as not planned
Copy link
Labels
needs-ownerOwner decision neededOwner decision neededtype:perfPerformance or resource usePerformance or resource use
Description
Use case
Agent Code now runs many long-lived agent sessions, transcript tails, semantic streams, debug buffers, terminal PTYs, renderer panes, Monaco instances, and performance instrumentation at the same time. The app should get a dedicated optimization sweep focused on keeping memory growth, CPU churn, IPC volume, and renderer re-render cost under control as real users keep 5-20+ agents open.
This is not a single known regression. It is a cross-cutting hardening pass: look for places where the app holds too much state, recomputes too often, ships too much data across IPC, or renders more than the visible UI needs.
Goals
- Lower idle memory footprint with multiple sessions open.
- Reduce memory growth during long-running sessions and large transcript resumes.
- Reduce main-process CPU churn from tailers, screen parsing, condition evaluation, debug writers, and perf collection.
- Reduce renderer churn from workspace selectors, feed rows, markdown/code rendering, semantic streaming, and modal/panel subscriptions.
- Make heavy debug/perf features cheap when disabled and bounded when enabled.
- Add measurement points where needed so future optimization work is evidence-driven.
Initial audit areas
Main process
src/main/sessionManager.ts— per-session buffers (terminalBuffers,agentPtyBuffers), listener cleanup, session lifecycle maps, attach/replay behavior.src/main/sessions/historyLoader.tsand transcript loading paths — avoid whole-file reads where streaming/tail counts are enough.src/main/sessions/jsonlCoalescer.ts,src/shared/runtime/streamJsonl.ts,jsonlTailerpaths — check backpressure, batching, and duplicate parsing.src/main/worktreeActivity/*andsrc/main/sessionIndex.ts— scanner/index cost and whether it repeats work unnecessarily.src/main/performance/*— ensure watchdog/perf logging stays bounded and env-gated work is actually off when disabled.- Debug journals (
ghostJournal,dictationJournal,pasteDebugJournal, feed debug logs) — verify retention, batching, and in-memory queues are bounded.
Renderer
src/renderer/src/workspace/mergedEntries.ts,workspace/ghosts.ts, semantic reducers — preserve reference stability and avoid repeated allocation on no-op ticks.src/renderer/src/features/feed/ui/*— feed row memoization, markdown rendering, code block/Monaco cost, table rendering, streaming turn updates.src/renderer/src/workspace/hook/ipc/useIpcSubscriptions.ts— subscription fanout, per-event state writes, batching opportunities.src/renderer/src/workspace/workspaceStore.tsand command/selectors — avoid broad store updates that re-render the whole app.- Debug panels (
DebugPanel,FeedDebugPanel,HtmlDebugPanel,ProxyDebugPanel, future DevDebugPanel) — ensure disabled panels do not subscribe/process heavy streams.
Provider/headless packages
packages/claude-code-headlessandpackages/codex-headless— screen snapshot cadence, semantic event volume, proxy adapter buffering, condition evaluation cost, transcript parser allocations.packages/agent-transcript-parser— conversion/ghost merge paths over large transcripts.
Measurement plan
- Define a reproducible baseline: fresh launch, 1 agent, 5 agents, 20 agents, large resumed transcript, long-running streaming turn, idle after heavy use.
- Capture main/renderer heap and CPU from existing performance tools.
- Record IPC event volume and largest payload classes during the baseline scenarios.
- Identify top memory retainers and hot render paths before changing code.
- Land optimizations in small PRs with before/after numbers.
Possible fixes to investigate
- Replace remaining whole-file transcript reads with streaming/tail/count APIs where possible.
- Add hard caps or eviction to any per-session debug/runtime buffers that can grow with time.
- Batch high-frequency semantic/screen/IPC updates before committing renderer state.
- Split Zustand selectors or state writes so one session tick does not invalidate unrelated panes.
- Ensure feed rows and markdown/code blocks are memoized by stable identity and do not reparse on unrelated ticks.
- Lazy-mount heavy debug panels and expensive modals only when visible/enabled.
- Move derived session/picker indexes to cached main-process indexes rather than recomputing in renderer modals.
- Audit cleanup paths for killed, buried, detached, switched, and naturally exited sessions so maps/listeners/timers cannot leak.
Relationship to existing issues
- Related to Entry-count indicator above composer reflects lazy-load window, not full transcript length #93: total transcript counts should be computed without bloating the visible lazy-load window.
- Related to Commands target grid-only sessions — dispatch agents recurringly fall through every command path #94: canonical session resolvers should avoid repeated ad-hoc tree scans and reduce future selector mistakes.
- Related to Resume + session search are inconsistent — sometimes show IDs, sometimes cwd names, sometimes prompts; needs to be reasoned through and redone #96: a canonical session identity/index can prevent repeated head/tail transcript derivation.
- Related to Improve documentation: write evergreen design docs in docs/design/ for complex subsystems (ghost-system.md as the template) #100: likely deserves a
docs/design/perf-and-watchdog.mdonce the current performance architecture is clarified. - Related to Add an extensible Dev Debug Panel — schema-driven slot for hyperspecific, default-off debug modules #101: dev debug modules must be default-off and bounded so investigation tooling does not become the performance problem.
Non-goals
- Do not rewrite the app architecture just to chase theoretical wins.
- Do not remove useful diagnostics; gate and bound them.
- Do not optimize without a baseline. Each substantive change should say what scenario it improves and how it was measured.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
needs-ownerOwner decision neededOwner decision neededtype:perfPerformance or resource usePerformance or resource use
Activity
Juliusolsson05 commentedon May 18, 2026
Linked PR: #216 #216
This is the current performance optimization sweep PR. It addresses the first high-confidence batch from the research pass: streamed transcript/history paths, bounded telemetry overhead, reduced renderer layout churn, cached worktree probes/summaries, AI Workspace registry churn reduction, orchestration wait polling reduction, and feed render projection splitting.
Juliusolsson05 commentedon May 18, 2026
PR #216 has been merged with a merge commit: #216
This partially resolves the general optimization sweep by landing the first high-confidence batch: streamed transcript/history paths, bounded telemetry and debug-log overhead, reduced renderer layout churn, cached worktree probes/summaries, AI Workspace registry churn reduction, orchestration wait polling reduction, and feed render projection splitting.
Leaving this issue open for the remaining broader performance follow-ups.
perf(sessions): read transcripts incrementally for the picker
perf(terminal): silence replies provoked by replay and coalesce keyst…
perf(sessions): read only the transcript tail when loading history
Juliusolsson05 commentedon Sep 5, 2026
Further optimization audit at
5d641845(2026-09-05). Read README, AGENTS.md, agent-code-conventions, rendering ownership architecture and relevant subsystem comments. No application code/branches/builds changed, no live app restart/profile/agent control, and no private transcript data used. Existing modified package-lock.json was preserved. B7's #795 implementation was not touched.New prioritized, reproducible findings
Issue bodies contain pinned file references, synthetic reproduction procedures, measurements, expected behavior and acceptance criteria. Existing open and closed issues were searched with gh before creating each separate report. The reproduction suite was repeated: duplicate-fold evidence, filesystem-operation counts, growing socket queues and retained collection cardinalities all reproduced.
A5 context: current status, not a second copy of the old findings
workspace/terminal/sessionDataDispatcher.ts,xtermWebglRenderer.ts; perf(terminal): one agent-pty-data dispatcher per window and the WebGL renderer for xterm hosts #768 remains open for broader ownership work). Screen interest perf(ipc): gate session:screen delivery on renderer interest and split the picker onto its own channel #762, persistent terminal ownership perf(terminal): own xterm instances outside the React tree (per-session terminal registry) #760, and serialized attach snapshots perf(terminal): serialise the current screen for pane attach instead of replaying 512 KiB of raw PTY output #766 remain separate open opportunities. Do not treat the older per-host global listener or all-spinner full-derivation claims as current unchanged behavior.Measurement limits and next investigation
Confirmed evidence here is source control flow, collection sizes, transport queue bytes, and actual synthetic filesystem calls. Logical text bytes and socket bufferedAmount are not V8 heap/RSS. One warm directory-scan sample was 13 ms/15 ms CPU for one record and 45 ms/116 ms CPU for ten; timing varies with machine load and is secondary to call counts.
Unmeasured hypotheses: the contribution of each finding to live multi-agent stalls, phone tab termination, total CPU, and FPS. Do not promise percentage gains or identify these as causes of past OOMs from this evidence. After focused fixes, compare the same synthetic workloads, then collect a consented/non-disruptive app baseline (main event-loop latency, per-session scan counts, renderer commit count, bytes/queues) across idle/streaming/resume states. Larger process-isolation work #764/#769 should be prioritized with that remaining workload evidence; moving duplicate work off-main does not remove it.
Juliusolsson05 commentedon Sep 27, 2026
Closing: an umbrella whose work now lives in focused issues (triage 2026-09-27, main
a70403ef).This catch-all has no acceptance criteria that could ever be met.
Reopen when: never as an umbrella. New performance findings get their own issue.