Skip to content

perf: inline codex monitor tailing and sidebar batching - #4128

Closed
austinywang wants to merge 34 commits into
mainfrom
issue-4127-cmux-perf-codex-monitors-sidebar
Closed

austinywang wants to merge 34 commits into
mainfrom
issue-4127-cmux-perf-codex-monitors-sidebar

Conversation

@austinywang

@austinywang austinywang commented May 13, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Split sidebar row observation so user-driven fields stay immediate while agent-driven title/description/message churn is throttled at 80ms.
  • Batch sidebar log appends through a per-workspace 50ms coalescing flush backed by an O(1) ring buffer and cached log limit.
  • Collapse background workspace prime tab/pending observers into one shared subscriber per coordinator.
  • Replace persistent cmux hooks codex monitor sidecars and lease coordination with in-process transcript JSONL tailing in the app.

Driver 1 choice

I split truly user-driven sidebar fields (isPinned, customColor, terminalScrollBarHidden) from high-frequency agent-driven fields (title, customDescription, latestConversationMessage) and throttle only the agent stream. That preserves immediate visual feedback for user actions while coalescing Codex title churn.

Verification

  • Not run locally per repo/user instruction; CI is the verification path.

Closes #4127


Note

Medium Risk
Moves Codex monitoring from an external CLI sidecar to in-app JSONL tailing with new V2 socket RPCs, which changes runtime behavior and file I/O/event handling. Also refactors sidebar observation and log buffering, which could affect UI update timing and persistence snapshots if edge cases are missed.

Overview
Inlines Codex transcript monitoring into the app by removing the CLI codex monitor sidecar/lease system and replacing it with V2 socket calls (agent.codex_transcript_monitor.start/stop) that start/stop an in-process JSONL tailer and publish user-input/failure/completion events to notifications and sidebar status.

Reduces sidebar/UI churn by throttling agent-driven sidebar row updates separately from user-driven fields, and by batching sidebar log appends through a per-workspace ring buffer with a short flush throttle (flushed before snapshots and on list_log).

Consolidates background priming observers so multiple readiness waiters share a single set of TabManager/notification subscriptions, with explicit cleanup/cancellation on coordinator teardown.

Reviewed by Cursor Bugbot for commit 0c3cc11. Bugbot is set up for automated code reviews on this repo. Configure here.


Summary by cubic

Inlines Codex transcript monitoring into the app via V2 RPCs with boundary‑aware JSONL tailing, and batches/throttles sidebar updates to cut UI churn and log I/O. Removes the CLI monitor/leases, confines monitor session state to a single queue, adds per‑turn tracking and localized error bodies, and moves sidebar log flushing to the main run loop. Addresses #4127.

  • New Features

    • Split sidebar observation: user fields are immediate; agent title/description/message throttle at 80ms.
    • Batch sidebar logs per workspace with a 50ms coalesced flush and O(1) ring buffer; flush before snapshots and on list_log.
    • Replace cmux hooks codex monitor with an in‑app monitor + registry; V2 agent.codex_transcript_monitor.start/stop validate workspace/surface, auto‑resolve transcript path, and publish needs‑input/failure/completion to notifications and the sidebar.
  • Bug Fixes

    • Confined monitor session state to a single dispatch queue; stop monitors when workspaces/surfaces close.
    • JSONL tailing stays boundary‑aware with partial‑line buffering, oversized‑line protection, and a bounded re‑tail window after truncation; reset per‑turn state on re‑tail and ignore unrelated task_started.
    • Hardened background priming: shared observers with deduped waiters; cancel stale waiters, including on coordinator deinit; sidebar log timer/flush now on the main actor and runs before snapshot capture.

Written for commit 0c3cc11. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

  • New Features

    • Socket-driven start/stop controls for Codex transcript monitoring with runtime RPC integration.
    • Persistent per-session monitoring with sidebar status updates and user notifications for waiting, failures, and completion.
  • Bug Fixes

    • Monitors are stopped reliably when workspaces close to avoid stray monitors.
  • Performance

    • Buffered, capped sidebar logging with delayed flush and throttled sidebar updates.
    • Shared readiness observation to improve background workspace priming efficiency.

Review Change Stack

@vercel

vercel Bot commented May 13, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment May 22, 2026 9:23pm
cmux-staging Building Building Preview, Comment May 22, 2026 9:23pm

