Skip to content

feat(cli): add interactive TUI config editor#1529

Open
WietRob wants to merge 2 commits intocode-yeongyu:devfrom
WietRob:feature/tui-config-editor
Open

feat(cli): add interactive TUI config editor#1529
WietRob wants to merge 2 commits intocode-yeongyu:devfrom
WietRob:feature/tui-config-editor

Conversation

@WietRob
Copy link

@WietRob WietRob commented Feb 5, 2026

Summary

Add new oh-my-opencode config command - an interactive TUI for managing oh-my-opencode configuration files.

Problem

Currently, editing oh-my-opencode.json requires:

  1. Finding the config file location (~/.config/opencode/oh-my-opencode.json)
  2. Opening it in a text editor
  3. Knowing the correct schema (agent names, valid model IDs, permission values)
  4. Making changes without validation feedback
  5. No backup before modifying

Solution

An interactive TUI (using @clack/prompts) that provides:

Main Features:

  • Agent Configuration: Edit model, category, fallback_model, and permissions for each agent
  • Category Settings: Configure model and description for custom categories
  • Root Defaults: Set default_run_agent for the run command
  • Bulk Operations: Apply settings to all agents at once (set model, fallback, permissions)
  • Validation Warnings: Identify configuration issues (missing models, undefined categories)

Safety Features:

  • Creates backup before saving: config.json.backup.{timestamp}
  • Atomic writes (temp file → rename)
  • Graceful cancellation at any step

Type of Change

  • New feature

Testing

# Command launches correctly
$ bunx oh-my-opencode config --help

# TypeScript compiles without errors
$ bun x tsc --noEmit

# Existing tests still pass (13 pre-existing failures unrelated to this PR)
$ bun test

Files Added

File Lines Purpose
src/cli/config/index.ts 199 Main command with menu loop
src/cli/config/agents.ts 325 Agent configuration editor
src/cli/config/categories.ts 167 Category editor
src/cli/config/bulk.ts 180 Bulk operations
src/cli/config/validation.ts 76 Warning checks
src/cli/config/types.ts 78 Local type definitions

Screenshots

┌   oh-my-opencode config 
│
●  Config file: ~/.config/opencode/oh-my-opencode.json
│
◆  What would you like to configure?
│  ● Agents (configure model, category, fallback, permissions)
│  ○ Categories (configure model, description)
│  ○ Root Defaults (default_run_agent)
│  ○ Bulk Operations (set values for all agents)
│  ○ View Validation Warnings
│  ○ Save and Exit
│  ○ Exit without Saving
└

Checklist

  • Code follows style guidelines (uses @clack/prompts like install.ts)
  • No new dependencies added
  • TypeScript compiles without errors
  • No changes to existing config schema
  • Documentation updated in command help text

Summary by cubic

Adds a new interactive TUI command, oh-my-opencode config, to edit the config file with validation and safe saves. This makes configuring agents and categories faster and less error-prone.

  • New Features
    • Edit agents (model, category, fallback_model, permissions) and categories (model, description), with create-new category flow.
    • Set root defaults (default_run_agent) and run bulk updates (model, fallback, bash permissions) across all agents.
    • Validation view with warning count; flags missing models/categories and fallback gaps.
    • Safe saves: timestamped backup and atomic writes; graceful cancel throughout.
    • New CLI command registered with help text: bunx oh-my-opencode config.

Written for commit ca09979. Summary will update on new commits.

Add new 'oh-my-opencode config' command with interactive TUI for managing:
- Agent configurations (model, category, fallback_model, permissions)
- Category settings (model, description)
- Root defaults (default_run_agent)
- Bulk operations (set model/fallback/permissions for all agents)
- Validation warnings (missing models, undefined categories)

Features:
- Uses @clack/prompts for consistent CLI UX
- Creates backup before saving (config.json.backup.{timestamp})
- Atomic config writes (temp file → rename)
- Graceful cancellation handling
- Model picker with common models + custom option

New files:
- src/cli/config/index.ts - main command and menu loop
- src/cli/config/agents.ts - agent configuration editor
- src/cli/config/categories.ts - category editor
- src/cli/config/bulk.ts - bulk operations
- src/cli/config/validation.ts - warning checks
- src/cli/config/types.ts - local types
@github-actions
Copy link
Contributor

github-actions bot commented Feb 5, 2026

Thank you for your contribution! Before we can merge this PR, we need you to sign our Contributor License Agreement (CLA).

To sign the CLA, please comment on this PR with:

I have read the CLA Document and I hereby sign the CLA

This is a one-time requirement. Once signed, all your future contributions will be automatically accepted.


I have read the CLA Document and I hereby sign the CLA


You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot.

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

7 issues found across 7 files

Confidence score: 3/5

  • There is some user-impacting risk in src/cli/config/index.ts: canceling the discard prompt reloads from disk and drops unsaved in-memory edits, which could surprise users and lose changes.
  • createBackup in src/cli/config/index.ts moves the original config before writeConfigAtomically; if the write fails, the original path is left missing, which is a concrete configuration-loss scenario.
  • Several medium-severity config editor/validation inconsistencies (src/cli/config/agents.ts, src/cli/config/types.ts, src/cli/config/validation.ts) can silently drop or fail to warn about fallback settings, adding behavioral uncertainty.
  • Pay close attention to src/cli/config/index.ts, src/cli/config/agents.ts, src/cli/config/types.ts, src/cli/config/validation.ts - config editor data loss and warning/serialization mismatches.
Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="src/cli/config/agents.ts">

<violation number="1" location="src/cli/config/agents.ts:251">
P2: Switching from simple to detailed bash permissions loses the existing simple value; a string permission is treated like a record so every command defaults to "ask".</violation>
</file>

<file name="src/cli/config/types.ts">

<violation number="1" location="src/cli/config/types.ts:20">
P2: The TUI editor adds a `fallback_model` field to agent overrides, but the official config schema (`AgentOverrideConfigSchema`) does not define this property. As a result, any `fallback_model` value saved by the editor will be stripped/ignored during schema validation and won’t be honored at runtime.</violation>
</file>

<file name="src/cli/config/validation.ts">

<violation number="1" location="src/cli/config/validation.ts:40">
P2: Fallback warning checks the primary model field instead of the configured fallback_model, so missing-fallback warnings are incorrect.</violation>

<violation number="2" location="src/cli/config/validation.ts:53">
P2: displayValidationWarnings ignores checkFallbackWarnings results, so "missing-fallback" warnings are never shown despite display logic for them.</violation>
</file>

<file name="src/cli/config/index.ts">

<violation number="1" location="src/cli/config/index.ts:40">
P2: createBackup uses renameSync (move) before writeConfigAtomically; if the write fails, the original config is no longer at configPath and is not restored, risking configuration loss.</violation>

<violation number="2" location="src/cli/config/index.ts:50">
P2: TUI save path re-serializes JSONC with JSON.stringify, which strips all comments/trailing commas from oh-my-opencode.jsonc files.</violation>

<violation number="3" location="src/cli/config/index.ts:169">
P2: Canceling the discard prompt restarts the editor and reloads config from disk, which drops the user's unsaved in-memory changes instead of returning to the current menu state.</violation>
</file>

Since this is your first cubic review, here's how it works:

  • cubic automatically reviews your code and comments on bugs and improvements
  • Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
  • Ask questions if you need clarification on any suggestion

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

export type BashPermission = BashPermissionValue | Record<string, BashPermissionValue>

