Skip to content

Reclaim hidden Ghostty renderer memory - #8998

Merged
austinywang merged 80 commits into
mainfrom
feat-ghostty-memory-baseline
Jul 30, 2026
Merged

austinywang merged 80 commits into
mainfrom
feat-ghostty-memory-baseline

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Jul 27, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Reclaim GPU-backed renderer resources from hidden terminal tabs after five idle seconds while keeping one renderer warm.
  • Keep PTYs, terminal state, and scrollback alive, then perform one forced Ghostty renderer rebuild when a tab becomes visible.
  • Share standard and custom Metal pipelines across renderer handoffs, with bounded idle entries and a source-keyed 30-second compiler-failure backoff owned by each compile attempt.
  • Elect one native-tab observation owner per Ghostty tab group.
  • Derive runtime defaults from the shared settings catalog so runtime, Settings, and schema behavior stay aligned.
  • Derive app, TUI, CI, and TestFlight Zig versions from the pinned Ghostty manifest.

Benchmark

Controlled workload: one isolated 80 by 24 window, five idle login-shell tabs, 30-second settle, five samples at five-second intervals. Values are app-only physical footprint.

App and policy Retained Peak GPU categories
Ghostty 1.3.1, five native tabs 172.5 MB 395.4 MB 106.0 MB
Patched Ghostty, five native tabs after restoration 103.9 MB 463.9 MB 32.7 MB dirty/wired
Otty 1.3.0, inactive-tab freezing 97.0 MB 395.7 MB 39.0 MB
Termy 0.2.30 96.2 MB 286.2 MB 30.1 MB

The patched standalone Ghostty build closes 90.4% of the retained-memory gap between Ghostty 1.3.1 and the 96.6 MB Otty/Termy mean.

Tagged cmux control after reclamation:

  • Five tabs settled: 416.0 MB physical, 223.2 MB graphics.
  • One tab settled: 415.0 MB physical, 220.9 MB graphics.
  • Four additional tabs cost 1.0 MB physical and 2.3 MB graphics.

Tab scaling is competitive. cmux retains a separate roughly 319 MB whole-app baseline above the Otty/Termy mean.

Memory-runtime implementation and test churn is 3,471 Ghostty lines versus 197 cmux GUI lines, or 94.6% Ghostty and 5.4% cmux. This excludes the compiler-synchronization workflow changes and unrelated commits brought in by merging current main in each repository.

Ghostty dependency

Testing

  • Ghostty Zig 0.16 custom-shader suite: 83/83 tests, exit 0.
  • Ghostty canonical exact-head autoreview: exit 0, no findings, thread 019fabe3-1f2f-7622-a43f-b46f479207c2.
  • CmuxSettings focused defaults test: 1/1 passed.
  • CmuxTerminal renderer-presentation suite: 10/10 passed, exit 0.
  • Zig manifest synchronization, installer fallback, TUI packaging, and TestFlight path-contract tests passed.
  • Tagged cmux build selected Zig 0.16.0 and completed on Xcode 26.3.
  • Exact GhosttyKit archive validation: plist valid, no AppleDouble entries, required API present in all slices, macOS archive contains arm64 and x86_64.

Demo Video

No video. This changes renderer memory lifecycle rather than visible UI; tagged preflight exercises tab reclamation and restoration.

Review Trigger

@codex review
@coderabbitai review
@greptile-apps review
@cubic-dev-ai review

Checklist

  • Focused behavior tests pass.
  • Regression tests precede fixes in commit history.
  • Ghostty fork documentation, exact submodule pin, release, and checksum agree.
  • All actionable review findings are resolved.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The changes switch macOS renderer presentation to forced Ghostty rebuild transactions, align reclamation defaults with the settings catalog, derive Zig requirements from Ghostty’s manifest, expand rebuild-focused tests, and update Ghostty fork metadata.

Changes

Renderer reclamation and presentation

