omoctl 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- omoctl-0.1.0/.github/workflows/release.yml +51 -0
- omoctl-0.1.0/.gitignore +7 -0
- omoctl-0.1.0/LICENSE +21 -0
- omoctl-0.1.0/PKG-INFO +244 -0
- omoctl-0.1.0/README.md +217 -0
- omoctl-0.1.0/pyproject.toml +44 -0
- omoctl-0.1.0/src/omoctl/__init__.py +1 -0
- omoctl-0.1.0/src/omoctl/__main__.py +3 -0
- omoctl-0.1.0/src/omoctl/cli.py +268 -0
- omoctl-0.1.0/src/omoctl/config.py +156 -0
- omoctl-0.1.0/src/omoctl/models.py +184 -0
- omoctl-0.1.0/src/omoctl/omo.py +107 -0
- omoctl-0.1.0/src/omoctl/output.py +100 -0
- omoctl-0.1.0/src/omoctl/patching.py +221 -0
- omoctl-0.1.0/src/omoctl/paths.py +18 -0
- omoctl-0.1.0/src/omoctl/store.py +51 -0
- omoctl-0.1.0/src/omoctl/types.py +98 -0
- omoctl-0.1.0/src/omoctl/validate.py +106 -0
- omoctl-0.1.0/uv.lock +82 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
name: Release to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*.*.*"
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
build:
|
|
11
|
+
name: Build distributions
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
|
|
16
|
+
- name: Install uv
|
|
17
|
+
uses: astral-sh/setup-uv@v6
|
|
18
|
+
with:
|
|
19
|
+
python-version: "3.12"
|
|
20
|
+
|
|
21
|
+
- name: Build sdist + wheel
|
|
22
|
+
run: uv build
|
|
23
|
+
|
|
24
|
+
- name: Verify metadata
|
|
25
|
+
run: |
|
|
26
|
+
uv tool run --from twine twine check dist/*
|
|
27
|
+
|
|
28
|
+
- name: Upload distributions
|
|
29
|
+
uses: actions/upload-artifact@v4
|
|
30
|
+
with:
|
|
31
|
+
name: dist
|
|
32
|
+
path: dist/
|
|
33
|
+
|
|
34
|
+
publish:
|
|
35
|
+
name: Publish to PyPI
|
|
36
|
+
needs: build
|
|
37
|
+
runs-on: ubuntu-latest
|
|
38
|
+
environment:
|
|
39
|
+
name: pypi
|
|
40
|
+
url: https://pypi.org/p/omoctl
|
|
41
|
+
permissions:
|
|
42
|
+
id-token: write
|
|
43
|
+
steps:
|
|
44
|
+
- name: Download distributions
|
|
45
|
+
uses: actions/download-artifact@v4
|
|
46
|
+
with:
|
|
47
|
+
name: dist
|
|
48
|
+
path: dist/
|
|
49
|
+
|
|
50
|
+
- name: Publish to PyPI
|
|
51
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
omoctl-0.1.0/.gitignore
ADDED
omoctl-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 André Ferreira
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
omoctl-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: omoctl
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: CLI tool for managing oh-my-openagent (OMO) profiles
|
|
5
|
+
Project-URL: Homepage, https://github.com/anfreire/omoctl
|
|
6
|
+
Project-URL: Repository, https://github.com/anfreire/omoctl
|
|
7
|
+
Project-URL: Issues, https://github.com/anfreire/omoctl/issues
|
|
8
|
+
Author-email: André Ferreira <anfreire.dev@gmail.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: ai-agents,cli,oh-my-openagent,omo,opencode,profile-manager
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Operating System :: MacOS
|
|
16
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Software Development
|
|
22
|
+
Classifier: Topic :: Utilities
|
|
23
|
+
Requires-Python: >=3.11
|
|
24
|
+
Requires-Dist: dacite>=1.8
|
|
25
|
+
Requires-Dist: pyyaml>=6.0
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# omoctl
|
|
29
|
+
|
|
30
|
+
CLI tool for managing [oh-my-openagent](https://github.com/code-yeongyu/oh-my-openagent) profiles in [OpenCode](https://opencode.ai).
|
|
31
|
+
|
|
32
|
+
Define profiles, patch models across providers, and switch between configurations with a single command.
|
|
33
|
+
|
|
34
|
+
## Run
|
|
35
|
+
|
|
36
|
+
No install needed — run on demand with `uvx`:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
uvx omoctl --help
|
|
40
|
+
uvx omoctl update
|
|
41
|
+
uvx omoctl switch claude
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
> The first run downloads the package; subsequent runs are cached.
|
|
45
|
+
|
|
46
|
+
### Prerequisites
|
|
47
|
+
|
|
48
|
+
- Python 3.11+
|
|
49
|
+
- [bun](https://bun.sh) (for fetching OMO configs via `oh-my-opencode`)
|
|
50
|
+
- OpenCode installed with a populated model cache (`~/.cache/opencode/models.json`)
|
|
51
|
+
|
|
52
|
+
## Quick Start
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
omoctl update # fetch & build all profiles
|
|
56
|
+
omoctl list # see what's available
|
|
57
|
+
omoctl switch claude # activate a profile
|
|
58
|
+
omoctl # show active profile
|
|
59
|
+
omoctl validate # check config against available models/agents
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Commands
|
|
63
|
+
|
|
64
|
+
| Command | Description |
|
|
65
|
+
|---|---|
|
|
66
|
+
| `omoctl` | Show active profile |
|
|
67
|
+
| `omoctl list` | List all profiles |
|
|
68
|
+
| `omoctl switch <profile>` | Switch to a profile (by name or alias) |
|
|
69
|
+
| `omoctl update [profile]` | Fetch fresh OMO configs, apply patches, save. All profiles if omitted |
|
|
70
|
+
| `omoctl remove <profile>` | Remove a stored profile |
|
|
71
|
+
| `omoctl validate` | Validate config against available models, agents, and categories |
|
|
72
|
+
| `omoctl show [-a\|-n\|-j]` | Show active profile: header + JSON by default; `-a` alias only, `-n` name only, `-j` JSON only |
|
|
73
|
+
| `omoctl version` | Print version |
|
|
74
|
+
|
|
75
|
+
## Config
|
|
76
|
+
|
|
77
|
+
Located at `~/.config/omoctl/config.yaml`. Created on first run.
|
|
78
|
+
|
|
79
|
+
### Minimal example
|
|
80
|
+
|
|
81
|
+
```yaml
|
|
82
|
+
profiles:
|
|
83
|
+
- name: Claude
|
|
84
|
+
providers: [claude]
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
That's it. One profile, one provider. Run `omoctl update` and you're done.
|
|
88
|
+
|
|
89
|
+
### Full example
|
|
90
|
+
|
|
91
|
+
```yaml
|
|
92
|
+
active_profile: no-copilot
|
|
93
|
+
|
|
94
|
+
defaults:
|
|
95
|
+
disabled_hooks:
|
|
96
|
+
- context-window-monitor
|
|
97
|
+
|
|
98
|
+
patches:
|
|
99
|
+
- source: { provider: google }
|
|
100
|
+
target: { provider: proxy }
|
|
101
|
+
|
|
102
|
+
profiles:
|
|
103
|
+
- name: Claude
|
|
104
|
+
providers: [claude]
|
|
105
|
+
|
|
106
|
+
- name: Claude & OpenAI
|
|
107
|
+
providers: [claude, openai]
|
|
108
|
+
|
|
109
|
+
- name: No Copilot
|
|
110
|
+
providers: [claude, gemini, openai]
|
|
111
|
+
patches:
|
|
112
|
+
- source: { provider: google, model: gemini-3.1-pro-preview }
|
|
113
|
+
target: { provider: proxy, model: gemini-3-1-pro-xhigh, variant: null }
|
|
114
|
+
overrides:
|
|
115
|
+
disabled_hooks:
|
|
116
|
+
- context-window-monitor
|
|
117
|
+
- some-other-hook
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Fields
|
|
121
|
+
|
|
122
|
+
| Field | Type | Description |
|
|
123
|
+
|---|---|---|
|
|
124
|
+
| `active_profile` | string | Profile to auto-activate after `update`. Optional |
|
|
125
|
+
| `defaults` | dict | OMO config overrides applied to all profiles |
|
|
126
|
+
| `patches` | list | Global patches applied to all profiles (see [Patches](#patches)) |
|
|
127
|
+
| `profiles` | list | Profile definitions (at least one required) |
|
|
128
|
+
|
|
129
|
+
### Profile fields
|
|
130
|
+
|
|
131
|
+
| Field | Type | Description |
|
|
132
|
+
|---|---|---|
|
|
133
|
+
| `name` | string | **Required.** Display name. Also determines the alias (e.g. `"No Copilot"` -> `no-copilot`) |
|
|
134
|
+
| `providers` | list | **Required.** OMO providers to enable. Run `omoctl validate` to see available providers |
|
|
135
|
+
| `patches` | list | Profile-specific patches. Take priority over global patches |
|
|
136
|
+
| `overrides` | dict | OMO config overrides. Deep-merged on top of `defaults` |
|
|
137
|
+
|
|
138
|
+
## Patches
|
|
139
|
+
|
|
140
|
+
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).
|
|
141
|
+
|
|
142
|
+
### Source
|
|
143
|
+
|
|
144
|
+
The source specifies what to match. All fields are optional but at least one must be set.
|
|
145
|
+
|
|
146
|
+
| Field | Type | Description |
|
|
147
|
+
|---|---|---|
|
|
148
|
+
| `provider` | string | Match models from this provider (e.g. `google`, `anthropic`) |
|
|
149
|
+
| `model` | string, list, or dict | Filter which models to match (see [Model Filters](#model-filters)) |
|
|
150
|
+
| `agent` | string | Match a specific agent (e.g. `sisyphus`, `oracle`) |
|
|
151
|
+
| `category` | string | Match a specific category (e.g. `deep`, `quick`) |
|
|
152
|
+
|
|
153
|
+
These combine: `{ agent: sisyphus, provider: google }` matches sisyphus only when it uses a google model.
|
|
154
|
+
|
|
155
|
+
### Target
|
|
156
|
+
|
|
157
|
+
| Field | Type | Description |
|
|
158
|
+
|---|---|---|
|
|
159
|
+
| `provider` | string | Target provider. Falls back to source provider if omitted |
|
|
160
|
+
| `model` | string, list, or dict | Target model (see [Model Filters](#model-filters)) |
|
|
161
|
+
| `variant` | string or null | `"max"` sets variant, `null` removes it, omit to keep existing |
|
|
162
|
+
|
|
163
|
+
### Examples
|
|
164
|
+
|
|
165
|
+
```yaml
|
|
166
|
+
patches:
|
|
167
|
+
# Redirect all google models to a proxy provider
|
|
168
|
+
- source: { provider: google }
|
|
169
|
+
target: { provider: proxy }
|
|
170
|
+
|
|
171
|
+
# Redirect a specific model to a specific target
|
|
172
|
+
- source: { provider: google, model: gemini-3.1-pro-preview }
|
|
173
|
+
target: { provider: proxy, model: gemini-3-1-pro-xhigh, variant: null }
|
|
174
|
+
|
|
175
|
+
# Override a specific agent
|
|
176
|
+
- source: { agent: sisyphus }
|
|
177
|
+
target: { provider: anthropic, model: claude-opus-4-7, variant: max }
|
|
178
|
+
|
|
179
|
+
# Override a category
|
|
180
|
+
- source: { category: ultrabrain }
|
|
181
|
+
target: { provider: openai, model: gpt-5.4, variant: xhigh }
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Priority
|
|
185
|
+
|
|
186
|
+
1. Profile patches are checked before global patches
|
|
187
|
+
2. Agent/category patches take priority over provider-only patches
|
|
188
|
+
3. Exact model matches beat filter matches
|
|
189
|
+
4. More specific filters beat less specific ones
|
|
190
|
+
|
|
191
|
+
## Model Filters
|
|
192
|
+
|
|
193
|
+
The `model` field in source/target accepts three formats:
|
|
194
|
+
|
|
195
|
+
**Exact match** — a string:
|
|
196
|
+
```yaml
|
|
197
|
+
model: gemini-3.1-pro-preview
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
**Keyword filter** — a list of terms that must all match:
|
|
201
|
+
```yaml
|
|
202
|
+
model: [gemini, pro]
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
**Include/exclude filter** — fine-grained control:
|
|
206
|
+
```yaml
|
|
207
|
+
model:
|
|
208
|
+
include: [gemini, pro]
|
|
209
|
+
exclude: [flash]
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
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.
|
|
213
|
+
|
|
214
|
+
## File Layout
|
|
215
|
+
|
|
216
|
+
```
|
|
217
|
+
~/.config/omoctl/
|
|
218
|
+
config.yaml # your config
|
|
219
|
+
active # current active profile alias
|
|
220
|
+
profiles/
|
|
221
|
+
claude.json # stored OMO config per profile
|
|
222
|
+
no-copilot.json
|
|
223
|
+
|
|
224
|
+
~/.config/opencode/
|
|
225
|
+
oh-my-openagent.jsonc # active profile config (plain JSON, read by oh-my-openagent plugin)
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Validation
|
|
229
|
+
|
|
230
|
+
`omoctl validate` checks your config against live data:
|
|
231
|
+
|
|
232
|
+
- Patch source/target **providers** exist in the model cache
|
|
233
|
+
- Patch source/target **models** exist in their provider
|
|
234
|
+
- Patch **agent** names exist in the OMO config
|
|
235
|
+
- Patch **category** names exist in the OMO config
|
|
236
|
+
|
|
237
|
+
On failure, it prints each error with available options:
|
|
238
|
+
|
|
239
|
+
```
|
|
240
|
+
Validation failed with 2 error(s):
|
|
241
|
+
|
|
242
|
+
• global patch [0]: source provider 'nonexistent' not found.
|
|
243
|
+
• profile 'Test' patch [0]: source agent 'fake' not found. Available: atlas, explore, ...
|
|
244
|
+
```
|
omoctl-0.1.0/README.md
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# omoctl
|
|
2
|
+
|
|
3
|
+
CLI tool for managing [oh-my-openagent](https://github.com/code-yeongyu/oh-my-openagent) profiles in [OpenCode](https://opencode.ai).
|
|
4
|
+
|
|
5
|
+
Define profiles, patch models across providers, and switch between configurations with a single command.
|
|
6
|
+
|
|
7
|
+
## Run
|
|
8
|
+
|
|
9
|
+
No install needed — run on demand with `uvx`:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
uvx omoctl --help
|
|
13
|
+
uvx omoctl update
|
|
14
|
+
uvx omoctl switch claude
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
> The first run downloads the package; subsequent runs are cached.
|
|
18
|
+
|
|
19
|
+
### Prerequisites
|
|
20
|
+
|
|
21
|
+
- Python 3.11+
|
|
22
|
+
- [bun](https://bun.sh) (for fetching OMO configs via `oh-my-opencode`)
|
|
23
|
+
- OpenCode installed with a populated model cache (`~/.cache/opencode/models.json`)
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
omoctl update # fetch & build all profiles
|
|
29
|
+
omoctl list # see what's available
|
|
30
|
+
omoctl switch claude # activate a profile
|
|
31
|
+
omoctl # show active profile
|
|
32
|
+
omoctl validate # check config against available models/agents
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Commands
|
|
36
|
+
|
|
37
|
+
| Command | Description |
|
|
38
|
+
|---|---|
|
|
39
|
+
| `omoctl` | Show active profile |
|
|
40
|
+
| `omoctl list` | List all profiles |
|
|
41
|
+
| `omoctl switch <profile>` | Switch to a profile (by name or alias) |
|
|
42
|
+
| `omoctl update [profile]` | Fetch fresh OMO configs, apply patches, save. All profiles if omitted |
|
|
43
|
+
| `omoctl remove <profile>` | Remove a stored profile |
|
|
44
|
+
| `omoctl validate` | Validate config against available models, agents, and categories |
|
|
45
|
+
| `omoctl show [-a\|-n\|-j]` | Show active profile: header + JSON by default; `-a` alias only, `-n` name only, `-j` JSON only |
|
|
46
|
+
| `omoctl version` | Print version |
|
|
47
|
+
|
|
48
|
+
## Config
|
|
49
|
+
|
|
50
|
+
Located at `~/.config/omoctl/config.yaml`. Created on first run.
|
|
51
|
+
|
|
52
|
+
### Minimal example
|
|
53
|
+
|
|
54
|
+
```yaml
|
|
55
|
+
profiles:
|
|
56
|
+
- name: Claude
|
|
57
|
+
providers: [claude]
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
That's it. One profile, one provider. Run `omoctl update` and you're done.
|
|
61
|
+
|
|
62
|
+
### Full example
|
|
63
|
+
|
|
64
|
+
```yaml
|
|
65
|
+
active_profile: no-copilot
|
|
66
|
+
|
|
67
|
+
defaults:
|
|
68
|
+
disabled_hooks:
|
|
69
|
+
- context-window-monitor
|
|
70
|
+
|
|
71
|
+
patches:
|
|
72
|
+
- source: { provider: google }
|
|
73
|
+
target: { provider: proxy }
|
|
74
|
+
|
|
75
|
+
profiles:
|
|
76
|
+
- name: Claude
|
|
77
|
+
providers: [claude]
|
|
78
|
+
|
|
79
|
+
- name: Claude & OpenAI
|
|
80
|
+
providers: [claude, openai]
|
|
81
|
+
|
|
82
|
+
- name: No Copilot
|
|
83
|
+
providers: [claude, gemini, openai]
|
|
84
|
+
patches:
|
|
85
|
+
- source: { provider: google, model: gemini-3.1-pro-preview }
|
|
86
|
+
target: { provider: proxy, model: gemini-3-1-pro-xhigh, variant: null }
|
|
87
|
+
overrides:
|
|
88
|
+
disabled_hooks:
|
|
89
|
+
- context-window-monitor
|
|
90
|
+
- some-other-hook
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Fields
|
|
94
|
+
|
|
95
|
+
| Field | Type | Description |
|
|
96
|
+
|---|---|---|
|
|
97
|
+
| `active_profile` | string | Profile to auto-activate after `update`. Optional |
|
|
98
|
+
| `defaults` | dict | OMO config overrides applied to all profiles |
|
|
99
|
+
| `patches` | list | Global patches applied to all profiles (see [Patches](#patches)) |
|
|
100
|
+
| `profiles` | list | Profile definitions (at least one required) |
|
|
101
|
+
|
|
102
|
+
### Profile fields
|
|
103
|
+
|
|
104
|
+
| Field | Type | Description |
|
|
105
|
+
|---|---|---|
|
|
106
|
+
| `name` | string | **Required.** Display name. Also determines the alias (e.g. `"No Copilot"` -> `no-copilot`) |
|
|
107
|
+
| `providers` | list | **Required.** OMO providers to enable. Run `omoctl validate` to see available providers |
|
|
108
|
+
| `patches` | list | Profile-specific patches. Take priority over global patches |
|
|
109
|
+
| `overrides` | dict | OMO config overrides. Deep-merged on top of `defaults` |
|
|
110
|
+
|
|
111
|
+
## Patches
|
|
112
|
+
|
|
113
|
+
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).
|
|
114
|
+
|
|
115
|
+
### Source
|
|
116
|
+
|
|
117
|
+
The source specifies what to match. All fields are optional but at least one must be set.
|
|
118
|
+
|
|
119
|
+
| Field | Type | Description |
|
|
120
|
+
|---|---|---|
|
|
121
|
+
| `provider` | string | Match models from this provider (e.g. `google`, `anthropic`) |
|
|
122
|
+
| `model` | string, list, or dict | Filter which models to match (see [Model Filters](#model-filters)) |
|
|
123
|
+
| `agent` | string | Match a specific agent (e.g. `sisyphus`, `oracle`) |
|
|
124
|
+
| `category` | string | Match a specific category (e.g. `deep`, `quick`) |
|
|
125
|
+
|
|
126
|
+
These combine: `{ agent: sisyphus, provider: google }` matches sisyphus only when it uses a google model.
|
|
127
|
+
|
|
128
|
+
### Target
|
|
129
|
+
|
|
130
|
+
| Field | Type | Description |
|
|
131
|
+
|---|---|---|
|
|
132
|
+
| `provider` | string | Target provider. Falls back to source provider if omitted |
|
|
133
|
+
| `model` | string, list, or dict | Target model (see [Model Filters](#model-filters)) |
|
|
134
|
+
| `variant` | string or null | `"max"` sets variant, `null` removes it, omit to keep existing |
|
|
135
|
+
|
|
136
|
+
### Examples
|
|
137
|
+
|
|
138
|
+
```yaml
|
|
139
|
+
patches:
|
|
140
|
+
# Redirect all google models to a proxy provider
|
|
141
|
+
- source: { provider: google }
|
|
142
|
+
target: { provider: proxy }
|
|
143
|
+
|
|
144
|
+
# Redirect a specific model to a specific target
|
|
145
|
+
- source: { provider: google, model: gemini-3.1-pro-preview }
|
|
146
|
+
target: { provider: proxy, model: gemini-3-1-pro-xhigh, variant: null }
|
|
147
|
+
|
|
148
|
+
# Override a specific agent
|
|
149
|
+
- source: { agent: sisyphus }
|
|
150
|
+
target: { provider: anthropic, model: claude-opus-4-7, variant: max }
|
|
151
|
+
|
|
152
|
+
# Override a category
|
|
153
|
+
- source: { category: ultrabrain }
|
|
154
|
+
target: { provider: openai, model: gpt-5.4, variant: xhigh }
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Priority
|
|
158
|
+
|
|
159
|
+
1. Profile patches are checked before global patches
|
|
160
|
+
2. Agent/category patches take priority over provider-only patches
|
|
161
|
+
3. Exact model matches beat filter matches
|
|
162
|
+
4. More specific filters beat less specific ones
|
|
163
|
+
|
|
164
|
+
## Model Filters
|
|
165
|
+
|
|
166
|
+
The `model` field in source/target accepts three formats:
|
|
167
|
+
|
|
168
|
+
**Exact match** — a string:
|
|
169
|
+
```yaml
|
|
170
|
+
model: gemini-3.1-pro-preview
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**Keyword filter** — a list of terms that must all match:
|
|
174
|
+
```yaml
|
|
175
|
+
model: [gemini, pro]
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**Include/exclude filter** — fine-grained control:
|
|
179
|
+
```yaml
|
|
180
|
+
model:
|
|
181
|
+
include: [gemini, pro]
|
|
182
|
+
exclude: [flash]
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
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.
|
|
186
|
+
|
|
187
|
+
## File Layout
|
|
188
|
+
|
|
189
|
+
```
|
|
190
|
+
~/.config/omoctl/
|
|
191
|
+
config.yaml # your config
|
|
192
|
+
active # current active profile alias
|
|
193
|
+
profiles/
|
|
194
|
+
claude.json # stored OMO config per profile
|
|
195
|
+
no-copilot.json
|
|
196
|
+
|
|
197
|
+
~/.config/opencode/
|
|
198
|
+
oh-my-openagent.jsonc # active profile config (plain JSON, read by oh-my-openagent plugin)
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Validation
|
|
202
|
+
|
|
203
|
+
`omoctl validate` checks your config against live data:
|
|
204
|
+
|
|
205
|
+
- Patch source/target **providers** exist in the model cache
|
|
206
|
+
- Patch source/target **models** exist in their provider
|
|
207
|
+
- Patch **agent** names exist in the OMO config
|
|
208
|
+
- Patch **category** names exist in the OMO config
|
|
209
|
+
|
|
210
|
+
On failure, it prints each error with available options:
|
|
211
|
+
|
|
212
|
+
```
|
|
213
|
+
Validation failed with 2 error(s):
|
|
214
|
+
|
|
215
|
+
• global patch [0]: source provider 'nonexistent' not found.
|
|
216
|
+
• profile 'Test' patch [0]: source agent 'fake' not found. Available: atlas, explore, ...
|
|
217
|
+
```
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "omoctl"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "CLI tool for managing oh-my-openagent (OMO) profiles"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
authors = [
|
|
14
|
+
{ name = "André Ferreira", email = "anfreire.dev@gmail.com" },
|
|
15
|
+
]
|
|
16
|
+
keywords = ["omo", "oh-my-openagent", "opencode", "cli", "profile-manager", "ai-agents"]
|
|
17
|
+
classifiers = [
|
|
18
|
+
"Development Status :: 3 - Alpha",
|
|
19
|
+
"Environment :: Console",
|
|
20
|
+
"Intended Audience :: Developers",
|
|
21
|
+
"Operating System :: POSIX :: Linux",
|
|
22
|
+
"Operating System :: MacOS",
|
|
23
|
+
"Programming Language :: Python :: 3",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Programming Language :: Python :: 3.13",
|
|
27
|
+
"Topic :: Software Development",
|
|
28
|
+
"Topic :: Utilities",
|
|
29
|
+
]
|
|
30
|
+
dependencies = [
|
|
31
|
+
"pyyaml>=6.0",
|
|
32
|
+
"dacite>=1.8",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[project.scripts]
|
|
36
|
+
omoctl = "omoctl.cli:main"
|
|
37
|
+
|
|
38
|
+
[project.urls]
|
|
39
|
+
Homepage = "https://github.com/anfreire/omoctl"
|
|
40
|
+
Repository = "https://github.com/anfreire/omoctl"
|
|
41
|
+
Issues = "https://github.com/anfreire/omoctl/issues"
|
|
42
|
+
|
|
43
|
+
[tool.hatch.build.targets.wheel]
|
|
44
|
+
packages = ["src/omoctl"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.0"
|