Skip to content

feat: integrate oh-my-opencode as native built-in plugin#2

Merged
sellys-537 merged 3 commits intodevfrom
copilot/integrate-oh-my-opencode
Feb 10, 2026
Merged

feat: integrate oh-my-opencode as native built-in plugin#2
sellys-537 merged 3 commits intodevfrom
copilot/integrate-oh-my-opencode

Conversation

Copy link

Copilot AI commented Feb 10, 2026

What does this PR do?

Integrates oh-my-opencode natively into coli so it ships as a built-in plugin with centralized config in coli.json and a settings UI in the web/desktop app.

Core changes:

  • Built-in plugin — Added oh-my-opencode@3.4.0 to BUILTIN in plugin/index.ts, auto-installed on every coli run
  • Config schema — Added oh_my_opencode section to Config.Info Zod schema with typed fields for agents, categories, tmux, ralph_loop, disabled_hooks/agents/skills/mcps, browser_automation_engine, experimental
  • Config sync — On config load, deep-merges oh_my_opencode settings from coli.json into ~/.config/coli/oh-my-opencode.json so the plugin picks them up
  • SDK types — Extended the generated Config type with oh_my_opencode so the frontend has type safety
  • Settings UI — New "Oh My OpenCode" tab in settings dialog with toggles for tmux, Ralph Loop, auto-update, browser engine, layout
  • i18n — English translation keys for all new settings

Example config in coli.json:

{
  "oh_my_opencode": {
    "agents": {
      "oracle": { "model": "openai/gpt-5.2" },
      "explore": { "model": "opencode/gpt-5-nano" }
    },
    "tmux": { "enabled": true, "layout": "main-vertical" },
    "ralph_loop": { "enabled": true },
    "disabled_hooks": ["comment-checker"]
  }
}

How did you verify your code works?

  • Reviewed config schema integration against oh-my-opencode's OhMyOpenCodeConfigSchema to ensure field parity
  • Verified the config sync logic correctly deep-merges with existing oh-my-opencode.json and handles missing files
  • Confirmed settings UI component follows existing patterns (settings-general.tsx, settings-providers.tsx)
  • CodeQL security scan: 0 alerts

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/repos/code-yeongyu/oh-my-opencode/contents/src
    • Triggering command: /home/REDACTED/work/_temp/ghcca-node/node/bin/node /home/REDACTED/work/_temp/ghcca-node/node/bin/node --enable-source-maps /home/REDACTED/work/_temp/copilot-developer-action-main/dist/index.js (http block)

If you need me to access, download, or install something from one of these locations, you can either:


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 2 commits February 10, 2026 07:55
…tings UI

Co-authored-by: sellys-537 <239629995+sellys-537@users.noreply.github.com>
… values

Co-authored-by: sellys-537 <239629995+sellys-537@users.noreply.github.com>
Copilot AI changed the title [WIP] Integrate oh-my-opencode into the system feat: integrate oh-my-opencode as native built-in plugin Feb 10, 2026
Copilot AI requested a review from sellys-537 February 10, 2026 08:01
@sellys-537 sellys-537 marked this pull request as ready for review February 10, 2026 08:03
Copilot AI review requested due to automatic review settings February 10, 2026 08:03
@sellys-537 sellys-537 merged commit 4e472d0 into dev Feb 10, 2026
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Integrates the external oh-my-opencode package as a first-class, built-in coli plugin, adds centralized configuration support via coli.json, and exposes core options in the app settings UI.

Changes:

  • Adds oh-my-opencode@3.4.0 to built-in plugins and updates docs to mark it as built-in.
  • Extends server config schema + SDK Config type with a new oh_my_opencode section.
  • Syncs oh_my_opencode from coli.json into ~/.config/coli/oh-my-opencode.json, and adds a new Settings tab/UI to edit key options.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
packages/web/src/content/docs/ecosystem.mdx Marks oh-my-opencode as “built-in” in the ecosystem list.
packages/sdk/js/src/v2/gen/types.gen.ts Adds oh_my_opencode to generated SDK Config typings.
packages/opencode/src/plugin/index.ts Adds oh-my-opencode to the built-in plugin install/load list.
packages/opencode/src/config/config.ts Adds Zod schema for oh_my_opencode + sync/write-out to oh-my-opencode.json.
packages/app/src/i18n/en.ts Adds English i18n strings for the new settings tab.
packages/app/src/components/settings-ohmyopencode.tsx New settings screen for oh-my-opencode options.
packages/app/src/components/dialog-settings.tsx Adds the new “Oh My OpenCode” settings tab to the settings dialog.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1075 to +1077
main_pane_size: z.number().optional().describe("Main pane size as percentage (20-80)"),
main_pane_min_width: z.number().optional().describe("Minimum width for main pane in columns"),
agent_pane_min_width: z.number().optional().describe("Minimum width for each agent pane in columns"),
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

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

The schema docs describe main_pane_size as a percentage (20–80) and the pane widths as column counts, but the Zod schema currently allows any number (including negatives/floats/out-of-range). Add .int() and appropriate .min()/.max() constraints so invalid values are rejected at config-parse time.