Layer / File(s) Summary
Forced renderer rebuild presentation
Packages/macOS/CmuxTerminal/Sources/CmuxTerminal/Surface/*, Packages/macOS/CmuxTerminal/Tests/..., Sources/App/RendererRealizationController.swift
Presentation uses ghostty_surface_rebuild_renderer, with repair and occlusion state updated around rebuild acceptance; stubs and tests track rebuild calls and rejection retries.
Catalog-backed reclamation defaults
Packages/macOS/CmuxSettings/..., Sources/App/WorkspaceRuntimeSettings.swift, cmuxTests/RendererRealizationPlannerTests.swift, web/data/cmux.schema.json
Renderer reclamation defaults change to 5 idle seconds and 1 warm renderer, runtime fallbacks read catalog values, and planner and settings tests validate the defaults.

Build and Ghostty integration

Layer / File(s) Summary
Manifest-driven Zig version selection
scripts/ghostty-zig-version.sh, scripts/install-zig-ci.sh, scripts/build-ghostty-cli-helper.sh, tests/test_ghostty_zig_version_sync.sh, cmux-tui/...
Build helpers resolve the required Zig version from Ghostty’s manifest, synchronize the configured version, and document Zig 0.16.0 requirements.
Ghostty revision and release metadata
ghostty, docs/ghostty-fork.md, scripts/ghosttykit-checksums.txt
The Ghostty revision, GhosttyKit archive reference, checksum entries, and fork documentation are updated to revision ed67f2b59.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Sequence Diagram(s)

sequenceDiagram
  participant TerminalSurface
  participant Ghostty
  participant PresentationRepair
  TerminalSurface->>Ghostty: request renderer rebuild
  Ghostty-->>TerminalSurface: accept or reject rebuild publication
  TerminalSurface->>PresentationRepair: cancel or arm repair
  PresentationRepair->>TerminalSurface: retry after renderer activity
Loading

Possibly related PRs

Suggested reviewers: austinywang


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 1 warning)

Check name Status Explanation Resolution
Cmux Full Internationalization ❌ Error New user-facing xcstrings keys were added for agent auto-retry, memory attribution, settings, and resume validation, but only en/ja entries exist; the rest of the catalog locales are missing. Add translated entries for each new xcstrings key in every locale already supported by Resources/Localizable.xcstrings, or defer the strings until translations are available.
Docstring Coverage ⚠️ Warning Docstring coverage is 15.15% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (23 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Swift Actor Isolation ✅ Passed PASS: The diff only retunes value defaults/comments; TerminalSurface stays @MainActor, and SettingCatalog/sections are value-typed Sendable structs, so no new isolation debt.
Cmux Swift Blocking Runtime ✅ Passed The PR only switches to a non-blocking renderer rebuild and updates comments/tests/settings; no new waits, sleeps, syncs, semaphores, or locks were introduced in production Swift.
Cmux Browser Automation Off-Main ✅ Passed PR only changes memory reclamation/settings; diff has no browser automation routing edits, and ControlCommandExecutionPolicy.swift is untouched.
Cmux Expensive Synchronous Load ✅ Passed No added or moved RestorableAgentSessionIndex.load()/large-file parsing on interactive or MainActor paths; changed code uses SharedLiveAgentIndex/off-main cache.
Cmux Cache Substitution Correctness ✅ Passed No diff replaced a fresh authoritative read with a stale cache in persistence/snapshot paths; the new snapshot data still comes from live diagnostics and freshness checks.
Cmux No Hacky Sleeps ✅ Passed Changed shell/build scripts only add shared Zig-version lookup and tests; no fixed sleeps, timers, polling, or wall-clock waits were introduced.
Cmux Algorithmic Complexity ✅ Passed Changed production code only updates comments/defaults or one-pass reads; no new nested scans, repeated sorts, or per-target rescans were introduced.
Cmux Swift Concurrency ✅ Passed PASS: the touched Swift changes are synchronous or boundary-only; no new Combine/completion-handler patterns, and existing Task/Dispatch usage is lifecycle-managed or allowed AppKit/notification bo...
Cmux Swift @Concurrent ✅ Passed Touched Swift code is sync or @MainActor; no new nonisolated async helpers or invalid @concurrent uses. Existing async work already hops explicitly to MainActor.
Cmux Swift Package Boundaries ✅ Passed PASS — the diff only updates app-side settings glue to read defaults from CmuxSettings and keeps terminal/Ghostty changes as AppKit glue/test fixtures, with no new reusable domain logic in Sources/...
Cmux Swiftpm Lockfiles ✅ Passed No Package.swift, .gitignore, or Package.resolved changes were in the diff, and the pbxproj diff showed no SwiftPM package-reference edits.
Cmux Swift Logging ✅ Passed No added print/debugPrint/dump/NSLog/Logger in touched production Swift files; the diff only changes renderer lifecycle logic/comments and settings defaults.
Cmux User-Facing Error Privacy ✅ Passed No user-facing error/alert/recovery copy changed; the PR only adjusts comments, settings defaults, tests, and developer-facing build-script diagnostics.
Cmux Swiftui State Layout ✅ Passed PASS: The PR only adjusts AppKit/renderer plumbing and comments; no new SwiftUI views, GeometryReader, lazy-row store refs, or render-time state writes were introduced.
Cmux Architecture Rethink ✅ Passed Uses required Ghostty callback bridge and keeps ownership in TerminalSurface; no sleeps, polling, locks, or duplicate lifecycle owners are introduced.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed No standalone window APIs or cmuxAuxiliaryWindowIdentifiers changes appear in the diff; the Swift edits are renderer/settings/main-window routing only.
Cmux Source Artifacts ✅ Passed All changed paths are intentional source/docs/tests/config/localization/checksum files; no build, temp, cache, or local-tool artifacts were added.
Cmux No Test Or Debug Seam In Production Source ✅ Passed Production diff only swaps Ghostty rebuild logic and settings defaults; no new #if DEBUG, ForTesting/TestHook, or widened wrapper seam appears.
Cmux No Ambient Global State ✅ Passed No new file-scope funcs/vars/singletons were added; new retry/settings state lives on injected instance types like Workspace and AgentSessionAutoRetrySettings.
Title check ✅ Passed The title clearly summarizes the main change: reclaiming hidden Ghostty renderer memory.
Description check ✅ Passed The description matches the template with Summary, Testing, Demo Video, Review Trigger, and Checklist sections filled in.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat-ghostty-memory-baseline

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jul 27, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

Unifies renderer-reclamation defaults and adopts the pinned Ghostty lifecycle implementation.

  • Changes the default hidden-renderer idle period to five seconds and retains one warm renderer.
  • Makes runtime settings derive their defaults from the same catalog used by Settings UI.
  • Updates renderer realization handling for Ghostty’s lossless latest-value publication.
  • Pins the corresponding GhosttyKit build, checksum, documentation, and regression coverage.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains; the runtime and Settings UI now obtain renderer-reclamation defaults from the same catalog, and the app target already links the imported settings module.

Important Files Changed

Filename Overview
Packages/macOS/CmuxSettings/Sources/CmuxSettings/Keys/TerminalCatalogSection.swift Changes the authoritative renderer-reclamation defaults from 30/12 to 5/1.
Sources/App/WorkspaceRuntimeSettings.swift Replaces duplicated runtime defaults with values from the shared settings catalog, resolving the prior divergence.
Packages/macOS/CmuxTerminal/Sources/CmuxTerminal/Surface/TerminalSurface+Renderer.swift Aligns renderer presentation state handling with Ghostty’s lossless latest-value realization API.
Sources/App/RendererRealizationController.swift Updates renderer repair and reclamation semantics for publication acknowledgements.
ghostty Advances the Ghostty submodule to the renderer-memory reclamation implementation.
scripts/ghosttykit-checksums.txt Adds checksums for the pinned GhosttyKit renderer lifecycle builds.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Hidden["Tab remains hidden for 5 seconds"] --> Policy["Renderer realization policy"]
  Policy --> Release["Release Ghostty renderer resources"]
  Release --> Preserved["Retain PTY, terminal state, and scrollback"]
  Preserved --> Selected["Tab becomes visible"]
  Selected --> Restore["Publish realized state"]
  Restore --> Presented["Renderer presented again"]
Loading

Reviews (5): Last reviewed commit: "Use catalog renderer reclamation default..." | Re-trigger Greptile

Comment thread Sources/App/WorkspaceRuntimeSettings.swift Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4ac4f04746

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Sources/App/WorkspaceRuntimeSettings.swift Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmuxTests/RendererRealizationPlannerTests.swift`:
- Around line 91-110: Update defaultFiveTabBaselineReclaimsFourHiddenRenderers
to resolve settings through RendererRealizationSettings.values(defaults:) using
an isolated UserDefaults instance with no stored keys, then pass the resolved
settings to selectedSurfaceIds instead of constructing Values directly from
constants. Preserve the test’s existing inputs and expected planner behavior.

In `@docs/ghostty-fork.md`:
- Around line 60-62: Before pinning the 517a4c75a GhosttyKit artifact, add a
deterministic teardown/shutdown regression test covering the clearSurface
main-queue dispatch_sync interaction with renderer-thread teardown, or update
the dependency to a release containing the fix from PR `#153`. Only promote the
pinned commit and checksum after shutdown completes without hanging.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 60f50b35-6bbd-4178-8cff-0fcdd3cc2d78

📥 Commits

Reviewing files that changed from the base of the PR and between eedc4a6 and 4ac4f04.

📒 Files selected for processing (8)
  • Packages/macOS/CmuxTerminal/Sources/CmuxTerminal/Surface/TerminalSurface+Renderer.swift
  • Packages/macOS/CmuxTerminal/Tests/CmuxTerminalTests/TerminalSurfaceRendererPresentationTests.swift
  • Sources/App/RendererRealizationController.swift
  • Sources/App/WorkspaceRuntimeSettings.swift
  • cmuxTests/RendererRealizationPlannerTests.swift
  • docs/ghostty-fork.md
  • ghostty
  • scripts/ghosttykit-checksums.txt

Comment thread cmuxTests/RendererRealizationPlannerTests.swift Outdated
Comment thread docs/ghostty-fork.md Outdated
@cursor

cursor Bot commented Jul 27, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@lawrencecchen

Copy link
Copy Markdown
Contributor Author

Final tagged benchmark on gmem26 (298b23e790, Ghostty 232b24bf2):

  • five tabs at 5 seconds: 516.6 MB physical, 345.3 MB graphics
  • five tabs settled: 416.0 MB physical, 223.2 MB graphics
  • one tab settled: 415.0 MB physical, 220.9 MB graphics

The four extra tabs add 1.0 MB physical and 2.3 MB graphics after reclamation. The remaining 220.9 MB graphics baseline is fixed cmux process cost, not Ghostty tab growth.

The catalog regression failed at the stale 30-second/12-renderer defaults, then passed at 5 seconds/1 renderer. Cloud build: https://github.com/manaflow-ai/cmux/actions/runs/30263879004

@austinywang

Copy link
Copy Markdown
Contributor

@codex review
@coderabbitai resume
@coderabbitai review
@greptile-apps review
@cubic-dev-ai review

@cubic-dev-ai

cubic-dev-ai Bot commented Jul 28, 2026

Copy link
Copy Markdown

@codex review
@coderabbitai resume
@coderabbitai review
@greptile-apps review
@cubic-dev-ai review

@austinywang I can't start this review because your workspace has reached its free monthly review limit. cubic has reviewed 241,631 of the 240,000 allowed lines of code this month. Reviews resume on 1 August 2026 (in 4 days). Paid plans include much higher monthly review limits. Upgrade now to resume reviews.

To help optimise your usage, you can tune cubic to get the most out of your usage limits:

Learn more →

# Conflicts:
#	.github/workflows/ios-testflight.yml
#	Packages/macOS/CmuxTerminal/Sources/CmuxTerminal/Engine/SurfaceRegistry/TerminalSurfaceRegistry.swift
#	docs/ghostty-fork.md
#	ghostty
#	scripts/ghosttykit-checksums.txt
@cursor

cursor Bot commented Jul 30, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@austinywang
austinywang merged commit 69efba1 into main Jul 30, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants