Skip to content

Suppress codex's blocking startup update prompt on cmux-driven resumes - #7222

Merged
lawrencecchen merged 12 commits into
mainfrom
fix-codex-resume-update-prompt
Jul 4, 2026
Merged

lawrencecchen merged 12 commits into
mainfrom
fix-codex-resume-update-prompt

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Jul 2, 2026 •

Copy link
Copy Markdown
Contributor

After a cmux update restarts the app, auto-restored codex sessions can land on codex's blocking "Update available!" startup picker instead of the restored conversation, so the pane looks like the session never restarted. codex shows that picker whenever a new release is cached and no initial prompt is passed (openai/codex codex-rs/tui/src/lib.rs, run_update_prompt_if_needed), which is exactly the shape of every cmux-generated codex resume <id>.

Fix: inject codex's per-invocation config override -c check_for_update_on_startup=false into every cmux-generated codex resume command: the shared resume argv builder in AgentResumeArgv (covers close-and-reopen auto-restore and the cmux-cli surface-restore publisher), the codexTeams launcher resolution, and the sessions-panel resume command in SessionIndexModels. -c key=value is a clap-global flag in codex, so it is valid after the resume subcommand and overrides config for that process only; ~/.codex/config.toml and the user's own manual codex launches keep their update checks. Injection is skipped when the captured launch arguments already set check_for_update_on_startup, so an explicit user choice stays authoritative and restore-of-a-restore does not stack duplicate overrides (the codex sanitizer policy preserves -c key=value pairs).

Two-commit structure: the first commit updates/adds the resume-command expectations only (red), the second adds the fix (green).

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

🤖 Generated with Claude Code


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.


Note

Low Risk
Targeted argv/shell-string changes for codex resume only, with broad tests and no changes to user ~/.codex/config.toml or non-codex agents.

Overview
Fixes auto-restored codex panes landing on codex’s blocking “Update available!” picker instead of the conversation after cmux relaunch (typical when codex resume <id> has no initial prompt).

Every new cmux-generated codex resume path now appends a per-process -c check_for_update_on_startup=false via shared AgentResumeArgv (codex, codex-teams, CLI codex-teams shell quoting, and sessions-panel resume commands). Injection is skipped when captured args already set check_for_update_on_startup via -c/--config, so user choice stays authoritative and restore-of-restore stays idempotent.

Stale persisted agent-hook bindings are upgraded at replay (no migration): SurfaceResumeCommandCanonicalizer+CodexUpdateCheck parses shell strings and inserts the override after resume <id> (or after the thread id for resume --remote), including /bin/sh -c and codex wrapper-token bodies; this runs before portable-executable repair on hook bindings.

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


Summary by cubic

Stops codex’s blocking update prompt on cmux-driven resumes so panes return to the conversation after updates. Adds a per-process -c check_for_update_on_startup=false to all codex resume paths without changing user config.

  • Bug Fixes
    • Injects the override into all cmux-generated codex resumes: codex resume <id>, codex-teams resume <id>, and codex resume --remote <url> <thread> (shared AgentResumeArgv, sessions panel, CLI codex-teams launcher). Skips when args already set check_for_update_on_startup via -c, --config, or short equals forms (-c=…, --config=…) to honor user choice and avoid duplicates.
    • Upgrades stale persisted codex bindings at replay by inserting the override after resume <id> (or after the thread id for --remote); handles /bin/sh -c and wrapper-token forms, and runs before portable-executable repair.

Written for commit 589af22. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features / Improvements

    • Codex and Codex Teams resume flows now automatically inject a per-invocation startup update-check suppression flag to avoid the “Update available!” picker, including session replay/restore.
    • The flag is inserted at the correct location for both direct and wrapped command forms, and it won’t be duplicated when check_for_update_on_startup is explicitly set.
  • Tests

    • Updated and expanded unit/integration/sanitizer expectations for argv and shell command ordering, plus added coverage for normalization during persisted binding replay.

lawrencecchen and others added 2 commits July 2, 2026 15:41
codex's TUI shows a blocking "Update available!" picker at startup whenever
no initial prompt is passed, which is exactly the shape of every
cmux-generated `codex resume <id>`. After a cmux update restarts the app,
auto-restored codex panes land on that picker instead of the restored
conversation. Expect all cmux-generated codex resume commands (auto-restore
argv, codex-teams launcher, sessions-panel command) to carry the
per-invocation `-c check_for_update_on_startup=false` override.

Failing-test commit; the fix follows.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…esumes

codex shows a blocking "Update available!" picker at TUI startup whenever no
initial prompt is passed, which is the shape of every cmux-generated
`codex resume <id>`. After a cmux update restarted the app, auto-restored
codex panes sat on that picker instead of the restored conversation.

Inject codex's per-invocation config override
`-c check_for_update_on_startup=false` into every cmux-generated codex
resume command: the shared resume argv builder (auto-restore and cmux-cli
surface restore), the codex-teams launcher resolution, and the
sessions-panel resume command. The override affects only that process;
~/.codex/config.toml and manual codex launches keep their update checks.
Injection is skipped when the captured launch args already set
check_for_update_on_startup, so an explicit user choice wins and
restore-of-a-restore stays idempotent.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 2, 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 Jul 3, 2026 10:17am
cmux-staging Building Building Preview, Comment Jul 3, 2026 10:17am

@coderabbitai

coderabbitai Bot commented Jul 2, 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

Adds Codex resume suppression for the startup update-check prompt, wires it into resume-command construction and replay normalization, and updates expectations so Codex resume paths include -c check_for_update_on_startup=false unless already set.

Changes

Codex Update-Check Suppression

Layer / File(s) Summary
Suppression override and detection logic
Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentResumeArgv.swift
Adds codexUpdateCheckSuppressionOverride and codexResumeConfigOverrides(preserved:) to detect existing check_for_update_on_startup config settings before injecting the override.
Resume argv wiring
Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentResumeArgv.swift, Sources/SessionIndexModels.swift, CLI/cmux.swift, cmux.xcodeproj/project.pbxproj
Injects the override into Codex Teams and built-in Codex resume argv, appends it to SessionEntry and CLI command assembly, and wires the new source and test files into the project.
Resume command canonicalization
Sources/SurfaceResumeCommandCanonicalizer+CodexUpdateCheck.swift, Sources/SurfaceResumeCommandCanonicalizer+PortableAgentExecutable.swift, cmux.xcodeproj/project.pbxproj
Adds replay-time insertion of the suppression override for persisted Codex commands and applies it before portable executable replacement, with project wiring for the new source file.
Test coverage and expectations
Packages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentResumeArgvTests.swift, Packages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/CodexForkSanitizerTests.swift, cmuxTests/*.swift, cmux.xcodeproj/project.pbxproj
Updates existing resume expectations and adds coverage for injected suppression, explicit config preservation, and replayed Codex bindings, plus test-target project wiring.

Estimated code review effort: 4 (Complex) | ~45 minutes


Important

Pre-merge checks failed

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

❌ Failed checks (2 errors)

Check name Status Explanation Resolution
Cmux User-Facing Error Privacy ❌ Error SessionIndexView copies entry.resumeCommand, and SessionIndexModels now embeds -c check_for_update_on_startup=false in that user-visible command. Keep the update-check override internal-only; show a sanitized resume command in UI/clipboard and inject the flag only at launch time.
Cmux No Ambient Global State ❌ Error Adds a new static helper on the caseless SurfaceResumeCommandCanonicalizer enum, which is a static-namespace type and new ambient global surface. Move the codex update-check insertion logic onto a constructable, injectable owning type (or private/fileprivate helper) instead of extending the static namespace.
✅ Passed checks (23 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 Changes add pure argv/shell-string helpers and immutable value constants only; no new @MainActor isolation, mutable Sendable refs, or UI-store background access.
Cmux Swift Blocking Runtime ✅ Passed No new blocking waits, sleeps, syncs, or locks were added; the Swift edits are pure argv/shell-string rewriting.
Cmux Browser Automation Off-Main ✅ Passed PR only changes Codex resume/restore argv and related tests; no browser-automation router, policy, or worker-lane code was touched.
Cmux Expensive Synchronous Load ✅ Passed Diff only adds argv/string normalization for codex resumes; no new synchronous history loads, JSON parsing, or session-store I/O on main/interactive paths.
Cmux Cache Substitution Correctness ✅ Passed The PR normalizes persisted codex resume commands at replay time with graceful no-op fallbacks and explicit-flag preservation; it doesn’t replace a fresh authoritative read with cache.
Cmux No Hacky Sleeps ✅ Passed The PR diff only changes Swift files; no non-Swift runtime scripts were introduced or modified, and no sleeps/timers/polling appear in the changed files.
Cmux Algorithmic Complexity ✅ Passed Only small argv/token arrays are scanned once; no new nested rescans, hot-path rebuilds, or scalable collection joins were introduced.
Cmux Swift Concurrency ✅ Passed The diff only adds argv/string normalization and tests; no new DispatchQueue, Combine, completion-handler, or fire-and-forget Task patterns were introduced.
Cmux Swift @Concurrent ✅ Passed The diff only adds synchronous argv/string rewriting and tests; no new async helpers, actor isolation, or @concurrent annotations were introduced.
Cmux Swift File And Package Boundaries ✅ Passed PASS: The new codex suppression logic is small and isolated, the heavy argv builder lives in CMUXAgentLaunch, and app-target touches are narrow glue/tests only.
Cmux Swiftpm Lockfiles ✅ Passed PASS: cmux.xcodeproj only adds source files; no Package.swift, Package.resolved, .gitignore, or workflow dependency changes are present.
Cmux Swift Logging ✅ Passed The touched production Swift code only assembles argv/command strings; no added print/debugPrint/dump/NSLog/Logger appears in the changed runtime files.
Cmux Full Internationalization ✅ Passed The diff only changes Codex resume argv/shell construction and tests; no user-facing Swift text, catalogs, Info.plist, or web locale files were added or edited.
Cmux Swiftui State Layout ✅ Passed The PR only changes command-building/canonicalizer code and tests; no SwiftUI view files, @Observable/@published, GeometryReader, lazy row store refs, or render-time state writes were introduced.
Cmux Architecture Rethink ✅ Passed Pure argv/string normalization with one shared invariant; no sleeps, observers, locks, or split UI ownership were introduced.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PASS: Diff only touches argv/canonicalizer code; no NSWindow/NSPanel/WindowGroup or cmuxAuxiliaryWindowIdentifiers changes, so the auxiliary-window rule doesn't apply.
Cmux Source Artifacts ✅ Passed Only submodule gitlinks changed (ghostty, vendor/bonsplit); .gitmodules shows they’re intentional repo submodules, not generated artifacts.
Cmux No Test Or Debug Seam In Production Source ✅ Passed The changed Sources files add production helpers used by resume/canonicalizer code, with no #if DEBUG, test-only names, or test-accessor seams.
Title check ✅ Passed The title clearly matches the main change: suppressing Codex's startup update prompt on cmux-driven resume flows.
Description check ✅ Passed The description covers Summary and Review Trigger well, but it lacks explicit Testing, Demo Video, and checklist completion details.
✨ 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 fix-codex-resume-update-prompt

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.

@lawrencecchen

Copy link
Copy Markdown
Contributor Author

@codex review

@greptile-apps

greptile-apps Bot commented Jul 2, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a UX regression where cmux-driven codex resume commands could land on codex's blocking "Update available!" startup picker instead of the restored conversation, because codex resume <id> (no initial prompt) triggers the picker on every cached update.

  • Fix: Injects -c check_for_update_on_startup=false into every cmux-generated codex resume argv via the shared AgentResumeArgv builder (covering codex, codex-teams, and codex-teams --remote paths) and the sessions-panel resume command in SessionIndexModels; injection is guarded by hasExplicitCheckForUpdateOnStartupOverride so a user's explicit captured setting stays authoritative and restore-of-restore stays idempotent.
  • Stale binding upgrade: SurfaceResumeCommandCanonicalizer+CodexUpdateCheck inserts the override at replay time (not persistence) into older persisted agent-hook bindings, correctly handling direct codex commands, codex-teams commands, /bin/sh -c '…' wrappers, the codex wrapper-token form, and resume --remote <url> <thread> shapes; the insertion runs before portable-executable repair so the shell-wrapping step doesn't obscure the argv structure.

Confidence Score: 5/5

Safe to merge — targeted argv-manipulation changes with no mutations to persistent state or user config, covered by broad unit and integration tests.

All four resume code paths (AgentResumeArgv, SessionIndexModels, CLI codex-teams, stale-binding canonicalizer) receive well-scoped, tested changes. The idempotency guard is exercised for both two-token and equals-form variants. The ordering constraint (suppression before portable-executable repair) is correctly implemented and explained. No actor isolation, blocking runtime, or expensive sync-load concerns are introduced.

No files require special attention.

Important Files Changed

Filename Overview
Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentResumeArgv.swift Adds codexUpdateCheckSuppressionOverride static constant, the internal codexResumeConfigOverrides(preserved:) helper, and the public hasExplicitCheckForUpdateOnStartupOverride(in:) method; all three branches of the idempotency guard are logically correct.
Sources/SurfaceResumeCommandCanonicalizer+CodexUpdateCheck.swift New 188-line extension normalizing stale persisted codex bindings at replay; handles direct codex/codex-teams, sh/zsh/bash wrapper forms, codex wrapper-token form, and --remote thread-id placement.
Sources/SurfaceResumeCommandCanonicalizer+PortableAgentExecutable.swift Widens commandExecutableWordIndex from private static to internal static for cross-extension production use; correctly orders suppression insertion before portable-executable repair.
Sources/SessionIndexModels.swift Appends the override unconditionally in the sessions-panel resume command builder (intentional: builds from structured settings, not raw captured argv).
CLI/cmux.swift Appends codexUpdateCheckSuppressionOverride after threadId in the CLI codex-teams --remote resume path; correct placement per clap's global-flag semantics.
cmuxTests/SurfaceResumeBindingCodexUpdateCheckTests.swift New 188-line test suite covering all stale binding shapes, idempotency, claude passthrough, remote resume, and wrapper-token forms.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[cmux relaunch / auto-restore] --> B{Resume path}
    B --> C[AgentResumeArgv]
    B --> D[SessionIndexModels]
    B --> E[CLI codexTeams remote resume]
    B --> F[Stale binding replay]
    C --> G{override already in preserved args?}
    G -- No --> H[inject -c check_for_update_on_startup=false]
    G -- Yes --> I[skip injection]
    D --> J[unconditionally append override]
    E --> K[append override after threadId]
    F --> L[SurfaceResumeCommandCanonicalizer]
    L --> M{kind == codex or nil?}
    M -- No --> N[return unchanged]
    M -- Yes --> O{override already present?}
    O -- Yes --> N
    O -- No --> Q{command shape?}
    Q -- direct --> R[insert after session id]
    Q -- remote resume --> S[insert after thread id]
    Q -- sh wrapper --> T[recurse into body]
    Q -- wrapper token --> U[strip token then offset insert]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[cmux relaunch / auto-restore] --> B{Resume path}
    B --> C[AgentResumeArgv]
    B --> D[SessionIndexModels]
    B --> E[CLI codexTeams remote resume]
    B --> F[Stale binding replay]
    C --> G{override already in preserved args?}
    G -- No --> H[inject -c check_for_update_on_startup=false]
    G -- Yes --> I[skip injection]
    D --> J[unconditionally append override]
    E --> K[append override after threadId]
    F --> L[SurfaceResumeCommandCanonicalizer]
    L --> M{kind == codex or nil?}
    M -- No --> N[return unchanged]
    M -- Yes --> O{override already present?}
    O -- Yes --> N
    O -- No --> Q{command shape?}
    Q -- direct --> R[insert after session id]
    Q -- remote resume --> S[insert after thread id]
    Q -- sh wrapper --> T[recurse into body]
    Q -- wrapper token --> U[strip token then offset insert]
Loading

Reviews (10): Last reviewed commit: "Handle short codex config override form" | Re-trigger Greptile

Comment thread Sources/SessionIndexModels.swift Outdated
// wrapped in `/bin/sh -c '…'`; the `cd` guard stays outside in
// `resumeCommandWithCwd`. https://github.com/manaflow-ai/cmux/issues/5639
var parts = ["\(AgentResumeArgv.codexWrapperShellExecutableToken) resume \(sessionId)"]
parts.append(AgentResumeArgv.codexUpdateCheckSuppressionOverride.joined(separator: " "))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Unconditional injection bypasses the documented idempotency guard

The PR description says "injection is skipped when the captured launch arguments already set check_for_update_on_startup, so an explicit user choice stays authoritative." That guarantee is enforced in the AgentResumeArgv code paths via codexResumeConfigOverrides(preserved:), which inspects the raw sanitizer-preserved argv before injecting. This sessions-panel path, however, always appends the override unconditionally — no guard against a user who had -c check_for_update_on_startup=true in their original invocation. Because check_for_update_on_startup is not stored as a structured field in SessionEntry.agent.codex, the sessions-panel resume command cannot check for it, so the user's explicit preference is silently overridden for every sessions-panel resume. The workaround (~/.codex/config.toml) is also ineffective: the per-invocation -c override takes precedence over the config file, so a user with check_for_update_on_startup = true in toml would still have it suppressed for all cmux-driven resumes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Intentional: the sessions-panel command is built from per-session captured settings (model/approval/sandbox/effort), which don't include the launch argv, so there is nothing to dedup against there. The command is displayed and copy-pastable, so the flag is visible and editable before running. The automated paths (auto-restore argv, persisted-binding replay) do respect an explicit captured check_for_update_on_startup setting.

Comment on lines 118 to 148
executablePath: "/opt/bin/codex",
arguments: ["/opt/bin/codex"]
) == ["/opt/bin/codex", "resume", "SID"]
) == ["/opt/bin/codex", "resume", "SID", "-c", "check_for_update_on_startup=false"]
)
}

@Test("Codex resume suppresses codex's blocking startup update prompt per-invocation")
func codexResumeSuppressesStartupUpdatePrompt() {
// `codex resume <id>` passes no initial prompt, so codex's TUI shows a blocking
// "Update available!" picker before restoring the session — a cmux relaunch that
// auto-restores codex panes lands them on that prompt instead of the conversation.
// The per-invocation `-c` override keeps cmux-driven restores non-interactive
// without mutating the user's ~/.codex/config.toml, and it precedes the preserved
// launch arguments so a user-captured explicit override still wins.
let overrides = ["-c", "check_for_update_on_startup=false"]
#expect(
AgentResumeArgv().builtInKind(
kind: "codex",
sessionId: "SID",
executablePath: nil,
arguments: ["codex", "--model", "gpt-5.4"]
) == ["codex", "resume", "SID"] + overrides + ["--model", "gpt-5.4"]
)
#expect(
AgentResumeArgv().launcherResolution(
launcher: "codexTeams",
sessionId: "SID",
executablePath: nil,
arguments: ["cmux", "codex-teams", "--model", "gpt-5.4"]
) == .resolved(["cmux", "codex-teams", "resume", "SID"] + overrides + ["--model", "gpt-5.4"])
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Deduplication guard is untested

codexResumeConfigOverrides(preserved:) has three distinct early-return branches: the two-token -c/--config form, the single-token --config=check_for_update_on_startup= form, and the out-of-bounds guard when -c is the last element. None of these branches are exercised by the new test. If the idempotency logic has a bug — for instance, a captured session that was already a cmux-driven restore and thus has -c check_for_update_on_startup=false in its preserved args — the duplicate injection would go undetected. A few #expect cases with preserved containing each variant would close this gap.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Dedup-branch coverage added in 9fb1b1e049 (explicit true/false pair forms for both builtInKind and the codexTeams launcher). The --config= single-token form is defensive; the sanitizer normalizes captured pairs, so it isn't reachable from real captures.

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

ℹ️ 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".

/// `check_for_update_on_startup` (see ``codexResumeConfigOverrides(preserved:)``):
/// that keeps an explicit user choice authoritative and keeps restore-of-a-restore
/// idempotent, since the codex sanitizer policy preserves `-c key=value` pairs.
public static let codexUpdateCheckSuppressionOverride = ["-c", "check_for_update_on_startup=false"]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Apply update suppression to Codex Teams subagent resumes

When the Codex Teams watcher opens a spawned subagent pane, codexTeamsResumeCommandText in CLI/cmux.swift:20309-20320 still builds env ... codex resume --remote <url> <threadId> without this override. That resume has no initial prompt, so the same cached-update picker can still block Codex Teams subagent panes even though the root codex/codex-teams resume paths are suppressed; please reuse this shared override on that path as well.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 50c89522f0: codexTeamsResumeCommandText now appends the shared override tokens, so spawned subagent panes resume with the update check suppressed too.

@cubic-dev-ai cubic-dev-ai 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.

2 issues found across 7 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="Sources/SessionIndexModels.swift">

<violation number="1" location="Sources/SessionIndexModels.swift:352">
P2: This resume-command path always appends `-c check_for_update_on_startup=false`, which can override a session that was originally launched with an explicit `check_for_update_on_startup=true`. Consider adding the same idempotency check used in `codexResumeConfigOverrides(preserved:)` (or persisting this setting in session metadata) so explicit user config is preserved.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread Sources/SessionIndexModels.swift Outdated
// wrapped in `/bin/sh -c '…'`; the `cd` guard stays outside in
// `resumeCommandWithCwd`. https://github.com/manaflow-ai/cmux/issues/5639
var parts = ["\(AgentResumeArgv.codexWrapperShellExecutableToken) resume \(sessionId)"]
parts.append(AgentResumeArgv.codexUpdateCheckSuppressionOverride.joined(separator: " "))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: This resume-command path always appends -c check_for_update_on_startup=false, which can override a session that was originally launched with an explicit check_for_update_on_startup=true. Consider adding the same idempotency check used in codexResumeConfigOverrides(preserved:) (or persisting this setting in session metadata) so explicit user config is preserved.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Sources/SessionIndexModels.swift, line 352:

<comment>This resume-command path always appends `-c check_for_update_on_startup=false`, which can override a session that was originally launched with an explicit `check_for_update_on_startup=true`. Consider adding the same idempotency check used in `codexResumeConfigOverrides(preserved:)` (or persisting this setting in session metadata) so explicit user config is preserved.</comment>

<file context>
@@ -349,6 +349,7 @@ struct SessionEntry: Identifiable, Hashable {
             // wrapped in `/bin/sh -c '…'`; the `cd` guard stays outside in
             // `resumeCommandWithCwd`. https://github.com/manaflow-ai/cmux/issues/5639
             var parts = ["\(AgentResumeArgv.codexWrapperShellExecutableToken) resume \(sessionId)"]
+            parts.append(AgentResumeArgv.codexUpdateCheckSuppressionOverride.joined(separator: " "))
             if let model, !model.isEmpty {
                 parts.append("-m \(Self.shellQuote(model))")
</file context>

lawrencecchen and others added 2 commits July 2, 2026 15:56
Fold the update-check override into the initial parts literal so the file
stays at its budgeted line count.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Greptile flagged the early-return branches of codexResumeConfigOverrides as
untested: an explicit captured check_for_update_on_startup setting must stay
authoritative, and restore-of-a-restore must not stack duplicate overrides.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@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: 9fb1b1e049

ℹ️ 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 on lines +310 to +311
return [parts.executable, "resume", sessionId]
+ Self.codexResumeConfigOverrides(preserved: preserved) + preserved

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Normalize persisted Codex resume bindings before restore

On the first launch after updating from a build that saved an agent-hook resume binding, workspace restore does not call this new AgentResumeArgv path: Workspace.createPanel builds restoredBindingLaunch from the persisted SurfaceResumeBindingSnapshot.command and then suppresses the restorable-agent launch, so an existing saved command like 'codex' 'resume' '<id>' still runs without -c check_for_update_on_startup=false. That is the relaunch-after-update path this change is meant to fix; please canonicalize/migrate Codex resume bindings as they are decoded/restored, or let the regenerated restorable-agent command override matching stale bindings.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 50c89522f0: binding replay now normalizes stale codex resume bindings via SurfaceResumeCommandCanonicalizer.insertingCodexUpdateCheckSuppression (inserted after the parsed resume words, before the stale-executable repair so sh-wrapped repairs don't hide the argv). Commands that already set check_for_update_on_startup, non-codex kinds, and shapes that don't parse as a codex resume argv replay unchanged and self-heal on the next hook persist. Covered by SurfaceResumeBindingCodexUpdateCheckTests.

Codex review flagged two gaps in the update-prompt suppression:

Codex Teams subagent panes: the watcher-built subagent resume command
(codexTeamsResumeCommandText) ran `codex resume --remote <url> <thread>`
without the override, so spawned teammate panes could still hit the blocking
update picker. The shared override tokens are now appended there too.

Stale persisted bindings: agent-hook resume bindings are persisted rendered
shell strings, so bindings saved by a cmux build before this change replay
verbatim on the FIRST relaunch after updating cmux, which is exactly the
reported scenario. Replay now normalizes stale codex bindings by inserting
the override directly after the parsed `resume <session-id>` words
(insertingCodexUpdateCheckSuppression), before the existing stale-executable
repair so /bin/sh-wrapped repairs don't hide the argv. Commands that already
set check_for_update_on_startup, non-codex kinds, and shapes that don't
parse as a codex resume argv (remote thread resumes, sh-wrapped bodies)
replay unchanged; the unparsed shapes self-heal on the next hook persist.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@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 50c8952. Configure here.

Comment thread Sources/SurfaceResumeCommandCanonicalizer+CodexUpdateCheck.swift

@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: 50c89522f0

ℹ️ 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 on lines +35 to +38
guard sessionIndex < words.count,
words[resumeIndex].value == "resume",
!words[sessionIndex].value.hasPrefix("-") else {
return command

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Normalize wrapped Codex resume bindings too

Fresh evidence in this revision: the new replay normalizer still only accepts commands whose parsed word after the executable (or codex-teams) is resume. Existing agent-hook bindings saved by builds since the wrapper-shim change are rendered as cd ... && /bin/sh -c '<codex wrapper> resume <id> ...' from RestorableAgentSession.resumeCommand; for those, commandExecutableWordIndex returns /bin/sh, so this guard sees -c instead of resume and returns the stale command unchanged. Those users still hit the Codex update picker on the first relaunch after updating, which is the migration path this normalizer is meant to cover.

Useful? React with 👍 / 👎.

@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 `@cmuxTests/SurfaceResumeBindingCodexUpdateCheckTests.swift`:
- Around line 16-99: Add a test covering the stale codex replay path that goes
through remoteStartupInputWithLauncherScript, since this branch currently skips
update-check suppression when repairPortableAgentExecutable is gated off. Extend
SurfaceResumeBindingCodexUpdateCheckTests with a stale codex case that exercises
SurfaceResumeBindingSnapshot.startupInput for the remote launcher-script shape
and assert the replayed input includes check_for_update_on_startup=false for
codex/codex-teams-style resumes.
🪄 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: 3e593f9e-4938-4309-8f70-288b395497f6

📥 Commits

Reviewing files that changed from the base of the PR and between 9fb1b1e and 50c8952.

📒 Files selected for processing (5)
  • CLI/cmux.swift
  • Sources/SurfaceResumeCommandCanonicalizer+CodexUpdateCheck.swift
  • Sources/SurfaceResumeCommandCanonicalizer+PortableAgentExecutable.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/SurfaceResumeBindingCodexUpdateCheckTests.swift

Comment thread cmuxTests/SurfaceResumeBindingCodexUpdateCheckTests.swift

@cubic-dev-ai cubic-dev-ai 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.

3 issues found across 5 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="Sources/SessionIndexModels.swift">

<violation number="1" location="Sources/SessionIndexModels.swift:352">
P2: This resume-command path always appends `-c check_for_update_on_startup=false`, which can override a session that was originally launched with an explicit `check_for_update_on_startup=true`. Consider adding the same idempotency check used in `codexResumeConfigOverrides(preserved:)` (or persisting this setting in session metadata) so explicit user config is preserved.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread Sources/SurfaceResumeCommandCanonicalizer+CodexUpdateCheck.swift Outdated
Comment thread Sources/SurfaceResumeCommandCanonicalizer+CodexUpdateCheck.swift Outdated
Comment thread Sources/SurfaceResumeCommandCanonicalizer+CodexUpdateCheck.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: dbda5a2e5a

ℹ️ 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 on lines +66 to +68
guard sessionIndex < words.count,
words[resumeIndex].value == "resume",
!words[sessionIndex].value.hasPrefix("-") else {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Normalize remote Codex resume bindings

When replaying a persisted agent-hook binding whose command is the Codex Teams remote attach form (codex resume --remote <url> <thread>), this guard returns because the word after resume is --remote, so the stale command is left without -c check_for_update_on_startup=false. Fresh evidence in this revision is the new remote-binding replay path that intentionally leaves this exact shape unchanged, even though codexTeamsResumeCommandText now adds the override for newly opened subagent panes; users with subagent panes saved before updating can still land on Codex's blocking startup update picker on the first relaunch. Handle the remote shape by inserting after the thread id rather than skipping it.

Useful? React with 👍 / 👎.

@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/SurfaceResumeCommandCanonicalizer`+CodexUpdateCheck.swift:
- Around line 155-167: The override-detection logic is duplicated between
codexResumeConfigOverrideAlreadyPresent(in:) and
AgentResumeArgv.codexResumeConfigOverrides(preserved:), so factor the shared
-c/--config check_for_update_on_startup= scan into a single helper on
AgentResumeArgv and call it from both places. Keep the existing behavior, but
make the canonicalizer reuse the shared helper instead of reimplementing the
loop so the resume-argv builder and replay path stay in sync.
🪄 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: a56773d9-fcc7-449d-9455-3c95d8a0be1c

📥 Commits

Reviewing files that changed from the base of the PR and between 50c8952 and dbda5a2.

📒 Files selected for processing (3)
  • Sources/SurfaceResumeCommandCanonicalizer+CodexUpdateCheck.swift
  • Sources/SurfaceResumeCommandCanonicalizer+PortableAgentExecutable.swift
  • cmuxTests/SurfaceResumeBindingCodexUpdateCheckTests.swift

Comment thread Sources/SurfaceResumeCommandCanonicalizer+CodexUpdateCheck.swift

@cubic-dev-ai cubic-dev-ai 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.

1 issue found across 3 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="Sources/SessionIndexModels.swift">

<violation number="1" location="Sources/SessionIndexModels.swift:352">
P2: This resume-command path always appends `-c check_for_update_on_startup=false`, which can override a session that was originally launched with an explicit `check_for_update_on_startup=true`. Consider adding the same idempotency check used in `codexResumeConfigOverrides(preserved:)` (or persisting this setting in session metadata) so explicit user config is preserved.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread Sources/SurfaceResumeCommandCanonicalizer+CodexUpdateCheck.swift
@lawrencecchen
lawrencecchen merged commit 3eabcfa into main Jul 4, 2026
36 checks passed
@lawrencecchen
lawrencecchen deleted the fix-codex-resume-update-prompt branch July 4, 2026 04:48
azooz2003-bit added a commit that referenced this pull request Jul 4, 2026
…ng, themes)

Delta: #7318/#7319 mouse cursor-shape + right/middle drag forwarding, #7320 ghostty
upstream, #6664 iOS themes, #7196 iOS scroll, #7257/#7307 web, #7329 CLI suggestions,
#7222 codex resume update-suppression. Conflicts resolved keeping HEAD structure:
- GhosttyTerminalView.swift: took main's viewDidEndLiveResize + resetCursorRects
  (cursor-shape #7318; ghosttyMouseShape/ghosttyMouseCursor already in HEAD).
- Mobile/MobileHostService.swift: union (kept HEAD sharedRequestActivity +
  main publicStatusPayload theme payload #6664).
- project.pbxproj: union-dedup, normalized; test-wiring green.
- swift-file-length-budget.tsv regenerated.

#7222 (codex update-check suppression) partially landed: the CMUXAgentLaunch package
part (AgentResumeArgv.codexUpdateCheckSuppressionOverride) auto-merged and is present;
the app-target files (+CodexUpdateCheck.swift + test) extend SurfaceResumeCommandCanonicalizer,
a type HEAD dissolved into the CmuxWorkspaces package, so they can't compile and the
suppression was never wired (call site was in the HEAD-deleted +PortableAgentExecutable).
Removed those two files; re-wire recorded in merge-deferred-gaps.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@lawrencecchen
lawrencecchen restored the fix-codex-resume-update-prompt branch July 18, 2026 10:24

This branch was successfully deployed

1 active deployment
Preview – cmux — 589af22e Deployed Jul 3, 2026 by vercel[bot]
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.

1 participant