@coderabbitai

coderabbitai Bot commented May 13, 2026 •

Copy link
Copy Markdown

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

Inlines Codex transcript monitoring via V2 socket RPCs, replaces per-chunk sidebar log appends with a ring-buffered debounced pipeline, consolidates readiness observers into a TabManager-scoped system, and throttles agent-driven sidebar updates.

Changes

Performance optimization for high-frequency sidebar updates and process overhead

Layer / File(s) Summary
Readiness observer consolidation
Sources/BackgroundWorkspacePrimeCoordinator.swift
Shared TabManager-scoped readiness observers, Waiter.addCleanupAction(_:), per-workspace waiter registration, and targeted re-evaluation/pruning of waiters.
Agent-driven sidebar throttling & publisher split
Sources/ContentView.swift, Sources/Workspace.swift
Applies an 80ms throttle to agent-driven sidebar updates and splits immediate user-gesture fields from high-frequency agent-driven publishers.
Sidebar log ring buffer
Sources/SidebarLogRingBuffer.swift
Implements a bounded ring buffer for SidebarLogEntry with append, replaceAll, removeAll, and entries() operations; enforces a 1–500 clamp.
Workspace buffered log state and API
Sources/Workspace.swift
Adds cached/clamped max entry limit, lazy ring buffer, pending queue, sidebarLogFlushDelay, and implements enqueueSidebarLog(...), clearSidebarLogEntries(), setSidebarLogEntries(...), scheduleSidebarLogFlush(), and flushPendingSidebarLogEntries(). Ensures session snapshots flush pending logs and restoreSessionSnapshot(...) restores ring-buffered logs; cancels flush timer on deinit and stops monitors.
TerminalController socket log command wiring
Sources/TerminalController.swift
Routes socket log append/clear/list through tab.enqueueSidebarLog, tab.clearSidebarLogEntries(), and tab.flushPendingSidebarLogEntries() instead of directly mutating logEntries.
CLI socket request helpers & hook rewiring
CLI/cmux.swift
Adds requestCodexTranscriptMonitorStart and requestCodexTranscriptMonitorStop to normalize inputs, emit telemetry breadcrumbs, and send agent.codex_transcript_monitor.start/stop via SocketClient. Rewires Codex hook lifecycle to call these requests on session start/turn/end and removes the codex monitor subcommand and lease machinery.
TerminalController V2 handlers
Sources/TerminalController.swift
Adds agent.codex_transcript_monitor.start/stop cases, advertises them in v2Capabilities, implements v2 handlers that validate parameters and call CodexTranscriptMonitorRegistry, and handles incoming events to update sidebar "codex" status and enqueue notifications.
Codex transcript monitor core
Sources/CodexTranscriptMonitor.swift, Sources/CodexTranscriptMonitorModels.swift, Sources/CodexTranscriptMonitorParsing.swift, Sources/CodexTranscriptMonitorRegistry.swift, Sources/CodexTranscriptPathResolver.swift
Introduces request/summary/event models and CodexTranscriptMonitorRegistry with per-session CodexTranscriptMonitorSession that discovers *.jsonl transcripts, installs DispatchSource watchers, tails newline-delimited JSON, parses events, extracts user-input/failure/completion, enforces deadlines/retries, deduplicates calls, and publishes events to TerminalController.
Xcode project wiring
GhosttyTabs.xcodeproj/project.pbxproj
Adds CodexTranscriptMonitor.swift and SidebarLogRingBuffer.swift (plus support files) to the app target's sources and file references.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 I watched the sidecars hop away,

One monitor now leads the day,
Rings hold logs till timers wake,
Observers share for sanity’s sake,
Quiet burrow, lighter play.


Caution

Pre-merge checks failed

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

  • Ignore

❌ Failed checks (3 errors, 1 warning)

Check name Status Explanation Resolution
Cmux Swift Actor Isolation ❌ Error Pure value types CodexTranscriptFailureCandidate and CodexTranscriptUserInputCandidate lack Sendable conformance; stateless helpers lack nonisolated marking per Swift 6 rules. Add Sendable to CodexTranscriptFailureCandidate/CodexTranscriptUserInputCandidate; mark CodexTranscriptPathResolver static methods as nonisolated per coding guidelines.
Cmux Swift File And Package Boundaries ❌ Error 695L of lifecycle-independent code in Sources/ root violates package-boundary rule. Should be in SwiftPM package: CodexTranscriptMonitor (373L), Parser (184L), PathResolver (72L), Models, RingBuffer. Move lifecycle-independent code to new SwiftPM package. Keep glue-layer Registry in Sources/. Aligns with author's review comment on this placement.
Cmux Architecture Rethink ❌ Error Split state ownership: sawAssistantMessage set for any response_item, used to determine monitored turn completion. Concurrent turns pollute flag. Review flagged but unfixed. Add turn matching guards to line 225: scope sawAssistantMessage via (turnMatches || sawRelevantTurn) as suggested in review comments.
Docstring Coverage ⚠️ Warning Docstring coverage is 3.30% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (11 passed)
Check name Status Explanation
Title check ✅ Passed Title concisely summarizes the main changes: performance optimization via inlined Codex monitor and sidebar batching.
Linked Issues check ✅ Passed PR code changes address all four drivers from #4127: throttled sidebar observation (Driver 1), batched log appends (Driver 2), shared readiness observers (Driver 3), and inlined Codex monitoring (Driver 4).
Out of Scope Changes check ✅ Passed All changes align with #4127 objectives: sidebar throttling/batching, background coordinator observer consolidation, and Codex monitor inlining; no unrelated modifications detected.
Cmux Swift Blocking Runtime ✅ Passed PR introduces only non-blocking timing: Combine .throttle (UI batching) and DispatchSourceTimer callbacks (async file monitoring). Zero blocking patterns detected in new/modified production code.
Cmux No Hacky Sleeps ✅ Passed Rule covers TypeScript, JavaScript, shell, non-Swift runtime only. This PR modifies only Swift files. Swift timing is covered by swift-blocking-runtime.md.
Cmux Swift Concurrency ✅ Passed All new concurrency patterns are justified: DispatchSource OS boundary, closure callbacks required for async handlers, minimal MainActor hops, private internal batching.
Cmux Swift @Concurrent ✅ Passed PR complies with swift-concurrent-annotation.md. File I/O work properly confined to background queue, explicit Task { @MainActor } hops used when needed, no invalid @concurrent annotations.
Cmux Swift Logging ✅ Passed No new logging violations. Zero print/NSLog statements added. New files properly sanitize telemetry. Compliant.
Cmux Swiftui State Layout ✅ Passed No new SwiftUI state violations. No ObservableObject/@published added, no render-time mutations, no store refs in lazy rows. Workspace batching is private implementation detail.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR contains no NSWindow/NSPanel/NSWindowController/SwiftUI Window changes. All modifications are monitoring, logging, and observer refactoring without new auxiliary windows.
Description check ✅ Passed Pull request description is detailed and addresses the template structure with a comprehensive summary of changes, driver choices, and verification notes.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-4127-cmux-perf-codex-monitors-sidebar

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 and usage tips.

@greptile-apps

greptile-apps Bot commented May 13, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR inlines Codex transcript monitoring from a CLI sidecar into the app runtime via new V2 agent.codex_transcript_monitor.start/stop RPCs, replaces the per-waiter observer pattern in BackgroundWorkspacePrimeCoordinator with a single shared subscriber set, and introduces a 50 ms coalescing ring-buffer flush for sidebar logs alongside an 80 ms throttle for agent-driven sidebar row updates.

  • CodexTranscriptMonitor (Sources/CodexTranscriptMonitor/): five new focused files implementing boundary-aware JSONL tailing, failure summarization with sanitized localized copy, session-id registry with workspace-scoped stop, and filesystem path resolution. State is confined to a private serial queue; events are forwarded to @MainActor via DispatchQueue.main.async + assumeIsolated.
  • Sidebar batching (Workspace.swift): enqueueSidebarLog / flushPendingSidebarLogEntries backed by a SidebarLogRingBuffer; the coalescing sink now calls flushPendingSidebarLogEntries via MainActor.assumeIsolated (prior actor-isolation concern resolved). sidebarImmediateObservationPublisher retains unthrottled delivery for user-driven fields; agent-driven fields move to sidebarAgentObservationPublisher throttled at 80 ms in ContentView.
  • BackgroundWorkspacePrimeCoordinator: class annotated @MainActor; shared observers replace per-waiter installation; stale waiters are cancelled on coordinator teardown and TabManager change.

Confidence Score: 4/5

Safe to merge after adding catalog translations for the two notification strings; all blocking / actor-isolation / completion-event concerns from previous rounds are resolved.

The previous blocking concerns (Task.sleep debounce, MainActor.assumeIsolated in timer and sink callbacks, monitor lifetime, completion event clearing the bell badge, raw upstream error text in notification bodies, and missing locale coverage for the four new error-body strings) are all addressed in the current revision. One localization gap remains: agent.codex.input.subtitle.waiting and agent.codex.input.status.needsInput are catalog keys that were dormant before this PR; this PR is the first production code to emit them in macOS notification subtitles and sidebar status badges, but neither key has translations for 18 of the 20 supported locales. Users outside en/ja will see English text in those surfaces.

Sources/TerminalController.swift — the handleCodexTranscriptMonitorEvent notification path uses two catalog keys (agent.codex.input.subtitle.waiting, agent.codex.input.status.needsInput) that are missing translations for 18 supported locales.

Important Files Changed

Filename Overview
Sources/CodexTranscriptMonitor/CodexTranscriptMonitor.swift New 483-line in-process JSONL tailing engine: boundary-aware with partial-line buffering, oversized-line protection, re-tail after truncation, per-turn deduplication, and DispatchSource-based file watching. State is correctly confined to a private serial queue.
Sources/CodexTranscriptMonitor/CodexTranscriptMonitorRegistry.swift Singleton registry managing sessions by sessionId on a shared utility queue; publishes events to MainActor via DispatchQueue.main.async + assumeIsolated. Correct lifetime handling and workspace-scoped stop.
Sources/CodexTranscriptMonitor/CodexTranscriptMonitorParsing.swift Parser helpers for failure classification, user-input extraction, and failure summarization. All notification body strings now use static localized copy via String(localized:); no raw upstream error text exposed.
Sources/TerminalController.swift Adds V2 RPC handlers for transcript monitor start/stop, wires handleCodexTranscriptMonitorEvent callback, and delegates sidebar log to enqueueSidebarLog. Two notification strings used here (subtitle.waiting, status.needsInput) are present in the catalog only for en/ja, not the 18 other supported locales.
Sources/Workspace.swift Splits sidebar observation into immediate (user-driven) and throttled (agent-driven) publishers; introduces O(1) ring buffer with 50ms coalesced flush via Combine throttle. Actor isolation is correct: throttled sink uses MainActor.assumeIsolated, DispatchSource callback does the same.
Sources/BackgroundWorkspacePrimeCoordinator.swift Refactored from per-waiter observers to a single shared set of observers per TabManager; class is now @mainactor so mutable registry state is correctly isolated. Stale waiter cancellation on teardown and tab-manager switch is handled.
Sources/SidebarLogRingBuffer.swift New 44-line O(1) ring buffer for sidebar log entries with append, replaceAll, removeAll, and entries() helpers. Correctly clamps limit to [1, 500] and handles wrap-around.
Resources/Localizable.xcstrings Adds four Codex error body strings (auth, generic, network, rateLimit) with complete translations across all 20 supported locales including km. Previous gap addressed.

Sequence Diagram

sequenceDiagram
    participant Agent as Codex Agent (CLI)
    participant Socket as V2 Socket RPC
    participant TC as TerminalController (@MainActor)
    participant Reg as CodexTranscriptMonitorRegistry (utility queue)
    participant Mon as CodexTranscriptMonitorSession (utility queue)
    participant FS as JSONL Transcript File
    participant WS as Workspace (@MainActor)

    Agent->>Socket: agent.codex_transcript_monitor.start
    Socket->>TC: v2CodexTranscriptMonitorStart(params)
    TC->>Reg: start(request)
    Reg->>Mon: init + start()
    Mon->>FS: open O_EVTONLY (DispatchSourceFileSystemObject)
    Mon->>FS: readInitialTail (last 512 KB)

    FS-->>Mon: .write / .extend event
    Mon->>Mon: readIncremental → processLine
    Mon->>TC: "DispatchQueue.main.async { assumeIsolated { handleEvent } }"
    TC->>WS: "tab.statusEntries[codex] = SidebarStatusEntry"
    TC->>TC: notificationStore.addNotification

    Agent->>Socket: agent.codex_transcript_monitor.stop
    Socket->>TC: v2CodexTranscriptMonitorStop(params)
    TC->>Reg: stop(sessionId:turnId:)
    Reg->>Mon: cancel()
    Mon->>FS: source.cancel() / close(fd)

    Note over TC,WS: Workspace teardown path
    TC->>Reg: stopWorkspace(workspaceId)
    Reg->>Mon: cancel() for all workspace sessions
