feat(slim): Full oh-my-opencode-slim presets system + bug fixes#194
feat(slim): Full oh-my-opencode-slim presets system + bug fixes#194itsmylife44 merged 5 commits intomainfrom
Conversation
- Add presets-based config generation (modern oh-my-opencode-slim approach)
- Fix external model overrides being silently ignored (now passed through as-is)
- Fix council presets with only master override being dropped
- Add model array support (string | {id, variant}[])
- Add websearch config support ({ provider: 'exa' | 'tavily' })
- Add multiplexer unified config (tmux + zellij)
- Add interview config for browser-based Q&A flow
- Add todoContinuation for auto-continue on incomplete todos
- Add provider-specific options support
- Add retry_on_empty for silent 0-token responses
- Add default skills/MCPs per agent
- Fix misleading type imports
HIGH priority fixes: - Fix manualPlan to exclude council agent (schema compliance) - Fix external model passthrough for fallback chains, manualPlan, master_fallback - Enforce council requires both master AND presets (schema compliance) - Remove unresolved placeholder models - fail fast if no models available MEDIUM priority fixes: - Allow explicit empty arrays to disable default skills/MCPs - Fix truthy checks to use !== undefined for optional strings - Clone default arrays to prevent mutation leaks - Protect against prototype pollution via Object.create(null) LOW priority fixes: - Remove dead code (unreachable agentConfigs.length check) - Validate interview.outputFolder minLength 1 Update tests to reflect new external model passthrough behavior
The /api/agent-config endpoint was doing full replacement of overrides, which clobbered state saved by /api/user/config (e.g., MCP toggle states). Added deepMergeOverrides() helper that: - Recursively merges nested objects - Replaces arrays (not merged) - Preserves fields not being updated Now both endpoints can coexist without overwriting each other's changes.
1. Fix truthy check in processModelConfig (line 76-77) - Changed 'item.variant &&' to 'item.variant !== undefined' - Consistent with all other variant checks in the file 2. Replace deep merge with shallow merge in agent-config API - Deep merge prevented users from removing agent overrides - Shallow merge preserves unrelated top-level keys (mcpServers) - While fully replacing keys being updated (agents)
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit bc6031c. Configure here.
| }, | ||
| update: { | ||
| overrides: JSON.parse(JSON.stringify(validated)), | ||
| overrides: JSON.parse(JSON.stringify(mergedOverrides)), |
There was a problem hiding this comment.
Read-modify-write race can still lose MCP state
Medium Severity
The new read-then-write pattern in the PUT handler introduces a TOCTOU race with /api/user/config, which writes to the same agentModelOverride row. If a user toggles an MCP via /api/user/config between the findUnique read and the upsert write here, the MCP change is silently overwritten by stale existingOverrides. This is the same class of data loss the PR intends to fix — now probabilistic instead of deterministic. A database-level atomic merge (e.g., a transaction with row locking or a JSON merge in SQL) would eliminate the window entirely.
Reviewed by Cursor Bugbot for commit bc6031c. Configure here.
| source: Record<string, unknown> | ||
| ): Record<string, unknown> { | ||
| return { ...target, ...source }; | ||
| } |
There was a problem hiding this comment.
Unnecessary wrapper function over simple spread
Low Severity
shallowMergeOverrides is a named function wrapping { ...target, ...source } — a single-expression spread that is universally understood. It's called exactly once. The call site already has a comment explaining the merge intent, making the function's doc-comment redundant. The extra indirection slightly increases cognitive load without adding any abstraction value; inlining the spread at the call site would be clearer.
Reviewed by Cursor Bugbot for commit bc6031c. Configure here.
🤖 I have created a release *beep* *boop* --- ## [0.1.76](dashboard-v0.1.75...dashboard-v0.1.76) (2026-04-15) ### Features * **slim:** Full oh-my-opencode-slim presets system + bug fixes ([#194](#194)) ([3587ab4](3587ab4)) ### Bug Fixes * add missing oauth-import-normalization module ([c7e56fa](c7e56fa)) * **api:** eliminate race condition with optimistic concurrency ([0a4ee97](0a4ee97)) * force clean checkout and no-cache on self-hosted runner ([f70d672](f70d672)) * refresh buttons now bypass server cache for update checks ([6aa1c53](6aa1c53)) * run tag-contributors for build-existing-tag action ([2cb998c](2cb998c)) * update version.json for build-existing-tag action ([b423665](b423665)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>


Summary
Changes
New Features (oh-my-opencode-slim)
string | {id, variant}[]format{ provider: "exa" | "tavily" }Bug Fixes (Oracle Deep Review)
manualPlannow excludes council agent (schema compliance)!== undefinedfor optional stringsObject.create(null)interview.outputFolderminLength validationBug Fix (Dashboard)
/api/agent-confignow deep merges instead of full replace, preserving MCP states set via/api/user/configTesting
Note
Medium Risk
Medium risk because it rewrites the Slim config generator semantics (model resolution, presets, fallback/manualPlan/council handling) and changes the
/api/agent-configpersistence behavior to merge stored overrides, which could affect generated configs and user settings.Overview
Adds a full presets-capable
oh-my-opencode-slimconfig generator (v0.9.12-aligned), including support for namedpresets, array-style model configs with variants, default per-agentskills/mcps, provideroptions, unifiedmultiplexer(and legacytmuxconversion), plus newinterview,todoContinuation,websearch, andretry_on_emptyfields.Changes model handling to prefix only models found in
availableModels(external IDs pass through) across agent models,manualPlan, fallbackchains, and councilmaster_fallback, and switches to fail-fast (buildSlimConfigreturnsnull) when no models can be resolved without explicit overrides; council emission is tightened to require bothmasterand non-emptypresets.Fixes dashboard override clobbering by making
PUT /api/agent-configfetch and shallow-merge existing stored overrides with incoming updates so unrelated top-level keys (e.g., MCP server config) are preserved; updates/extends unit tests to match the new external-model passthrough and fail-fast behaviors.Reviewed by Cursor Bugbot for commit bc6031c. Bugbot is set up for automated code reviews on this repo. Configure here.