Skip to main content

CLI tool for managing oh-my-openagent (OMO) profiles

Project description

omoctl

CI

CLI tool for managing oh-my-openagent profiles in OpenCode.

Define profiles, patch models across providers, and switch between configurations with a single command.

Install

Run on demand with no install:

uvx omoctl --help

Or install permanently:

uv tool install omoctl
omoctl --help

Examples in this README use the bare omoctl form. If you prefer uvx, prefix every command (uvx omoctl update, uvx omoctl use claude, ...).

Prerequisites

  • Python 3.11+
  • bun or npm (for fetching OMO configs via oh-my-opencode)
  • OpenCode installed and on PATH (used to list models)

Quick Start

omoctl update          # fetch & build all profiles
omoctl list            # see what's available
omoctl use claude      # activate a profile
omoctl                 # show active profile
omoctl check           # check config against available models/agents

Commands

Command Aliases Description
omoctl [show] current, status Show active profile. Use -a/-n/-j to print only the alias, name, or JSON (e.g. omoctl -j)
omoctl list ls List all profiles
omoctl use <profile> apply, switch Activate a profile (by name or alias)
omoctl update [profile] build, upgrade Fetch fresh OMO configs, apply patches, save. All profiles if omitted
omoctl remove <profile> rm Remove a stored profile
omoctl check validate, verify Check config against available models, agents, and categories
omoctl version Print version. Also available as -v

Config

Located at ~/.config/omoctl/config.yaml. Created on first run.

Minimal example

profiles:
  - name: Claude
    providers: [claude]

That's it. One profile, one provider. Run omoctl update and you're done.

Full example

active_profile: no-copilot

overrides:
  disabled_hooks:
    - context-window-monitor

patches:
  - source: { provider: google }
    target: { provider: proxy }

profiles:
  - name: Claude
    providers: [claude]

  - name: Claude & OpenAI
    providers: [claude, openai]

  - name: No Copilot
    providers: [claude, gemini, openai]
    patches:
      - source: { provider: google, model: gemini-3.1-pro-preview }
        target: { provider: proxy, model: gemini-3-1-pro-xhigh, variant: null }
    overrides:
      disabled_hooks:
        - context-window-monitor
        - some-other-hook

Fields

Field Type Description
active_profile string Profile to auto-activate after update. Optional. Does not affect what show/list report — they always reflect the actually active profile
overrides dict OMO config overrides applied to all profiles
patches list Global patches applied to all profiles (see Patches)
remove_fallbacks list Global rules for dropping entries from fallback_models lists. Each entry is a source matcher (see Removing Fallbacks)
profiles list Profile definitions (at least one required)

Profile fields

Field Type Description
name string Required. Display name. Also determines the alias (e.g. "No Copilot" -> no-copilot)
providers list Required. OMO providers to enable. Run omoctl check to see available providers
patches list Profile-specific patches. Take priority over global patches
overrides dict OMO config overrides. Deep-merged on top of the global overrides
remove_fallbacks list Profile-specific fallback-removal rules. Added to the global remove_fallbacks

Patches

Patches rewrite models in the OMO config before saving. A patch has a source (what to match) and a target (what to replace it with).

Source

The source specifies what to match. All fields are optional but at least one must be set.

Field Type Description
provider string Match models from this provider (e.g. google, anthropic)
model string, list, or dict Filter which models to match (see Model Filters)
agent string Match a specific agent (e.g. sisyphus, oracle)
category string Match a specific category (e.g. deep, quick)

These combine: { agent: sisyphus, provider: google } matches sisyphus only when it uses a google model, and { agent: sisyphus, model: [opus] } matches sisyphus only when its model passes the filter.

Target

Field Type Description
provider string Target provider. Falls back to source provider if omitted
model string, list, or dict Target model (see Model Filters)
variant string or null "max" sets variant, null removes it, omit to keep existing

Examples

patches:
  # Redirect all google models to a proxy provider
  - source: { provider: google }
    target: { provider: proxy }

  # Redirect a specific model to a specific target
  - source: { provider: google, model: gemini-3.1-pro-preview }
    target: { provider: proxy, model: gemini-3-1-pro-xhigh, variant: null }

  # Override a specific agent
  - source: { agent: sisyphus }
    target: { provider: anthropic, model: claude-opus-4-7, variant: max }

  # Override a category
  - source: { category: ultrabrain }
    target: { provider: openai, model: gpt-5.4, variant: xhigh }

Priority

  1. Agent/category patches take priority over provider/model patches
  2. Within each kind, the best-scoring source wins: an exact model match beats a filter, a filter beats no model constraint, and more specific filters beat less specific ones
  3. For agent/category patches with equal model scores, having a provider constraint wins
  4. On a complete tie, the earlier patch wins — profile patches are checked before global patches

Removing Fallbacks

remove_fallbacks drops specific entries from the fallback_models lists that OMO ships with, before patches are applied. Each entry is a flat object with the same matcher fields used in Patches:

Field Type Description
provider string Match fallbacks from this provider (e.g. openai, anthropic)
model string, list, or dict Filter which models to match (see Model Filters)
agent string Only apply to fallbacks belonging to this agent (e.g. sisyphus)
category string Only apply to fallbacks belonging to this category (e.g. deep)

At least one of provider, agent, or category must be set. Matching is done against the original OMO model — not the post-patch model. So a fallback that would have been rewritten by a patch is still removed if its original model matches.

Examples

# Remove a specific model from all fallback lists globally
remove_fallbacks:
  - provider: openai
    model: gpt-4-mini

# Remove all fallbacks for a specific agent matching a filter
profiles:
  - name: No Copilot
    providers: [claude, gemini, openai]
    remove_fallbacks:
      - agent: sisyphus
        provider: openai

Priority

  1. Profile remove_fallbacks are applied alongside global remove_fallbacks (any match removes the entry)
  2. The first matching entry removes the fallback; remaining rules are not evaluated for that entry

Model Filters

The model field in source/target accepts three formats:

Exact match — a string:

model: gemini-3.1-pro-preview

Keyword filter — a list of terms that must all match:

model: [gemini, pro]

Include/exclude filter — fine-grained control:

model:
  include: [gemini, pro]
  exclude: [flash]

Model IDs are split into words and numbers (e.g. claude-opus-4-7 -> words: [claude, opus], numbers: [4, 7]). Filters match against these parts. A single term may be given without list brackets (include: opus).

Malformed filters are rejected up front: unknown keys (e.g. includes:), wrong value types, and empty filters fail at config load with the offending patch named — they never silently match everything.

File Layout

~/.config/omoctl/
  config.yaml              # your config
  active                   # active profile alias — the source of truth for `show`/`list`
  active-config.bak        # transient crash-safety backup, only present during `update`
  profiles/
    claude.json            # stored OMO config per profile
    no-copilot.json

~/.config/opencode/
  oh-my-openagent.jsonc    # active profile config (plain JSON, read by oh-my-openagent plugin)

Validation

Structural problems — invalid YAML, unknown fields, wrong types, malformed model filters — are caught when the config is loaded, so every command fails fast with a pointed error.

omoctl check additionally checks your config against live data:

  • Profile providers are valid OMO providers
  • Patch source/target providers exist in the model cache
  • Patch source/target models exist in their provider (exact strings), and filters match at least one available model
  • Patch agent and category names exist in the OMO config
  • active_profile names a defined profile

On failure, it prints each error with available options:

Validation failed with 2 error(s):

  • global patch [0]: source provider 'nonexistent' not found.
  • profile 'Test' patch [0]: source agent 'fake' not found. Available: atlas, explore, ...

Development

uv sync --group dev      # install with dev dependencies
uv run pytest            # run the test suite
uv run ruff check src/ tests/
uv run ruff format --check src/ tests/
uv run mypy src/omoctl

CI runs all of the above on Python 3.11, 3.12, and 3.13.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

omoctl-0.4.0.tar.gz (57.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

omoctl-0.4.0-py3-none-any.whl (24.3 kB view details)

Uploaded Python 3

File details

Details for the file omoctl-0.4.0.tar.gz.

File metadata

  • Download URL: omoctl-0.4.0.tar.gz
  • Upload date:
  • Size: 57.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for omoctl-0.4.0.tar.gz
Algorithm Hash digest
SHA256 6ac804067f485ec7dec8a8b9784af924dc1969cd2388fbcac3e74ffbb813e253
MD5 c115867b56d11e26d27123bdf363cfa7
BLAKE2b-256 d302adc1ca1f36f7582ae451a805fe9cf98d35a654a3fea15588049093c614dd

See more details on using hashes here.

Provenance

The following attestation bundles were made for omoctl-0.4.0.tar.gz:

Publisher: release.yml on anfreire/omoctl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file omoctl-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: omoctl-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 24.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for omoctl-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5ca9bb73e64961836428e3c09e5c2ac6cbce24512af261be167f04d441eac69e
MD5 9a174490de8db983d6dbaace2aff1c1a
BLAKE2b-256 a2db482f4b7a86bffdb7491ad0d1ae8c0e518eab9dc98a7c038a29fa5134e098

See more details on using hashes here.

Provenance

The following attestation bundles were made for omoctl-0.4.0-py3-none-any.whl:

Publisher: release.yml on anfreire/omoctl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page