export interface AgentConfigExtended extends AgentOverrideConfig {
fallback_model?: string
Copy link

@cubic-dev-ai cubic-dev-ai bot Feb 5, 2026

Choose a reason for hiding this comment

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

P2: The TUI editor adds a fallback_model field to agent overrides, but the official config schema (AgentOverrideConfigSchema) does not define this property. As a result, any fallback_model value saved by the editor will be stripped/ignored during schema validation and won’t be honored at runtime.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/cli/config/types.ts, line 20:

<comment>The TUI editor adds a `fallback_model` field to agent overrides, but the official config schema (`AgentOverrideConfigSchema`) does not define this property. As a result, any `fallback_model` value saved by the editor will be stripped/ignored during schema validation and won’t be honored at runtime.</comment>

<file context>
@@ -0,0 +1,78 @@
+export type BashPermission = BashPermissionValue | Record<string, BashPermissionValue>
+
+export interface AgentConfigExtended extends AgentOverrideConfig {
+  fallback_model?: string
+}
+
</file context>
Fix with Cubic

function writeConfigAtomically(configPath: string, config: OhMyOpenCodeConfig): boolean {
try {
const tempPath = `${configPath}.tmp`
writeFileSync(tempPath, JSON.stringify(config, null, 2) + "\n")
Copy link

@cubic-dev-ai cubic-dev-ai bot Feb 5, 2026

Choose a reason for hiding this comment

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

P2: TUI save path re-serializes JSONC with JSON.stringify, which strips all comments/trailing commas from oh-my-opencode.jsonc files.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/cli/config/index.ts, line 50:

<comment>TUI save path re-serializes JSONC with JSON.stringify, which strips all comments/trailing commas from oh-my-opencode.jsonc files.</comment>

<file context>
@@ -0,0 +1,199 @@
+function writeConfigAtomically(configPath: string, config: OhMyOpenCodeConfig): boolean {
+  try {
+    const tempPath = `${configPath}.tmp`
+    writeFileSync(tempPath, JSON.stringify(config, null, 2) + "\n")
+    renameSync(tempPath, configPath)
+    return true
</file context>
Fix with Cubic

@acamq
Copy link

acamq commented Feb 6, 2026

🙏 thank you so much I really need this feature

- Fix createBackup to use copyFileSync instead of renameSync
  Prevents config loss if write fails after moving original

- Fix cancel/discard flow to preserve in-memory unsaved changes
  Return to menu loop instead of restarting editor

- Fix bash permission switching from simple to detailed mode
  Preserve existing simple value as default for all commands

- Fix checkFallbackWarnings to check fallback_model field
  Was incorrectly checking model field instead

- Fix displayValidationWarnings to include fallback warnings
  Now combines both model and fallback warnings

Addresses issues raised by @cubic-dev-ai in PR code-yeongyu#1529
@WietRob
Copy link
Author

WietRob commented Feb 6, 2026

I have read the CLA Document and I hereby sign the CLA

@WietRob
Copy link
Author

WietRob commented Feb 6, 2026

Thanks @cubic-dev-ai for the thorough review! I've addressed all the issues in commit ca09979:

Fixed Issues

P2: createBackup uses move instead of copy - Now uses copyFileSync to preserve original until write succeeds

P2: Cancel discard restarts editor, loses unsaved changes - Refactored to use runMenuLoop(state) which preserves the in-memory state

P2: Bash permission switching loses existing simple value - Now detects if existing value is a string and uses it as default for all commands

P2: Fallback warning checks wrong field - Fixed to check fallback_model field instead of model

P2: displayValidationWarnings ignores checkFallbackWarnings - Now combines both validateConfig() and checkFallbackWarnings() results

Deferred

⏸️ P2: JSON.stringify strips JSONC comments - This matches the existing project pattern in config-manager.ts (line 332, 338, 343, 346, 352). JSONC comment preservation would require a larger refactor across the project. Tracked as a follow-up enhancement.

Regarding fallback_model

The fallback_model field is a custom user-defined field that isn't in the official schema but is commonly used in user configs (as seen in the original issue that motivated this PR). The TUI allows editing it, and it's preserved during save. If the maintainers prefer, I can remove this feature or mark it as experimental.

@WietRob
Copy link
Author

WietRob commented Feb 6, 2026

Thanks @acamq! 🙏 I built this because I needed it too - manually editing JSON configs was painful. Let me know if you find any issues when testing!

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.

3 participants