Skip to content

perf(headless): skip derived screen work for spinner-only repaints inside the headless packages #765

Description

@Juliusolsson05

Symptom

packages/claude-code-headless/src/terminal/HeadlessTerminal.ts:600-613 gates snapshots on exact equality of plain/recent, which a spinner glyph or elapsed timer defeats every 100 ms. Every snapshot then runs two per-cell markdown walks (snapshotMarkdown, snapshotRecentMarkdown), and ClaudeCodeHeadless.ts:548-611 runs parseClaudeComposerState + snapshotComposerAttributes() (cell walk), the trust/resume/permission/compaction regex detectors, detectSlashPicker(term) + detectAskUserQuestion(term) (live-grid walks), four JSON.stringify keys and extractAssistantInProgress(recent). With ~10 sessions thinking: 60–100 snapshot pipelines/s ≈ 300–500 cell walks/s on the main thread for a spinner glyph. #761 gates the emit in the app's session manager; this issue removes the work at its source.

Expected

  • Normalise the spinner glyph set (ScreenParser.ts:281-284,321) and (Ns · …) timers before the equality gate; for a spinner-only diff run only detectActivity, skip the markdown walks, the attribute walk, the grid walks and the detectors.
  • Cap headless scrollback 10000 → 2000 (HeadlessTerminal.ts:251-256; codex same): nothing reads beyond snapshotRecent(200); up to −12 MB per session.
  • Same for codex-headless.

Submodule repos (separate PRs + pin bumps). Estimated −80–90% snapshot pipelines while thinking.
Refs #103, #390. Source: architecture audit 2026-09-03 (scratchpad/arch-perf-audit.md).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions