Skip to content

Add native OMO Slim launchers - #8165

Closed
guanbear wants to merge 5 commits into
manaflow-ai:mainfrom
guanbear:codex/omo-slim-native
Closed

guanbear wants to merge 5 commits into
manaflow-ai:mainfrom
guanbear:codex/omo-slim-native

Conversation

@guanbear

@guanbear guanbear commented Jul 15, 2026 •

Copy link
Copy Markdown

Background

PR #7712 introduced OMO Slim support through the same tmux shim and shadow-config path used by the existing cmux omo launcher.

Since then, OMO Slim 2.2.x has added native cmux multiplexer support. It detects the cmux socket/workspace/surface context and owns child-pane creation and lifecycle itself. Keeping a second tmux compatibility layer in cmux would duplicate that behavior, override user configuration, and make the integration more fragile.

This PR supersedes #7712 with a smaller first-class launcher integration.

What changed

  • Add cmux omo-slim and the shorter cmux omos alias locally and through cmuxd-remote.
  • Pass CMUX_SOCKET_PATH, focused workspace/surface IDs, an available OpenCode API port, and the background-subagent feature flag.
  • Preserve the active OpenCode and OMO Slim configuration; cmux does not install the plugin or create a shadow config.
  • Let OMO Slim 2.2+ create and manage native cmux agent panes.
  • Recognize both launcher names in launch capture, agent detection, session resume, session fork, trust checks, and task-manager metadata.
  • Add localized CLI help and regression coverage for launcher replay.

Non-goals

  • Reimplement OMO Slim pane layout or lifecycle in cmux.
  • Emulate tmux for OMO Slim.
  • Install or mutate the user’s OMO Slim configuration.

Validation

  • go test ./cmd/cmuxd-remote
  • swiftc -parse for all touched Swift sources
  • jq empty Resources/Localizable.xcstrings
  • git diff --check upstream/main...HEAD

The full Swift package test and tagged app build could not run on this machine because only Command Line Tools are installed, its Swift compiler/SDK versions are mismatched, and full Xcode is unavailable.

Closes and supersedes #7712.


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


Summary by cubic

Adds native OMO Slim launchers to cmux so OMO Slim 2.2+ owns cmux panes directly, replacing the tmux shim and preserving user opencode/OMO Slim config. Remote relay now clears ambient cmux identity and relies on inherited workspace/surface; wrapper sessions are handled uniformly to avoid plain opencode probes.

  • New Features

    • Added cmux omo-slim and alias cmux omos in cmux and cmuxd-remote.
    • Native launch passes cmux context; respects --port (otherwise picks a free OPENCODE_PORT); enables background subagents; all args pass through to opencode.
    • Localized CLI help; tests cover launcher arg sanitization, fork/resume preserving the launcher name, and remote port handling.
  • Bug Fixes

    • Dropped removed focus API; native launch now relies on inherited CMUX_WORKSPACE_ID/CMUX_SURFACE_ID.
    • Remote launcher clears ambient CMUX_WORKSPACE_ID/CMUX_SURFACE_ID before applying the resolved context.
    • Treat omo-slim/omos like omo in fork/resume and version probes; wrapper sessions aren’t probed as plain opencode.
    • Suppress raw syscall.Exec errors in the remote path; added tests for explicit and auto --port handling.

Written for commit 45aba72. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features
    • Added the omo-slim command and omos alias for launching OpenCode through cmux.
    • Added automatic port selection, workspace and surface context, background subagent support, and argument forwarding.
    • Added localized usage instructions and examples.
  • Bug Fixes
    • Expanded OpenCode alias recognition across launching, resuming, forking, and session availability.
  • Tests
    • Added coverage for aliases, session workflows, argument handling, and automatic port selection.

Note

Medium Risk
Introduces a new agent launch and remote relay path with port and workspace identity wiring; session fork/resume behavior changes for wrapper launchers but follows existing omo patterns and adds test coverage.

Overview
Adds cmux omo-slim and the omos alias as a first-class launch path for OpenCode with oh-my-opencode-slim 2.2+, using OMO Slim’s native cmux multiplexer instead of the legacy omo tmux shim and shadow-config flow.

The new launcher (local runOMOSlim and remote runOMOSlimRelay) sets socket/workspace/surface context, picks or honors an OpenCode API port, enables background subagents, and execs opencode without installing plugins or mutating user config.

omo, omo-slim, and omos are treated uniformly as OpenCode session wrappers across launch capture trust, fork/resume argv replay, sanitization, agent detection, fork diagnostics, and session-list availability—wrapper sessions skip plain opencode version probing where appropriate. CLI suggestions, built-in agent metadata, and localized usage text cover the new commands.

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

@vercel

vercel Bot commented Jul 15, 2026

Copy link
Copy Markdown

@guanbear is attempting to deploy a commit to the Manaflow Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jul 15, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds omo-slim and omos CLI aliases with native and remote launch paths, OpenCode port and environment setup, expanded launcher recognition, fork and resume support, localized help, and tests.

Changes

OMO Slim integration

Layer / File(s) Summary
OpenCode launcher alias contracts
Packages/macOS/CMUXAgentLaunch/...
OpenCode wrapper detection, argument sanitization, fork resolution, resume resolution, and tests recognize omo-slim and omos.
Native CLI launch path
CLI/cmux.swift, CLI/CMUXCLI+CommandSuggestions.swift
CLI dispatch, help text, environment setup, port selection, command suggestions, and executable handoff implement the new aliases.
Remote relay launch path
daemon/remote/cmd/cmuxd-remote/...
Remote dispatch configures cmux context, selects an OpenCode port, injects missing port arguments, and executes OpenCode.
Capability and support integration
Sources/..., Resources/Localizable.xcstrings, CLI/CMUXCLI+SessionsListForkDiagnostics.swift
Fork checks, capability detection, version probing, built-in detection, identity aliases, and localized usage include the new launchers.

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

Sequence Diagram(s)

sequenceDiagram
  participant CLI
  participant Launcher
  participant OpenCode
  CLI->>Launcher: dispatch omo-slim or omos
  Launcher->>Launcher: configure cmux context and select port
  Launcher->>OpenCode: execute with forwarded arguments
Loading

Suggested reviewers: austinywang, lawrencecchen


Important

Pre-merge checks failed

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

❌ Failed checks (3 errors, 1 warning)

Check name Status Explanation Resolution
Cmux User-Facing Error Privacy ❌ Error New production stderr/errors expose the upstream name opencode and environment variable PATH in missing-executable and launch-failure messages; these are not tests or help text. Use generic cmux error text for executable and launch failures. Keep provider names, environment variables, and raw system details in sanitized internal diagnostics.
Cmux Full Internationalization ❌ Error New Swift error text in runOMOSlim uses a raw CLIError string and has no localized API or catalog entry; the usage key itself covers all 20 catalog locales. Route the launch-failure message through String(localized:defaultValue:) and add translated values for all 20 locales in Resources/Localizable.xcstrings.
Cmux No Ambient Global State ❌ Error AgentLaunchCaptureTrust.swift:62 adds public static func launcherIsOpenCodeSessionWrapper to the caseless, static-only AgentLaunchCaptureTrust namespace, creating new ambient API. Make launcher trust a constructable AgentLaunchCaptureTrust instance with injected wrapper policy, and inject it at the fork, resume, diagnostics, and view seams.
Docstring Coverage ⚠️ Warning Docstring coverage is 34.38% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (21 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 No changed Swift declaration adds implicit MainActor state or an unsafe Sendable reference; launcher logic is pure/value-based, CLI state is local, and the ContentView use is an allowed UI type.
Cmux Swift Blocking Runtime ✅ Passed The production Swift diff adds launcher routing, environment setup, argv handling, and pure alias checks; it adds no semaphore, wait, sleep, timer, polling, main-sync, or lock primitive.
Cmux Browser Automation Off-Main ✅ Passed The full main..HEAD diff changes no browser automation files or routing symbols; neither rule-scoped file is modified, so no WebKit wait is moved off the required lane.
Cmux Expensive Synchronous Load ✅ Passed The Swift diff adds no synchronous agent-history or large-file loads. runOMOSlim only resolves an executable, selects a port, exports environment, and execs; RestorableAgentSession skips wrappe...
Cmux Cache Substitution Correctness ✅ Passed The diff adds launcher/env handling and broadens wrapper checks; it does not replace a fresh persistence, history, undo, or snapshot read with a cache.
Cmux No Hacky Sleeps ✅ Passed The cumulative PR diff adds no sleep, timer, polling, retry-delay, or wall-clock synchronization in non-Swift runtime code; OMO Slim port selection uses net.Listen only.
Cmux Algorithmic Complexity ✅ Passed New production scans are linear over launch arguments (Go lines 198 and 207); wrapper aliases use a fixed three-item Set, with no nested scans or hot-path record collection work added.
Cmux Swift Concurrency ✅ Passed The Swift diff adds no legacy async, DispatchQueue, Combine, completion-handler, or fire-and-forget Task pattern; runOMOSlim is synchronous throwing exec logic, and existing patterns remain unchanged.
Cmux Swift @Concurrent ✅ Passed The Swift diff changes only synchronous runOMOSlim and fork-validation logic; it adds no nonisolated async work, @concurrent annotation, or UI-isolated heavy async call site.
Cmux Swift Package Boundaries ✅ Passed The reusable wrapper, sanitizer, resume/fork, and trust logic is in CMUXAgentLaunch with isolated tests; app and CLI changes are integration, metadata, and process-launch composition.
Cmux Swiftpm Lockfiles ✅ Passed PR changes no Package.swift, Package.resolved, .gitignore, workflow, or Xcode project metadata; CMUXAgentLaunch has no external deps, and only vendor/bonsplit preserves the ignored lockfile policy.
Cmux Swift Logging ✅ Passed The Swift diff adds no print, debugPrint, dump, NSLog, ad hoc diagnostics, or Logger declarations; new usage text is intended CLI output.
Cmux Swiftui State Layout ✅ Passed The Swift diff only adds CMUXAgentLaunch and updates a fork predicate in ContentView; state/layout construct counts are unchanged, with no new render-time state writes.
Cmux Architecture Rethink ✅ Passed Swift changes add no new timing, blocking, observer, lock, or UI lifecycle code; both aliases share runOMOSlim, and wrapper semantics use one centralized predicate.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed The Swift diff adds launcher, detection, replay, and test logic only. It adds no standalone window API, identifier assignment, or close-shortcut workaround for scripts/lint_auxiliary_window_close_s...
Cmux Source Artifacts ✅ Passed All 20 changed paths are tracked Swift/Go source, tests, or localization files; no scratch directories, artifact-like paths, binary additions, logs, or build output appear.
Cmux No Test Or Debug Seam In Production Source ✅ Passed Changed production Swift adds no test/debug guard or test-named seam; the new launcherIsOpenCodeSessionWrapper helper has five production callers and implements real wrapper behavior.
Title check ✅ Passed The title clearly and concisely describes the main change: adding native OMO Slim launchers.
Description check ✅ Passed The description clearly covers the change, rationale, scope, and validation, although it does not use every template heading.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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 15, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

Adds first-class cmux omo-slim / cmux omos launchers that hand off pane creation and lifecycle to OMO Slim 2.2+, replacing the previous tmux-shim approach from PR #7712. Both the local Swift launcher and the cmuxd-remote Go relay are updated symmetrically, and all downstream recognition points (session resume, fork, agent detection, trust, task-manager metadata) are updated in a single consistent sweep.

  • New launchers: runOMOSlim (Swift) and runOMOSlimRelay (Go) set CMUX_SOCKET_PATH, query focused workspace/surface context, pick a free OPENCODE_PORT (dynamic selection rather than the fixed 4096 used by omo), enable OPENCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS, and exec opencode with the resolved port injected into argv.
  • Single source of truth for session-wrapper identity: openCodeSessionWrapperLaunchers in AgentLaunchCaptureTrust is now the authority for both launcherIsOpenCodeSessionWrapper() and the opencode subset of wrapperLaunchersByKind, eliminating the inline-literal duplication flagged on the prior PR and replacing every hardcoded launcher == \"omo\" guard across ContentView, AgentForkSupport, and RestorableAgentSession.
  • Localization: cli.omoSlim.usage is translated into all 20 supported app locales; fork/resume/sanitizer arg tests cover both new launcher names.

Confidence Score: 5/5

Safe to merge; the changes are well-scoped launcher additions with no mutations to the user's opencode or OMO Slim configuration.

All correctness-critical paths — session resume, fork, trust checks, agent detection — are updated consistently via the new launcherIsOpenCodeSessionWrapper helper that derives from a single authoritative set. The only noteworthy concern is a small TOCTOU window in the Go relay's dynamic port selection: the ephemeral listener is closed when openCodeNativeEffectivePort returns, marginally before syscall.Exec runs, leaving a brief window where another process could claim the port. The window is tiny and the behavior is strictly better than the hardcoded fallback used by the existing omo relay.

daemon/remote/cmd/cmuxd-remote/agent_launch.go — specifically openCodeNativeEffectivePort's defer-close/exec gap.

Important Files Changed

Filename Overview
daemon/remote/cmd/cmuxd-remote/agent_launch.go Adds runOMOSlimRelay and helpers openCodeNativeEffectivePort/openCodeNativeLaunchArgs; dynamic port selection has a small TOCTOU window, otherwise clean.
Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchCaptureTrust.swift Extracts openCodeSessionWrapperLaunchers set as the single source of truth for both launcherIsOpenCodeSessionWrapper and wrapperLaunchersByKind["opencode"]; well-structured improvement over the old inline literals.
Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentForkArgv.swift Extends omo case to cover omo-slim/omos, uses guard let launcherName = launcher instead of the old dead ?? "omo" fallback; correct and clean.
Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentResumeArgv.swift Mirror of AgentForkArgv changes; correctly uses guard let launcherName = launcher to preserve the real launcher name across resume argv reconstruction.
CLI/cmux.swift Adds runOMOSlim dispatch block and help text; correctly sets CMUX_SOCKET_PATH, queries focused context only when IDs are absent, and prepends --port only when not user-supplied.
Sources/CmuxTaskManagerCodingAgentDefinition+BuiltIns.swift Adds omo-slim/omos to launchKinds, directBasenames, and argumentNeedles for OpenCode agent definition; consistent with existing pattern.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant U as User
    participant CLI as cmux CLI (Swift)
    participant RD as cmuxd-remote (Go)
    participant OCS as OpenCode + OMO Slim 2.2+
    participant CM as cmux daemon

    U->>CLI: cmux omo-slim [args]
    CLI->>CLI: resolveOpenCodeExecutable()
    CLI->>CM: tmuxCompatFocusedContext() if WORKSPACE/SURFACE absent
    CM-->>CLI: workspaceId, surfaceId
    CLI->>CLI: omoResolvedPort() pick free port
    CLI->>CLI: exportAgentLaunchCommandEnvironment()
    CLI->>OCS: execv(opencode, [--port P, ...args])
    OCS->>CM: connect via CMUX_SOCKET_PATH
    OCS->>CM: create native agent panes
    CM-->>OCS: pane handles

    Note over U,CM: Remote path (cmuxd-remote)
    U->>RD: cmuxd-remote omo-slim [args]
    RD->>CM: getFocusedContext() via RPC
    CM-->>RD: workspaceId, surfaceId
    RD->>RD: openCodeNativeEffectivePort() free port
    RD->>OCS: syscall.Exec(opencode, [--port P, ...args])
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"}}}%%
sequenceDiagram
    participant U as User
    participant CLI as cmux CLI (Swift)
    participant RD as cmuxd-remote (Go)
    participant OCS as OpenCode + OMO Slim 2.2+
    participant CM as cmux daemon

    U->>CLI: cmux omo-slim [args]
    CLI->>CLI: resolveOpenCodeExecutable()
    CLI->>CM: tmuxCompatFocusedContext() if WORKSPACE/SURFACE absent
    CM-->>CLI: workspaceId, surfaceId
    CLI->>CLI: omoResolvedPort() pick free port
    CLI->>CLI: exportAgentLaunchCommandEnvironment()
    CLI->>OCS: execv(opencode, [--port P, ...args])
    OCS->>CM: connect via CMUX_SOCKET_PATH
    OCS->>CM: create native agent panes
    CM-->>OCS: pane handles

    Note over U,CM: Remote path (cmuxd-remote)
    U->>RD: cmuxd-remote omo-slim [args]
    RD->>CM: getFocusedContext() via RPC
    CM-->>RD: workspaceId, surfaceId
    RD->>RD: openCodeNativeEffectivePort() free port
    RD->>OCS: syscall.Exec(opencode, [--port P, ...args])
Loading

Reviews (2): Last reviewed commit: "Satisfy OMO Slim launcher review checks" | Re-trigger Greptile

Comment on lines +55 to +59
public static func launcherIsOpenCodeSessionWrapper(_ launcher: String?) -> Bool {
guard let launcher = launcher?.trimmingCharacters(in: .whitespacesAndNewlines),
!launcher.isEmpty else { return false }
return ["omo", "omo-slim", "omos"].contains(launcher.lowercased())
}

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 Two independent lists for the same session-wrapper subset

launcherIsOpenCodeSessionWrapper hardcodes ["omo", "omo-slim", "omos"] inline, independently of wrapperLaunchersByKind["opencode"] (which already contains exactly this subset plus "omx" and "omc"). When the next session-aware launcher is added, both the dict and the inline literal must be updated by hand — if one is missed, callers in ContentView, AgentForkSupport, and CMUXCLI+SessionsListForkDiagnostics that rely on this function will silently disagree with the trust-table. Deriving the answer from wrapperLaunchersByKind (e.g. by filtering out "omx" and "omc") would give one authoritative source.

Rule Used: Flag correctness-critical detection/identity deriv... (source)

Comment on lines +43 to +51
case "omo", "omo-slim", "omos":
let launcherName = launcher ?? "omo"
let parts = commandParts(executablePath: executablePath, arguments: arguments, fallbackExecutable: "cmux")
var tail = parts.tail
if tail.first == "omo" { tail.removeFirst() }
if tail.first == launcherName { tail.removeFirst() }
guard let preserved = AgentLaunchSanitizer.preservedArguments(kind: "opencode", args: tail) else {
return .resolved(nil)
}
return .resolved([parts.executable, "omo", "--session", sessionId, "--fork"] + preserved)
return .resolved([parts.executable, launcherName, "--session", sessionId, "--fork"] + preserved)

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 The ?? "omo" fallback is unreachable: Swift only enters this case branch when launcher is one of the three non-nil matched strings, so launcher is always non-optional here. The dead fallback is misleading — a future reader may assume nil can arrive here, and if the switch is ever refactored incorrectly a silent "omo" would be used instead of the real launcher name. The same pattern is repeated in AgentResumeArgv.swift and AgentLaunchSanitizer.swift.

Suggested change
case "omo", "omo-slim", "omos":
let launcherName = launcher ?? "omo"
let parts = commandParts(executablePath: executablePath, arguments: arguments, fallbackExecutable: "cmux")
var tail = parts.tail
if tail.first == "omo" { tail.removeFirst() }
if tail.first == launcherName { tail.removeFirst() }
guard let preserved = AgentLaunchSanitizer.preservedArguments(kind: "opencode", args: tail) else {
return .resolved(nil)
}
return .resolved([parts.executable, "omo", "--session", sessionId, "--fork"] + preserved)
return .resolved([parts.executable, launcherName, "--session", sessionId, "--fork"] + preserved)
case "omo", "omo-slim", "omos":
let launcherName = launcher! // non-nil: matched by this case
let parts = commandParts(executablePath: executablePath, arguments: arguments, fallbackExecutable: "cmux")
var tail = parts.tail
if tail.first == launcherName { tail.removeFirst() }
guard let preserved = AgentLaunchSanitizer.preservedArguments(kind: "opencode", args: tail) else {
return .resolved(nil)
}
return .resolved([parts.executable, launcherName, "--session", sessionId, "--fork"] + preserved)

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!

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchSanitizer.swift (1)

51-53: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Fix the invalid nil-coalescing in AgentLaunchSanitizer
launcher is declared as a non-optional String, so launcher ?? "omo" does not compile. Use let launcherName = launcher here, or make the parameter optional if that fallback is actually needed.

🤖 Prompt for 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.

In
`@Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchSanitizer.swift`
around lines 51 - 53, Update the launcher-name initialization in
AgentLaunchSanitizer to stop applying nil-coalescing to the non-optional
launcher parameter; assign launcher directly to launcherName, unless the
surrounding API requires an optional parameter and fallback behavior.
🤖 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 15425-15443: Add `cli.omoSlim.usage` locale entries in
`Resources/Localizable.xcstrings` for ar, bs, da, de, es, fr, it, km, nb, pl,
pt-BR, ru, th, tr, and zh-Hant, matching the existing `omo-slim`/`omos` usage
text and localization format used by other CLI keys.

In `@Sources/RestorableAgentSession.swift`:
- Around line 440-441: Replace the raw launcher-value switch in the relevant
session-detection logic with the shared launcherIsOpenCodeSessionWrapper(_:)
matcher, preserving the nil suppression behavior for wrapper aliases while
gaining its trimming and case-insensitive handling.

---

Outside diff comments:
In
`@Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchSanitizer.swift`:
- Around line 51-53: Update the launcher-name initialization in
AgentLaunchSanitizer to stop applying nil-coalescing to the non-optional
launcher parameter; assign launcher directly to launcherName, unless the
surrounding API requires an optional parameter and fallback behavior.
🪄 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: 79c4e6a7-40e3-46bf-8443-4eb164225e41

📥 Commits

Reviewing files that changed from the base of the PR and between 496a1c4 and 6a5a700.

📒 Files selected for processing (19)
  • CLI/CMUXCLI+CommandSuggestions.swift
  • CLI/CMUXCLI+SessionsListForkDiagnostics.swift
  • CLI/cmux.swift
  • Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentForkArgv.swift
  • Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchCaptureTrust.swift
  • Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchSanitizer.swift
  • Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentResumeArgv.swift
  • Packages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentForkArgvTests.swift
  • Packages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentLaunchCaptureTrustTests.swift
  • Packages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentResumeArgvTests.swift
  • Resources/Localizable.xcstrings
  • Sources/AgentForkSupport.swift
  • Sources/CmuxTaskManagerCodingAgentDefinition+BuiltIns.swift
  • Sources/ContentView.swift
  • Sources/RestorableAgentSession.swift
  • Sources/TextBoxAgentDetection.swift
  • daemon/remote/cmd/cmuxd-remote/agent_launch.go
  • daemon/remote/cmd/cmuxd-remote/agent_launch_test.go
  • daemon/remote/cmd/cmuxd-remote/cli.go

Comment thread CLI/cmux.swift
Comment thread Sources/RestorableAgentSession.swift Outdated
@cursor

cursor Bot commented Jul 16, 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.

@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
`@Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchCaptureTrust.swift`:
- Around line 61-65: Normalize the launcher once by trimming whitespace/newlines
and lowercasing it, then reuse that canonical token across
AgentLaunchCaptureTrust.launcherDescribesKind(_:kind:),
AgentLaunchSanitizer.sanitizedLaunchArguments(_:launcher:fallbackKind:),
AgentForkArgv.launcherResolution(...), and
AgentResumeArgv.launcherResolution(...). Apply the corresponding changes in
AgentLaunchSanitizer.swift lines 71-77, AgentForkArgv.swift lines 43-51, and
AgentResumeArgv.swift lines 283-291; the trust check in
AgentLaunchCaptureTrust.swift lines 61-65 already performs normalization and
should remain consistent.
🪄 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: 9f2b1d1e-f70e-47a6-9e02-af5c2f8f74a6

📥 Commits

Reviewing files that changed from the base of the PR and between 6a5a700 and 50b66ef.

📒 Files selected for processing (8)
  • Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentForkArgv.swift
  • Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchCaptureTrust.swift
  • Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchSanitizer.swift
  • Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentResumeArgv.swift
  • Packages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentLaunchCaptureTrustTests.swift
  • Packages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentLaunchSanitizerTests.swift
  • Resources/Localizable.xcstrings
  • Sources/RestorableAgentSession.swift

guanbear and others added 4 commits August 7, 2026 17:25
Add regression coverage for both public launcher spellings before wiring the native Slim path.\n\nConstraint: SwiftPM manifest linking is broken in the installed CommandLineTools, so local execution cannot reach the expected compile failure.\nConfidence: high\nScope-risk: narrow\nTested: swift test attempted; blocked by PackageDescription linker failure\nNot-tested: Test assertions cannot execute until the local Swift toolchain is repaired
OMO Slim 2.2.x now manages cmux panes directly, so expose lightweight omo-slim and omos launchers that provide cmux context without synthesizing tmux state or shadowing the user's OpenCode configuration.

Constraint: OMO Slim 2.2+ owns child-pane creation and lifecycle through its native cmux adapter
Rejected: Reuse the existing OMO tmux shim | duplicates Slim's native integration and risks configuration drift
Confidence: high
Scope-risk: moderate
Tested: Go remote launcher tests, Swift syntax parsing, localization JSON validation, diff whitespace checks
Not-tested: Full Swift package and tagged app build unavailable because the installed Command Line Tools SDK does not match its compiler and full Xcode is absent
Complete the new CLI usage key across the catalog and keep session-wrapper handling consistent with the launcher trust contract, so the native OMO Slim path compiles cleanly and does not probe wrapper sessions as plain OpenCode processes.

Constraint: The catalog requires every new user-facing key to cover all supported locales
Rejected: Treat OMO Slim wrapper aliases as a separate raw switch | loses the shared matcher normalization and duplicates alias ownership
Confidence: high
Scope-risk: narrow
Tested: Localization coverage equality check, Swift syntax parsing, Go remote launcher tests, diff whitespace checks
Not-tested: SwiftPM tests cannot start because the local CommandLineTools PackageDescription linker is incompatible
- Rebase native OMO Slim launchers onto current main
- Use agentLaunchContextForInvocation instead of removed getFocusedContext
- Keep nativeProcessAliasesByKind aligned with openCodeSessionWrapperLaunchers
@guanbear

guanbear commented Aug 7, 2026

Copy link
Copy Markdown
Author

Refresh: rebased onto current main + launch-context fix

Head: bf20befa8f316f9b4e50ab926be6933f5d644edd

Why this still matters

Current main still only has the legacy cmux omo tmux-shim / shadow-config path. It does not include omo-slim / omos native launchers.

What this refresh does

  1. Rebased the three OMO Slim commits cleanly onto latest origin/main (was ~2300 commits behind).
  2. Fixed compile break after main renamed focus lookup: runOMOSlimRelay now uses agentLaunchContextForInvocation (same contract as other agent relays), without installing a tmux shim or shadow config.
  3. Review polish: nativeProcessAliasesByKind["opencode"] reuses openCodeSessionWrapperLaunchers so omo / omo-slim / omos stay a single source of truth.

Validation

cd daemon/remote && go test ./cmd/cmuxd-remote -count=1 -run 'OMO|Port|Native'
# PASS (including TestOpenCodeNativeLaunchArgs)

Swift package / full Xcode app build still needs a machine with Xcode if maintainers require it; CLI sources and AgentLaunch unit sources remain in the diff with prior coverage for fork/resume/trust.

Non-goals unchanged

No tmux emulation for OMO Slim; no plugin install; OMO Slim 2.2+ owns pane lifecycle.

@guanbear
guanbear force-pushed the codex/omo-slim-native branch from 50b66ef to bf20bef Compare August 7, 2026 09:28
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@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 using default effort and found 1 potential issue.

Fix All in Cursor

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

Want higher recall? High effort reviews run extra passes and find more bugs. A team admin can switch effort levels in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit bf20bef. Configure here.

Comment thread CLI/cmux.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: 6

🤖 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 23123-23134: Update the focused-context initialization around
tmuxCompatFocusedContext so each environment variable is filled only when its
corresponding launcherEnvironment value is missing. Preserve existing
CMUX_WORKSPACE_ID and CMUX_SURFACE_ID values, and likewise gate each matching
setenv call independently while still applying focusedContext values for missing
entries.
- Around line 23145-23148: Update the effective argument construction around
omoRequestedPort so the default --port option is placed after the opencode run
subcommand, producing opencode run --port <n> before the remaining commandArgs;
preserve existing behavior when a port was explicitly requested.

In `@daemon/remote/cmd/cmuxd-remote/agent_launch.go`:
- Around line 171-178: Clear CMUX_WORKSPACE_ID and CMUX_SURFACE_ID before the
launchContext check in the environment setup block. Then apply non-empty values
from launchContext as currently done, ensuring nil or empty context cannot
inherit stale identity values.
- Around line 216-221: Update openCodeNativeEffectivePort so it does not close
and release the selected listener before OpenCode binds the port. Replace the
current ephemeral-port probe with an OpenCode-supported discovery handshake or
pass the live listener reservation to the process that performs the OpenCode
bind, preserving correct port reporting for concurrent launches. Add regression
coverage that exercises concurrent launches and verifies they do not select the
same released port.
- Around line 187-189: Update the syscall.Exec error handling in the agent
launch flow to replace the raw err formatting in the user-facing fmt.Fprintf
message with a stable, action-oriented failure message. Preserve the command
context, and route the raw error only through the project’s existing redacted
internal diagnostics mechanism.

In `@Sources/AgentForkSupport.swift`:
- Around line 137-139: Replace the literal "omo" launcher comparisons in
requiresForkValidationExecutableIdentity and
forkValidationExecutableResolutionPlan with
AgentLaunchCaptureTrust.launcherIsOpenCodeSessionWrapper, matching supportsFork
so all wrapper aliases use the same fork-validation behavior.
🪄 Autofix

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: 0e32feaf-4e8b-4fbf-af45-2922dbdf583a

📥 Commits

Reviewing files that changed from the base of the PR and between 3faf795 and bf20bef.

📒 Files selected for processing (20)
  • CLI/CMUXCLI+CommandSuggestions.swift
  • CLI/CMUXCLI+SessionsListForkDiagnostics.swift
  • CLI/cmux.swift
  • Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentForkArgv.swift
  • Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchCaptureTrust.swift
  • Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchSanitizer.swift
  • Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentResumeArgv.swift
  • Packages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentForkArgvTests.swift
  • Packages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentLaunchCaptureTrustTests.swift
  • Packages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentLaunchSanitizerTests.swift
  • Packages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentResumeArgvTests.swift
  • Resources/Localizable.xcstrings
  • Sources/AgentForkSupport.swift
  • Sources/CmuxTaskManagerCodingAgentDefinition+BuiltIns.swift
  • Sources/ContentView.swift
  • Sources/RestorableAgentSession.swift
  • Sources/TextBoxAgentDetection.swift
  • daemon/remote/cmd/cmuxd-remote/agent_launch.go
  • daemon/remote/cmd/cmuxd-remote/agent_launch_test.go
  • daemon/remote/cmd/cmuxd-remote/cli.go

Comment thread CLI/cmux.swift Outdated
Comment on lines +23123 to +23134
if launcherEnvironment["CMUX_WORKSPACE_ID"] == nil || launcherEnvironment["CMUX_SURFACE_ID"] == nil,
let focusedContext = try tmuxCompatFocusedContext(
processEnvironment: launcherEnvironment,
explicitPassword: explicitPassword
) {
launcherEnvironment["CMUX_WORKSPACE_ID"] = focusedContext.workspaceId
setenv("CMUX_WORKSPACE_ID", focusedContext.workspaceId, 1)
if let surfaceId = focusedContext.surfaceId {
launcherEnvironment["CMUX_SURFACE_ID"] = surfaceId
setenv("CMUX_SURFACE_ID", surfaceId, 1)
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Fix the combined-OR guard that lets a valid CMUX_WORKSPACE_ID get overwritten.

The condition at line 23123 uses OR: launcherEnvironment["CMUX_WORKSPACE_ID"] == nil || launcherEnvironment["CMUX_SURFACE_ID"] == nil. If CMUX_SURFACE_ID is missing but CMUX_WORKSPACE_ID is already set to the correct terminal's workspace, this condition still evaluates true. When tmuxCompatFocusedContext then resolves, line 23128 unconditionally overwrites launcherEnvironment["CMUX_WORKSPACE_ID"] with focusedContext.workspaceId, regardless of whether the existing value was already correct. focusedContext represents whatever window/surface is currently focused in the app, which is not guaranteed to match the pane that invoked cmux omo-slim. This can route the OMO Slim launch to the wrong workspace.

Gate each assignment on its own missing-ness instead of the combined condition.

🐛 Proposed fix to scope each overwrite to its own missing value
-        if launcherEnvironment["CMUX_WORKSPACE_ID"] == nil || launcherEnvironment["CMUX_SURFACE_ID"] == nil,
-           let focusedContext = try tmuxCompatFocusedContext(
-               processEnvironment: launcherEnvironment,
-               explicitPassword: explicitPassword
-           ) {
-            launcherEnvironment["CMUX_WORKSPACE_ID"] = focusedContext.workspaceId
-            setenv("CMUX_WORKSPACE_ID", focusedContext.workspaceId, 1)
-            if let surfaceId = focusedContext.surfaceId {
-                launcherEnvironment["CMUX_SURFACE_ID"] = surfaceId
-                setenv("CMUX_SURFACE_ID", surfaceId, 1)
-            }
-        }
+        let missingWorkspaceId = launcherEnvironment["CMUX_WORKSPACE_ID"] == nil
+        let missingSurfaceId = launcherEnvironment["CMUX_SURFACE_ID"] == nil
+        if missingWorkspaceId || missingSurfaceId,
+           let focusedContext = try tmuxCompatFocusedContext(
+               processEnvironment: launcherEnvironment,
+               explicitPassword: explicitPassword
+           ) {
+            if missingWorkspaceId {
+                launcherEnvironment["CMUX_WORKSPACE_ID"] = focusedContext.workspaceId
+                setenv("CMUX_WORKSPACE_ID", focusedContext.workspaceId, 1)
+            }
+            if missingSurfaceId, let surfaceId = focusedContext.surfaceId {
+                launcherEnvironment["CMUX_SURFACE_ID"] = surfaceId
+                setenv("CMUX_SURFACE_ID", surfaceId, 1)
+            }
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if launcherEnvironment["CMUX_WORKSPACE_ID"] == nil || launcherEnvironment["CMUX_SURFACE_ID"] == nil,
let focusedContext = try tmuxCompatFocusedContext(
processEnvironment: launcherEnvironment,
explicitPassword: explicitPassword
) {
launcherEnvironment["CMUX_WORKSPACE_ID"] = focusedContext.workspaceId
setenv("CMUX_WORKSPACE_ID", focusedContext.workspaceId, 1)
if let surfaceId = focusedContext.surfaceId {
launcherEnvironment["CMUX_SURFACE_ID"] = surfaceId
setenv("CMUX_SURFACE_ID", surfaceId, 1)
}
}
let missingWorkspaceId = launcherEnvironment["CMUX_WORKSPACE_ID"] == nil
let missingSurfaceId = launcherEnvironment["CMUX_SURFACE_ID"] == nil
if missingWorkspaceId || missingSurfaceId,
let focusedContext = try tmuxCompatFocusedContext(
processEnvironment: launcherEnvironment,
explicitPassword: explicitPassword
) {
if missingWorkspaceId {
launcherEnvironment["CMUX_WORKSPACE_ID"] = focusedContext.workspaceId
setenv("CMUX_WORKSPACE_ID", focusedContext.workspaceId, 1)
}
if missingSurfaceId, let surfaceId = focusedContext.surfaceId {
launcherEnvironment["CMUX_SURFACE_ID"] = surfaceId
setenv("CMUX_SURFACE_ID", surfaceId, 1)
}
}
🤖 Prompt for 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.

In `@CLI/cmux.swift` around lines 23123 - 23134, Update the focused-context
initialization around tmuxCompatFocusedContext so each environment variable is
filled only when its corresponding launcherEnvironment value is missing.
Preserve existing CMUX_WORKSPACE_ID and CMUX_SURFACE_ID values, and likewise
gate each matching setenv call independently while still applying focusedContext
values for missing entries.

Comment thread CLI/cmux.swift
Comment on lines +23145 to +23148
var effectiveArgs = commandArgs
if omoRequestedPort(from: commandArgs) == nil {
effectiveArgs.insert(contentsOf: ["--port", openCodePort], at: 0)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

opencode CLI global flags before or after subcommand

💡 Result:

For the OpenCode CLI, global flags must be placed before any subcommand [1]. When using the OpenCode CLI, you should provide global flags (such as --debug, --cwd, --version, or --help) directly after the root command, preceding any specific command or subcommand [1][2]. For example: opencode --debug [subcommand] [arguments] opencode -c /path/to/project [subcommand] [arguments] The CLI follows standard command-line conventions where global flags are parsed at the root level [1][2]. Placing them after a subcommand may result in the CLI incorrectly identifying the flags as arguments belonging to that specific subcommand, or the flags may simply be ignored [1][3]. Always prioritize placing them before the subcommand to ensure they are correctly interpreted as global configuration settings [1][2].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate and inspect the referenced code and the matching runOMO logic.
wc -l CLI/cmux.swift
sed -n '23120,23170p' CLI/cmux.swift
printf '\n--- runOMO occurrences ---\n'
rg -n "func runOMO|omoRequestedPort|int \\(\"--port\"|append contentsOf: \\(\"--port\"" CLI/cmux.swift
printf '\n--- relevant omo request/port handling ---\n'
sed -n '22700,23100p' CLI/cmux.swift

Repository: manaflow-ai/cmux

Length of output: 1918


🌐 Web query:

site:github.com OpenCode OpenCode CLI global flags before subcommand --port

💡 Result:

In the OpenCode CLI, the --port flag is not a global flag; it is a command-specific option [1][2][3]. Because it is specific to commands such as run or serve, it must be placed after the subcommand, not before it [4][5]. Global flags in the OpenCode CLI are limited to options that apply to every command, such as --help, --version, --print-logs, --log-level, and --pure [1][6][4]. Since --port is associated with the configuration of the underlying server or local listener for specific operations, it is defined within the builder for those subcommands (e.g., in the run or serve command definitions) rather than at the root level [7][5][8]. Therefore, you should use the structure: opencode --port For example: opencode run --port 4096 opencode serve --port 4096

Citations:


Move --port into the opencode subcommand.

opencode defines --port as a command-level option, so this becomes cmux omo-slim run "prompt" → opencode --port <n> run "prompt" and --port can be parsed as an unexpected argument instead of a run command option. Build the call as opencode run --port <n> "prompt" before inserting the rest of commandArgs.

🤖 Prompt for 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.

In `@CLI/cmux.swift` around lines 23145 - 23148, Update the effective argument
construction around omoRequestedPort so the default --port option is placed
after the opencode run subcommand, producing opencode run --port <n> before the
remaining commandArgs; preserve existing behavior when a port was explicitly
requested.

Comment thread daemon/remote/cmd/cmuxd-remote/agent_launch.go
Comment thread daemon/remote/cmd/cmuxd-remote/agent_launch.go
Comment on lines +216 to +221
listener, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
return "4097"
}
defer listener.Close()
return strconv.Itoa(listener.Addr().(*net.TCPAddr).Port)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Do not release the selected port before OpenCode binds it.

openCodeNativeEffectivePort closes the listener when it returns. Another process can bind that port before syscall.Exec starts OpenCode. Concurrent launches can then fail intermittently.

Use an OpenCode-supported port discovery handshake, or make the process that binds OpenCode own the reservation. Add concurrent-launch regression coverage.

🧰 Tools
🪛 golangci-lint (2.12.2)

[error] 220-220: Error return value of listener.Close is not checked

(errcheck)


[error] 221-221: type assertion must be checked

(forcetypeassert)


[error] 216-216: net.Listen must not be called. use (*net.ListenConfig).Listen

(noctx)

🤖 Prompt for 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.

In `@daemon/remote/cmd/cmuxd-remote/agent_launch.go` around lines 216 - 221,
Update openCodeNativeEffectivePort so it does not close and release the selected
listener before OpenCode binds the port. Replace the current ephemeral-port
probe with an OpenCode-supported discovery handshake or pass the live listener
reservation to the process that performs the OpenCode bind, preserving correct
port reporting for concurrent launches. Add regression coverage that exercises
concurrent launches and verifies they do not select the same released port.

Comment thread Sources/AgentForkSupport.swift
runOMOSlim still called tmuxCompatFocusedContext after the inherited-identity
redesign removed it. Native OMO Slim now relies only on the caller's
CMUX_WORKSPACE_ID / CMUX_SURFACE_ID, matching tmuxCompatLaunchContext fail-closed
behavior.

Also:
- treat omo-slim/omos like omo in fork validation executable probes
- clear ambient CMUX identity before applying remote launch context
- avoid printing raw syscall.Exec errors from the remote launcher
@guanbear

guanbear commented Aug 7, 2026

Copy link
Copy Markdown
Author

Review follow-up

Head refreshes with:

  1. High: removed deleted tmuxCompatFocusedContext call in local runOMOSlim. After the inherited-identity redesign that API is gone, and borrowing system-wide focus is intentionally fail-closed. Native OMO Slim now only passes through the caller's CMUX_WORKSPACE_ID / CMUX_SURFACE_ID (same contract as tmuxCompatLaunchContext).
  2. Fork validation now skips OpenCode version probes for all session wrappers (omo, omo-slim, omos) via launcherIsOpenCodeSessionWrapper, matching supportsFork.
  3. Remote relay unsets ambient CMUX workspace/surface before applying resolved launch context, and prints a stable launch-failure message instead of the raw syscall.Exec error.

Not changed in this push:

  • OpenCode free-port TOCTOU between bind discovery and exec (existing shared port-selection pattern; needs a broader handshake change)
  • full Xcode package test suite (not available on this machine)

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
CLI/cmux.swift (1)

23096-23158: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Fail closed before launching omo-slim without an inherited cmux surface.

runOMOSlim only reads CMUX_WORKSPACE_ID/CMUX_SURFACE_ID from ProcessInfo.processInfo.environment, so it can execv opencode outside a cmux terminal. Call tmuxCompatLaunchContext and throw managedTerminalRequiredMessage(displayName: "cmux \(launcher)") when normalizedTmuxTarget(launchContext?.surfaceId) is absent, mirroring runOMO, runOMX, and runOMC.

🤖 Prompt for 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.

In `@CLI/cmux.swift` around lines 23096 - 23158, Update runOMOSlim to obtain the
inherited context via tmuxCompatLaunchContext and validate
normalizedTmuxTarget(launchContext?.surfaceId) before resolving or launching
OpenCode. If no inherited surface is available, throw
managedTerminalRequiredMessage(displayName: "cmux \(launcher)"), matching the
fail-closed behavior in runOMO, runOMX, and runOMC.

Source: Path instructions

♻️ Duplicate comments (3)
CLI/cmux.swift (1)

23127-23139: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Fix the --port placement so it does not break opencode subcommand invocations.

effectiveArgs.insert(contentsOf: ["--port", openCodePort], at: 0) always inserts --port <n> at index 0, before any positional subcommand. For cmux omo-slim run "prompt", this produces commandArgs = ["run", "prompt"] and effectiveArgs = ["--port", "<port>", "run", "prompt"], which execs as opencode --port <port> run "prompt".

A previous review on this same function already flagged this exact pattern and verified through web search that opencode's --port flag is a per-subcommand option (for example run or serve), not a global flag, so it must come after the subcommand: opencode run --port <n> "prompt". Placing --port before the subcommand risks opencode treating it as an unexpected positional argument. That past comment has no "Addressed" marker, and the code still exhibits the same behavior.

🐛 Proposed fix to place `--port` after any leading subcommand
     var effectiveArgs = commandArgs
     if omoRequestedPort(from: commandArgs) == nil {
-        effectiveArgs.insert(contentsOf: ["--port", openCodePort], at: 0)
+        let insertionIndex = effectiveArgs.first?.hasPrefix("-") == false ? 1 : 0
+        effectiveArgs.insert(contentsOf: ["--port", openCodePort], at: insertionIndex)
     }

Since this depends on opencode's actual CLI flag parsing rules, please confirm the exact accepted syntax for the installed opencode version before merging the fix.

opencode CLI --port flag global or subcommand
🤖 Prompt for 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.

In `@CLI/cmux.swift` around lines 23127 - 23139, Update the effectiveArgs
construction in the omo launcher flow so the generated --port value is inserted
after the leading opencode subcommand rather than always at index 0. Preserve
existing arguments and support invocations such as run or serve, while
confirming the installed opencode version’s accepted option syntax before
finalizing the change.
daemon/remote/cmd/cmuxd-remote/agent_launch.go (2)

206-226: ⚠️ Potential issue | 🟠 Major

Keep the selected port reserved until OpenCode binds it.

The effective-port helper releases the ephemeral listener before syscall.Exec starts OpenCode. Another process can claim the port during this gap, so concurrent launches can fail intermittently. Use an OpenCode-supported discovery handshake or preserve the reservation through the bind. Add concurrent-launch regression coverage.

The previous review already identified this unresolved port-reservation race, and the supplied change details show that it remains unchanged.

🤖 Prompt for 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.

In `@daemon/remote/cmd/cmuxd-remote/agent_launch.go` around lines 206 - 226,
Update openCodeNativeEffectivePort so an automatically selected ephemeral port
remains reserved until OpenCode successfully binds it, using an
OpenCode-supported discovery handshake or equivalent reservation-preserving flow
instead of closing the listener before syscall.Exec. Keep explicit --port and
OPENCODE_PORT behavior unchanged, and add regression coverage that exercises
concurrent launches.

173-176: ⚠️ Potential issue | 🟠 Major

Fail closed when clearing inherited identity fails.

Lines 175-176 ignore the errors from os.Unsetenv. If either call fails, stale CMUX_WORKSPACE_ID or CMUX_SURFACE_ID can reach the exec'd process. Check both results and abort before syscall.Exec on failure. Keep the user-facing message stable.

As per coding guidelines, correctness-critical launch identity must fail closed instead of continuing with ambient state.

🤖 Prompt for 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.

In `@daemon/remote/cmd/cmuxd-remote/agent_launch.go` around lines 173 - 176,
Update the environment-clearing logic in the launch flow around os.Unsetenv so
both CMUX_WORKSPACE_ID and CMUX_SURFACE_ID errors are checked. If either unset
operation fails, abort before syscall.Exec using the existing stable user-facing
error message, ensuring stale inherited identity cannot reach the exec'd
process.

Sources: Coding guidelines, Linters/SAST tools

🤖 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.

Outside diff comments:
In `@CLI/cmux.swift`:
- Around line 23096-23158: Update runOMOSlim to obtain the inherited context via
tmuxCompatLaunchContext and validate
normalizedTmuxTarget(launchContext?.surfaceId) before resolving or launching
OpenCode. If no inherited surface is available, throw
managedTerminalRequiredMessage(displayName: "cmux \(launcher)"), matching the
fail-closed behavior in runOMO, runOMX, and runOMC.

---

Duplicate comments:
In `@CLI/cmux.swift`:
- Around line 23127-23139: Update the effectiveArgs construction in the omo
launcher flow so the generated --port value is inserted after the leading
opencode subcommand rather than always at index 0. Preserve existing arguments
and support invocations such as run or serve, while confirming the installed
opencode version’s accepted option syntax before finalizing the change.

In `@daemon/remote/cmd/cmuxd-remote/agent_launch.go`:
- Around line 206-226: Update openCodeNativeEffectivePort so an automatically
selected ephemeral port remains reserved until OpenCode successfully binds it,
using an OpenCode-supported discovery handshake or equivalent
reservation-preserving flow instead of closing the listener before syscall.Exec.
Keep explicit --port and OPENCODE_PORT behavior unchanged, and add regression
coverage that exercises concurrent launches.
- Around line 173-176: Update the environment-clearing logic in the launch flow
around os.Unsetenv so both CMUX_WORKSPACE_ID and CMUX_SURFACE_ID errors are
checked. If either unset operation fails, abort before syscall.Exec using the
existing stable user-facing error message, ensuring stale inherited identity
cannot reach the exec'd process.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: c6a12d06-78e2-488d-93be-5cd862de755b

📥 Commits

Reviewing files that changed from the base of the PR and between bf20bef and 45aba72.

📒 Files selected for processing (3)
  • CLI/cmux.swift
  • Sources/AgentForkSupport.swift
  • daemon/remote/cmd/cmuxd-remote/agent_launch.go

@guanbear

Copy link
Copy Markdown
Author

Closing this PR for now.

There has not been maintainer merge traction, so I’m withdrawing it to reduce noise rather than keep the branch open indefinitely.

Thanks for the automated review feedback. Happy to revisit with a fresher PR if native OMO Slim launchers are still wanted.

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