Loading

Reviews (24): Last reviewed commit: "fix: cancel readiness waiters from deini..." | Re-trigger Greptile

Comment thread Sources/Workspace.swift
Comment thread Sources/TerminalController.swift Outdated
Comment thread Sources/TerminalController.swift Outdated
Comment thread Sources/TerminalController.swift Outdated
Comment thread Sources/TerminalController.swift Outdated
Comment thread Sources/Workspace.swift Outdated
coderabbitai[bot]
coderabbitai Bot previously requested changes May 13, 2026

@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: 3

🤖 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 `@CLI/cmux.swift`:
- Around line 18012-18084: requestCodexTranscriptMonitorStart currently trims
sessionId/workspaceId only for the emptiness check but stores the raw values
into params, causing a mismatch with requestCodexTranscriptMonitorStop which
uses a trimmed normalizedSessionId; fix by trimming both sessionId and
workspaceId up front (e.g. create normalizedSessionId and normalizedWorkspaceId
via trimming like requestCodexTranscriptMonitorStop), use those normalized
values when building params["session_id"] and params["workspace_id"], and keep
the existing guard and telemetry logic otherwise so the start/stop RPC payloads
are symmetric.

In `@Sources/TerminalController.swift`:
- Around line 23-709: Extract the entire Codex transcript monitor subsystem
(types CodexTranscriptMonitorRequest, CodexTranscriptFailureSummary,
CodexTranscriptMonitorEvent and the CodexTranscriptMonitorRegistry class
including its nested Monitor and all helper/static methods) into a new file
named Sources/CodexTranscriptMonitor.swift, preserving their access level and
Sendable annotations and any required imports; in the original
TerminalController.swift keep only the V2 endpoint handlers, the
stopCodexTranscriptMonitors(forWorkspaceId:) function, and
handleCodexTranscriptMonitorEvent(_:) so callers still route events into
TerminalController.shared; ensure the new file compiles by keeping the onEvent
closure signature and the Task { `@MainActor` in
TerminalController.shared.handleCodexTranscriptMonitorEvent(event) } call site
unchanged, and run a quick build to fix any visibility/import issues (make types
internal/public as needed).
- Around line 174-191: The deadline timer in armDeadline() calls finish() with
the default publishCompletion: false, which leaves the "Codex needs input"
sidebar entry set by handleCodexTranscriptMonitorEvent
(tab.statusEntries["codex"]) stuck when no completion event arrives; change the
timer event handler to call finish(publishCompletion: true) so
onEvent(.completion(request: request)) is published and the existing .completion
handling clears the bell.fill entry (alternatively, if you prefer direct
handling here, explicitly clear the codex status entry via the same mechanism
used in the .completion branch), ensuring you reference armDeadline(),
finish(publishCompletion:), and the .completion event path in
handleCodexTranscriptMonitorEvent.
🪄 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

Run ID: 16b684b9-36fe-4b79-a20b-d207ed245df3

📥 Commits

Reviewing files that changed from the base of the PR and between 278b312 and 8ca6cc9.

📒 Files selected for processing (6)
  • CLI/cmux.swift
  • Sources/BackgroundWorkspacePrimeCoordinator.swift
  • Sources/ContentView.swift
  • Sources/TabManager.swift
  • Sources/TerminalController.swift
  • Sources/Workspace.swift

Comment thread CLI/cmux.swift
Comment thread Sources/TerminalController.swift Outdated
Comment thread Sources/TerminalController.swift Outdated
@austinywang

Copy link
Copy Markdown
Contributor Author

Risk/rationale note after the review pass:

  • Driver 4 is the required architectural fix for the measured RSS/process-count issue: persistent cmux hooks codex monitor helpers are replaced by one in-app tailing registry, so the app no longer pays one process per active Codex session.
  • The low-risk boundary is that hook semantics and the V2 socket contract stay narrow: CLI hooks only request start/stop; TerminalController still owns workspace validation, notifications, status updates, and cleanup.
  • The follow-up commit kept behavior changes minimal: it mechanically moved the tailer to Sources/CodexTranscriptMonitor.swift, normalized start RPC IDs to match stop semantics, and publishes the existing .completion path on deadline to clear stale bell.fill status.
  • I am intentionally not converting the file-descriptor DispatchSource tailer to a broader async/await redesign in this PR. The current serial queue is the lifecycle boundary for fd events, retry/deadline timers, and parser state; replacing that now would be a larger concurrency rewrite than the performance fix requires.
  • CodeRabbit’s remaining aggregate pre-merge table is stale: file-boundary and deadline items are fixed in a11ce49b3; the print() lines it mentions existed on origin/main; Greptile now reports 5/5 confidence and safe to merge. CI remains the verification path per repo instructions.

@austinywang

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 13, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@austinywang
austinywang dismissed coderabbitai[bot]’s stale review May 13, 2026 22:46

Stale bot review: all three actionable threads were fixed in a11ce49, replied to, and resolved; CodeRabbit check is/was passing after fixes.

coderabbitai[bot]
coderabbitai Bot previously requested changes May 13, 2026

@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: 5

🤖 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 `@Sources/CodexTranscriptMonitor.swift`:
- Around line 437-439: The computed callId currently trims rawCallId but treats
whitespace-only strings as non-nil empty strings, defeating deduplication;
replace the trim logic to use the existing normalizedValue helper (or call
Self.normalizedValue(rawCallId)) so that whitespace-only/empty inputs become nil
and the fallback "\(payloadTurnId ?? requestTurnId ?? "session"):\(question ??
"request_user_input")" is used; update the assignment that defines callId
(references: rawCallId, callId, Self.firstString(in:keys:), normalizedValue,
payloadTurnId, requestTurnId, question) to call normalizedValue on rawCallId
before applying the nil-coalescing fallback.
- Around line 277-291: The current logic snapshots endOffset via
handle.seekToEnd() and later sets readOffset = endOffset, which can cause
re-reading appended bytes if the file grows between the snapshot and read;
update the logic in CodexTranscriptMonitor's handleFileEvent() (the block using
endOffset, readOffset, handle.seekToEnd(), handle.seek(toOffset:),
handle.readDataToEndOfFile(), and process(data:)) to advance readOffset by the
actual number of bytes read (data.count) after process(data:) instead of
assigning the earlier endOffset; specifically, after reading data =
handle.readDataToEndOfFile() and processing it, set readOffset +=
UInt64(data.count) (and handle the empty-data case safely), and retain the
existing out-of-range reset (if readOffset > endOffset) and pendingData.clear
behavior.
- Around line 81-85: The current publish(_ event: CodexTranscriptMonitorEvent)
uses Task { `@MainActor` in ... } which does not preserve FIFO ordering; replace
the Task call with a main-queue FIFO dispatch and explicit main-actor isolation
so events are delivered in order: use DispatchQueue.main.async {
MainActor.assumeIsolated {
TerminalController.shared.handleCodexTranscriptMonitorEvent(event) } } inside
publish(_:), ensuring
TerminalController.shared.handleCodexTranscriptMonitorEvent(event) is invoked on
the main actor with FIFO semantics; alternatively implement an AsyncStream
consumed by a single Task { `@MainActor` in for await event in stream {
TerminalController.shared.handleCodexTranscriptMonitorEvent(event) } } if you
prefer stream-based serialization.

In `@Sources/Workspace.swift`:
- Around line 6621-6663: Move the SidebarLogRingBuffer implementation out of
Sources/Workspace.swift into its own new Swift file (e.g.,
SidebarLogRingBuffer.swift) at module scope so it’s lifecycle-independent and
unit-testable; copy the struct and related symbols (SidebarLogRingBuffer,
SidebarLogEntry type references, init(limit:), replaceAll(_:limit:), append(_:),
removeAll(), entries()) into the new file, adjust access level from private to
internal/public as appropriate so tests can access it, remove the original
nested/private definition from Workspace.swift, and update any call sites to use
the relocated type; ensure the new file has no dependencies on AppKit/SwiftUI or
singletons so it compiles in isolation.
- Around line 6652-6655: The removeAll() currently only resets head and count,
leaving old SidebarLogEntry objects referenced in storage; update removeAll() to
also clear or release those references (e.g., nil out elements or replace
storage with an empty array) so stored SidebarLogEntry instances are
deallocated, then reset head and count as before; locate the removeAll() method
and the storage backing (storage, SidebarLogEntry) and perform the storage-clear
before resetting head/count.
🪄 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

