Skip to content

Fix omo model override - #3939

Closed
austinywang wants to merge 24 commits into
mainfrom
issue-3682-omo-change-model
Closed

austinywang wants to merge 24 commits into
mainfrom
issue-3682-omo-change-model

Conversation

@austinywang

@austinywang austinywang commented May 12, 2026 •

Copy link
Copy Markdown
Contributor

Closes #3682.

Summary

  • Capture the cmux omo --model regression with a CLI-level test.
  • Apply the requested model to oh-my-opencode agent and category config in the local CLI path.
  • Mirror the model override behavior in the remote relay.

Verification

  • Manual repro used a temporary HOME and fake opencode: /opt/homebrew/bin/cmux omo --model deepinfra/zai-org/GLM-4.7-Flash run hello forwarded the model but produced no oh-my-opencode agent/category model overrides before the fix.
  • Local test suites were not run, per repo/user instruction; CI will verify.

Note

Medium Risk
Touches cmux omo launch and config-shadow generation in both the local Swift CLI and remote relay; incorrect parsing or config writes could break OpenCode launches or persist unintended config overrides.

Overview
Fixes a regression where cmux omo --model was forwarded to opencode but did not override the model inside the generated oh-my-opencode.json shadow config.

Adds --model/-m parsing (including =... forms and honoring --), applies the override across a fixed set of agent and category keys, and rebuilds the shadow config from the user source on every run so overrides don’t persist. Also tightens config IO: clearer read/parse errors without leaking full paths, only passthrough-symlinks oh-my-opencode.jsonc, and writes remote shadow files atomically.

Adds Swift and Go tests covering model override application/reset, -- terminator handling, and invalid user config rejection, and documents the cmux omo contract behavior.

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


Summary by cubic

Fixes a regression where cmux omo --model was forwarded but not applied to oh-my-opencode configs. Overrides now update all agent/category entries and reset each run by rebuilding the shadow config (closes #3682).

  • Bug Fixes
    • Apply the requested model across agents and categories in the shadow config (CLI and cmuxd-remote), rebuilt from the user source on every run so overrides never persist.
    • Parse --model/-m with or without =, and honor -- as a terminator.
    • Validate user oh-my-opencode.json and opencode.json; show path-safe read/parse errors; skip writing any shadow config on failure; pass through only oh-my-opencode.jsonc; write shadow configs atomically.
    • Add tests for overrides, reset, terminator handling, and invalid-config rejection; update docs/cli-contract.md.

Written for commit 52e9c8d. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

  • New Features

    • Added a --model / -m CLI option to override the model for the oh-my-opencode plugin (supports --model value and --model=value forms).
    • Shadow plugin config is rebuilt each run to avoid stale overrides; tmux is ensured, pane-size defaults are applied, and generated config is written atomically.
    • Correct handling of -- so it won’t be treated as a model argument.
  • Tests

    • Added tests for argument forwarding, persisted override behavior, and terminator handling.

Review Change Stack

@vercel

vercel Bot commented May 12, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment May 19, 2026 7:19am
cmux-staging Building Building Preview, Comment May 19, 2026 7:19am

@coderabbitai

coderabbitai Bot commented May 12, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds parsing for --model/-m, writes the requested model into allowlisted oh-my-opencode agent/category entries, forces per-run shadow-config rebuild with tmux defaults, writes configs atomically, updates call sites to pass the parsed model, and adds tests and docs for terminator and clearing behavior.

Changes

Model Override Feature

Layer / File(s) Summary
Model target configuration
CLI/cmux.swift
Defines allowlists of agents and categories keys eligible for model overrides.
Model argument parsing
CLI/cmux.swift
Parses optional requested model from --model/-m forms (spaced and =), honoring -- terminator.
Apply override & plugin ensure refactor
CLI/cmux.swift, daemon/remote/cmd/cmuxd-remote/agent_launch.go
Adds helper to set "model" on allowlisted entries; updates omoEnsurePlugin(requestedModel:) to rebuild shadow oh-my-opencode.json each run, enable tmux, set pane defaults when missing, remove stale symlinks, and write JSON atomically.
CLI contract docs
docs/cli-contract.md
Documents cmux omo forwarding, supported --model/-m syntaxes, -- terminator handling, and per-invocation shadow-config rebuild behavior.
Regression tests
cmuxTests/OpenCodeHookRegressionTests.swift, daemon/remote/cmd/cmuxd-remote/main_test.go
Adds tests verifying argv forwarding, persisted config contains/clears model overrides for expected keys, and that -- terminator is respected.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • manaflow-ai/cmux#2238: Introduced foundational runOMORelay/omoEnsurePlugin shadow-config wiring that this PR extends with model override parsing and application.
  • manaflow-ai/cmux#2280: Overlaps at shadow plugin install/bootstrap paths and touches related omoEnsurePlugin/shadow-config generation logic.

Poem

🐰 I found a flag beneath the log and nudged it with a paw,
The model hopped into agents where the whitelist saw.
No stale symlinks clutter the dale, each run writes clean and bright,
Swift parses, Go applies, the rabbit polishes the night. ✨


Caution

Pre-merge checks failed

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

  • Ignore

❌ Failed checks (3 errors, 1 warning)

Check name Status Explanation Resolution
Cmux Swift File And Package Boundaries ❌ Error oh-my-opencode.json parsing silently defaults to empty config on JSON error, unlike opencode.json which throws CLIError. Makes config mistakes hard to diagnose. Separate read from parse: throw CLIError on invalid JSON instead of silently defaulting to empty config, matching opencode.json pattern.
Cmux User-Facing Error Privacy ❌ Error Error message "Failed to parse \(userJsonURL.path). Fix the JSON syntax and retry." exposes internal file paths to users, violating privacy rules for implementation details. Replace file path with generic reference like "oh-my-opencode.json" in user-facing error. Move detailed path info to logs/telemetry only."
Cmux Architecture Rethink ❌ Error Invalid JSON in oh-my-opencode.json silently defaults to empty config, unlike opencode.json which throws. Makes errors hard to diagnose. Add guard statement at line 15100-15108 to throw on parse errors, matching opencode.json pattern and fixing review comment.
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (12 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 New Swift functions use safe value types and caller-owned parameters. No MainActor, Sendable, or actor isolation annotations added. Test additions are allowed. No actor isolation violations detected.
Cmux Swift Blocking Runtime ✅ Passed No blocking runtime patterns in production Swift code. New functions perform pure parsing and data transformation. Test-only DispatchSemaphore in test helper allowed for subprocess completion.
Cmux No Hacky Sleeps ✅ Passed Check does not apply to this PR. The rule covers TypeScript, JavaScript, shell, and non-Swift runtime scripts. The PR only modifies Swift code and Go code. Go is not in the specified scope.
Cmux Swift Concurrency ✅ Passed No legacy async patterns introduced. All new Swift code is synchronous (string parsing, JSON config manipulation, file I/O). New test function is XCTest-based, which is explicitly allowed.
Cmux Swift @Concurrent ✅ Passed All Swift functions added are synchronous (no async/await). They perform blocking I/O typical of CLI tools. No @concurrent or @MainActor attributes were added.
Cmux Swift Logging ✅ Passed No logging rule violations found. New omo code uses no prohibited logging (print/debugPrint/dump/NSLog). FileHandle.standardError for plugin install messages is acceptable.
Cmux Swiftui State Layout ✅ Passed PR contains no SwiftUI state changes. Modifications are CLI argument parsing, config handling, Go backend, and docs. No @Published, @Observable, @StateObject, GeometryReader, or render-time mutations.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR contains no NSWindow, NSPanel, NSWindowController, or SwiftUI Window/WindowGroup code. Changes limited to CLI argument parsing, config file handling, and test utilities.
Title check ✅ Passed The title accurately summarizes the main change—fixing the omo model override regression—but lacks specificity about how (parsing and applying model overrides).
Description check ✅ Passed Pull request description addresses all required sections with complete detail: summary explains what changed and why, verification describes manual testing performed, and checklist items are mostly checked.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-3682-omo-change-model

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

❤️ Share

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

@greptile-apps

greptile-apps Bot commented May 12, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes the cmux omo --model regression (closes #3682) where the requested model was forwarded to opencode but never written into the generated oh-my-opencode shadow config, so agent and category entries always used their defaults.

  • Model parsing: adds --model/-m in both space-separated and =value forms, with correct -- terminator handling in both the Swift CLI and the Go relay.
  • Override application: applies the model to all 14 agent keys and 8 category keys; rebuilds the shadow config from the user's source on every run so a previous --model override cannot silently persist.
  • Hardening: user oh-my-opencode.json and opencode.json are validated before any shadow write; errors use only the filename (no full path); Go shadow files are now written atomically via a temp-file + os.Rename pattern; the JSONC passthrough is kept separate from the generated JSON shadow.

Confidence Score: 5/5

Safe to merge — the three previously flagged issues (stale override, non-atomic Go writes, incomplete agent key coverage in tests) are all addressed and verified by new tests.

Both the Swift CLI and Go relay now rebuild the shadow oh-my-opencode config from the user source on every invocation. Argument parsing handles all flag forms and the -- terminator consistently in both implementations. Shadow writes use atomic temp-file rename. User config validation fails fast before writing anything. Regression tests cover all 14 agent keys, 8 category keys, the reset path, the -- terminator, and invalid-config rejection including path-leakage checks.

No files require special attention. The agent/category key lists are intentionally duplicated across Swift and Go with a keep-in-sync comment; that coupling is a maintenance concern but not a correctness issue in this PR.

Important Files Changed

Filename Overview
CLI/cmux.swift Adds --model/-m parsing (including = forms and -- terminator), rebuilds oh-my-opencode shadow config from user source on every run, uses atomic write, and validates user configs with path-safe error messages.
cmuxTests/OpenCodeHookRegressionTests.swift Adds full-coverage regression tests: all 14 agent keys and 8 category keys verified for override and reset, -- terminator handling, and invalid-config rejection without leaking paths.
daemon/remote/cmd/cmuxd-remote/agent_launch.go Mirrors CLI fix in the remote relay: adds omoRequestedModel, omoApplyModelOverride, rebuilds shadow config every run, replaces direct os.WriteFile calls with writeFileAtomic (temp-file + os.Rename), validates user configs.
daemon/remote/cmd/cmuxd-remote/main_test.go Adds Go-level unit tests for the -- terminator, -m= short form, and invalid user oh-my-opencode.json rejection; confirms no shadow write on parse failure and no path leakage in errors.
docs/cli-contract.md Documents the cmux omo contract: --model/-m forms, -- terminator, per-invocation rebuild semantics.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["cmux omo [args...]"] --> B["omoRequestedModel(args)"]
    B --> C{--model / -m found before --?}
    C -- "yes" --> D["requestedModel = value"]
    C -- "no" --> E["requestedModel = nil / empty"]
    D --> F["omoEnsurePlugin(requestedModel)"]
    E --> F
    F --> G["Read user opencode.json\nfail-fast on read/parse error"]
    G --> H["Write shadow opencode.json atomically"]
    H --> I["Symlink oh-my-opencode.jsonc if user has one"]
    I --> J["Read user oh-my-opencode.json\nfail-fast on read/parse error"]
    J --> K{requestedModel non-empty?}
    K -- "yes" --> L["omoApplyModelOverride\nagents x14, categories x8"]
    K -- "no" --> M["Use user config as-is"]
    L --> N["Write shadow oh-my-opencode.json atomically"]
    M --> N
    N --> O["setenv OPENCODE_CONFIG_DIR=shadowDir"]
    O --> P["exec opencode with original args"]
Loading

Reviews (17): Last reviewed commit: "Merge remote-tracking branch 'origin/mai..." | Re-trigger Greptile

Comment thread cmuxTests/OpenCodeHookRegressionTests.swift Outdated
Comment thread daemon/remote/cmd/cmuxd-remote/agent_launch.go
Comment thread daemon/remote/cmd/cmuxd-remote/agent_launch.go Outdated
coderabbitai[bot]
coderabbitai Bot previously requested changes May 12, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

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

Inline comments:
In `@CLI/cmux.swift`:
- Around line 12648-12656: The parser for the "--model"/"-m" branch currently
accepts "--" as a model; update the block in CLI/cmux.swift (the branch handling
arg == "--model" || arg == "-m" that uses commandArgs, index, and
requestedModel) to treat a next token equal to "--" as the terminator: if the
next token is "--" do not assign requestedModel and do not consume it as the
model value (i.e., return or continue respecting the top-level "--" stop
behavior), otherwise trim and assign as before; ensure index advancement only
happens when a real model value was consumed.

In `@daemon/remote/cmd/cmuxd-remote/agent_launch.go`:
- Around line 563-568: The branch handling the "-m=value" argument sets
requestedModel but lacks a trailing continue like the "--model=value" case; add
a continue after assigning requestedModel in the strings.HasPrefix(arg, "-m=")
block so the loop immediately proceeds to the next arg (matching the pattern
used around the earlier "--model=" branch) and avoids falling through to
subsequent argument handling for the same arg.
🪄 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: efe0691a-0690-488a-802e-d4180fbbdcb6

📥 Commits

Reviewing files that changed from the base of the PR and between d56a546 and 716c3e8.

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

Comment thread CLI/cmux.swift
Comment thread daemon/remote/cmd/cmuxd-remote/agent_launch.go
@lawrencecchen
lawrencecchen dismissed coderabbitai[bot]’s stale review May 12, 2026 05:56

Dismissed after the two CodeRabbit findings were fixed in bd132ba and the follow-up CodeRabbit review approved the latest head.

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

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

Inline comments:
In `@CLI/cmux.swift`:
- Around line 15100-15104: The current logic treats read/parse failures of the
userOmoConfig file the same as a missing file and silently sets omoConfig = [:];
change this so you first check whether the file exists (e.g.
FileManager.fileExists(atPath: userOmoConfig.path)) and only default to an empty
dictionary when the file does not exist, but if the file exists and
Data(contentsOf:) or JSONSerialization.jsonObject(with:) fails, surface an
explicit CLI error (throw or process exit with a clear message) indicating the
file is unreadable or contains invalid JSON so the user is informed rather than
silently losing their settings; update the block around userOmoConfig/omoConfig
to implement this 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: cce8a5e2-c328-4c78-aeea-4a00e9bc5adb

📥 Commits

Reviewing files that changed from the base of the PR and between 4e90051 and b3a23eb.

📒 Files selected for processing (2)
  • CLI/cmux.swift
  • docs/cli-contract.md

Comment thread CLI/cmux.swift Outdated

@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 5 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="daemon/remote/cmd/cmuxd-remote/main_test.go">

<violation number="1" location="daemon/remote/cmd/cmuxd-remote/main_test.go:126">
P2: The test asserts a shadow OMO config file must exist after invalid user config, which can lock in the wrong behavior instead of verifying that no shadow config is written.</violation>
</file>

<file name="cmuxTests/OpenCodeHookRegressionTests.swift">

<violation number="1" location="cmuxTests/OpenCodeHookRegressionTests.swift:245">
P3: The invalid-config test is too permissive: it allows a newly written shadow config file as long as its contents are "{", so it can miss regressions where shadow config is written despite parse failure.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
Re-trigger cubic

Comment thread daemon/remote/cmd/cmuxd-remote/main_test.go Outdated
Comment thread cmuxTests/OpenCodeHookRegressionTests.swift Outdated
@lawrencecchen
lawrencecchen dismissed coderabbitai[bot]’s stale review May 18, 2026 06:57

Stale after follow-up commits. The requested invalid oh-my-opencode.json handling was addressed in bf38bba and path-free user-facing errors were added in 36deafa; the latest CodeRabbit status check is passing.

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

This branch was successfully deployed

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

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cmux omo: doesn't allow changing model

3 participants