Suggested change
main_pane_size: z.number().optional().describe("Main pane size as percentage (20-80)"),
main_pane_min_width: z.number().optional().describe("Minimum width for main pane in columns"),
agent_pane_min_width: z.number().optional().describe("Minimum width for each agent pane in columns"),
main_pane_size: z
.number()
.int()
.min(20)
.max(80)
.optional()
.describe("Main pane size as percentage (20-80)"),
main_pane_min_width: z
.number()
.int()
.min(1)
.optional()
.describe("Minimum width for main pane in columns"),
agent_pane_min_width: z
.number()
.int()
.min(1)
.optional()
.describe("Minimum width for each agent pane in columns"),

Copilot uses AI. Check for mistakes.
ralph_loop: z
.object({
enabled: z.boolean().optional().describe("Enable the Ralph Loop for self-referential development"),
default_max_iterations: z.number().optional().describe("Default max iterations for Ralph Loop"),
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

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

default_max_iterations is described as an iteration count but is typed as an unconstrained number. This permits non-integers/negative values; consider validating it as a positive integer (e.g., .int().positive()) to match the intent and prevent downstream runtime checks.

Suggested change
default_max_iterations: z.number().optional().describe("Default max iterations for Ralph Loop"),
default_max_iterations: z
.number()
.int()
.positive()
.optional()
.describe("Default max iterations for Ralph Loop"),

Copilot uses AI. Check for mistakes.
Comment on lines +11 to +17
const config = createMemo(() => globalSync.data.config.oh_my_opencode ?? {})

const update = (patch: Record<string, unknown>) => {
void globalSync.updateConfig({
oh_my_opencode: { ...config(), ...patch },
})
}
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

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

The UI controls here are effectively read-only because their checked/current values are derived from globalSync.data.config, but update() doesn’t update the local store (unlike other settings screens that call globalSync.set(...) optimistically). With a controlled <Switch>/<Select>, the value will snap back until the global reload finishes. Update the local store first (and rollback on request failure) so toggles/selections reflect immediately.

Copilot uses AI. Check for mistakes.
Comment on lines +737 to +740
"settings.ohmyopencode.row.disabledAgents.title": "Disabled agents",
"settings.ohmyopencode.row.disabledAgents.description": "Agents to disable (e.g., oracle, multimodal-looker)",
"settings.ohmyopencode.row.disabledHooks.title": "Disabled hooks",
"settings.ohmyopencode.row.disabledHooks.description": "Hooks to disable (e.g., comment-checker, auto-update-checker)",
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

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

These new translation keys for disabled agents/hooks are not referenced anywhere in the UI (the settings panel currently doesn’t render corresponding rows). Consider either wiring them up in SettingsOhMyOpenCode or removing the unused keys to avoid dead strings drifting over time.

Suggested change
"settings.ohmyopencode.row.disabledAgents.title": "Disabled agents",
"settings.ohmyopencode.row.disabledAgents.description": "Agents to disable (e.g., oracle, multimodal-looker)",
"settings.ohmyopencode.row.disabledHooks.title": "Disabled hooks",
"settings.ohmyopencode.row.disabledHooks.description": "Hooks to disable (e.g., comment-checker, auto-update-checker)",

Copilot uses AI. Check for mistakes.
Comment on lines +240 to +257
// Sync oh_my_opencode config to oh-my-opencode.json for the plugin to read.
// Uses deep merge so existing oh-my-opencode.json settings are preserved
// while coli.json settings take precedence.
if (result.oh_my_opencode) {
const omoConfigPath = path.join(Global.Path.config, "oh-my-opencode.json")
const existing = await Bun.file(omoConfigPath)
.json()
.catch((err: unknown) => {
if (err && typeof err === "object" && "code" in err && err.code !== "ENOENT") {
log.warn("failed to read oh-my-opencode.json", { error: err })
}
return {}
})
const merged = mergeDeep(existing, result.oh_my_opencode)
await Bun.write(omoConfigPath, JSON.stringify(merged, null, 2)).catch((err) => {
log.warn("failed to sync oh-my-opencode config", { error: err })
})
}
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

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

New behavior writes/syncs oh_my_opencode into oh-my-opencode.json, but there’s no corresponding test coverage in packages/opencode/test/config/config.test.ts for merge/precedence and error cases (missing file, existing file, invalid JSON). Adding a config test would help prevent regressions since this runs on every config load.

Copilot uses AI. Check for mistakes.
Comment on lines +245 to +252
const existing = await Bun.file(omoConfigPath)
.json()
.catch((err: unknown) => {
if (err && typeof err === "object" && "code" in err && err.code !== "ENOENT") {
log.warn("failed to read oh-my-opencode.json", { error: err })
}
return {}
})
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

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

The read error handling only logs when the caught error has a .code property (and is not ENOENT). JSON parse errors (e.g., a corrupted oh-my-opencode.json) typically won’t have code, so they’ll be silently ignored and the file will be overwritten. Consider logging for any error except ENOENT (and/or keeping the invalid file intact) so misconfigurations are diagnosable.

Copilot uses AI. Check for mistakes.
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.

2 participants