Run ID: 82e1bca6-b093-449d-9e87-41bbfbe9fc04

📥 Commits

Reviewing files that changed from the base of the PR and between 8ca6cc9 and a11ce49.

📒 Files selected for processing (5)
  • CLI/cmux.swift
  • GhosttyTabs.xcodeproj/project.pbxproj
  • Sources/CodexTranscriptMonitor.swift
  • Sources/TerminalController.swift
  • Sources/Workspace.swift

Comment thread Sources/CodexTranscriptMonitor.swift Outdated
Comment thread Sources/CodexTranscriptMonitor.swift Outdated
Comment thread Sources/CodexTranscriptMonitor.swift Outdated
Comment thread Sources/Workspace.swift Outdated
Comment thread Sources/Workspace.swift Outdated
Comment thread Sources/CodexTranscriptMonitor.swift
Comment thread Sources/CodexTranscriptMonitor.swift Outdated
@austinywang
austinywang dismissed coderabbitai[bot]’s stale review May 13, 2026 23:46

Stale CodeRabbit changes-requested review from a11ce49; all five inline threads were fixed in aafacac, replied to, and resolved. Latest CodeRabbit review is COMMENTED.

coderabbitai[bot]
coderabbitai Bot previously requested changes May 13, 2026

@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: 1

🤖 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 `@Sources/Workspace.swift`:
- Around line 9843-9849: The timer's event handler uses MainActor.assumeIsolated
which unsafely asserts actor isolation; change the handler to perform an
explicit MainActor hop using Task { `@MainActor` in ... } so the call to
flushPendingSidebarLogEntries() runs on the main actor safely: inside the
setEventHandler closure (the one capturing [weak self]) unwrap self and call
Task { `@MainActor` in self.flushPendingSidebarLogEntries() } (or Task {
`@MainActor` in await self.flushPendingSidebarLogEntries() } if the method is
async), replacing the MainActor.assumeIsolated block and preserving the weak
self capture.
🪄 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

Run ID: 5efb541c-8bec-4c9a-9b0f-3286688dad9f

📥 Commits

Reviewing files that changed from the base of the PR and between a11ce49 and aafacac.

📒 Files selected for processing (4)
  • GhosttyTabs.xcodeproj/project.pbxproj
  • Sources/CodexTranscriptMonitor.swift
  • Sources/SidebarLogRingBuffer.swift
  • Sources/Workspace.swift

Comment thread Sources/Workspace.swift Outdated
@austinywang
austinywang dismissed coderabbitai[bot]’s stale review May 14, 2026 00:00

Stale CodeRabbit changes-requested review from aafacac; the single inline thread was fixed in b0d8f4f, replied to, and resolved.

Comment thread Sources/BackgroundWorkspacePrimeCoordinator.swift
Comment thread Sources/BackgroundWorkspacePrimeCoordinator.swift
Comment thread Sources/CodexTranscriptMonitor/CodexTranscriptMonitor.swift
Comment thread Sources/Workspace.swift
Comment thread Resources/Localizable.xcstrings
Comment thread Sources/CodexTranscriptMonitor/CodexTranscriptMonitor.swift
Comment thread Sources/CodexTranscriptMonitor/CodexTranscriptMonitor.swift
Comment thread Sources/CodexTranscriptMonitor/CodexTranscriptMonitor.swift

@cursor cursor 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.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 98c3485. Configure here.

Comment thread Sources/BackgroundWorkspacePrimeCoordinator.swift
Comment thread cmuxTests/TerminalControllerSocketWriteTests.swift
@lawrencecchen lawrencecchen added the stale-revisit Closed after 30+ days without activity; preserved for possible revisit or reopening. label Sep 23, 2026
@github-project-automation github-project-automation Bot moved this from Todo to Done in cmux backlog Sep 23, 2026

This branch was successfully deployed

1 active deployment
Preview – cmux — 0c3cc114 Deployed May 22, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stale-revisit Closed after 30+ days without activity; preserved for possible revisit or reopening.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

perf: cmux Swift app + 35 codex-monitor sidecars drive 250% CPU spikes with many active sessions

3 participants