Sync OpenAI-compatible model endpoints into your agentic-dev tools — and optionally build a curated, per-model agent roster on top of them.
omodel-wire runs on your laptop, probes the model servers you point it at (e.g.
vLLM / SGLang on your DGX nodes), figures out what each model can actually do
(vision, reasoning, which thinking knob it honors), and writes the matching config.
Today it targets OpenCode; the detection and "configurator"
layers are pluggable so other tools (pi.dev, Claude Code, …) can be added later.
- Stdlib only. No
pip install, no dependencies — just Python 3. - Idempotent. Re-run any time; it merges into your existing config and preserves the settings it shouldn't touch (see Safety).
- Config-driven, no probing. Model capabilities + per-mode sampling are DECLARED
in omodel-manager's
configs/*.toml(read via--configs/$OMODEL_CONFIGS/ sibling../omodel-manager/configs). No slow per-model vision/reasoning probes on the sync path — use--verifyto check a declaration against a live endpoint.
omw is a verb-first CLI (like its sibling omm). Run it with no arguments for a
guided home screen; each command suggests the next step.
# 1) add the `omw` shell alias (re-open your shell afterwards)
python3 omodel-wire.py shell-init
# 2) see status + suggested next steps
omw
# 3) sync the OpenCode agent roster from the model configs
omw sync
# 4) inspect what you got
omw agents # primary agents (research/code/agent/team)
omw models qwen # a model's per-role sampling table
# 5) experiment live (edits are disposable — `omw sync` resets to known-good)
omw models qwen --role code --set-temperature 0.5
omw agents team --set-work-budget 4
omw audit # show what has drifted from the known-good configsCommon settings you don't want to retype live in ~/.config/otools/wire.json — set
them once and every command picks them up (precedence: flag > wire.json > default):
omw config --set default_agent code
omw config --set web_search exa
omw config # show resolved settings + their sourceBy default omw sync discovers the hosts in the shared ~/.config/otools/hosts store
(managed by omm's install/ps), on ports 8000/8001/8002 — so omm install user@ip dgx-3 makes the box visible here too. Override with omw sync --hosts / --ports.
- Detect which agentic-dev tools are installed (OpenCode today).
- Discover live models via each
/v1/modelsendpoint (fast), then read each model's capabilities (vision / reasoning / thinking-knob) and per-mode sampling from omodel-manager's declaredconfigs/*.toml— no slow per-model probing on the sync path. (omw verifyre-runs the real probes to check a declaration.) - Write the OpenCode config: providers, models (with
tool_call,attachment+modalitiesfor vision, context/output limits), a(model, agent)-keyedchat.paramsplugin that pins sampling, the agent roster, and Ctrl+T thinking variants.
Built from AGENT_SPECS, with per-mode sampling from omodel-manager's configs:
| Agent | Visibility | Role | Permissions |
|---|---|---|---|
research |
Tab | reason | read-only + web |
code |
Tab | code | edit/bash ask + web |
agent |
Tab | agent | full |
team |
Tab | orchestrator | delegation-only |
loom |
Tab | orchestrator (v2) | one loom tool call |
agent-research |
hidden | research | read-only + web |
agent-code |
hidden | implementation | full |
agent-test |
hidden | verification | read + checks, no edits |
agent-instruct |
hidden | mechanical | full |
agent-architect |
hidden | architecture | read-only |
agent-review |
hidden | review | read + checks, no edits |
team has no workspace tools; it can only delegate to the six hidden workers through task.
Team and every worker load a visible global role skill from
~/.config/opencode/skills/agent-*/SKILL.md; their system prompts contain only the bootstrap.
A repo can add .agents/skills/agent-<role>-extend/SKILL.md to append role guidance, or
agent-<role>-override to replace both the global role and extend skill. Override wins; otherwise
the global role loads before extend. Visible research/code/agent remain prompt-free and keep
OpenCode's model-specific default prompts.
The standard flow sends simple work to agent-code, routes medium/high-risk work through
agent-architect for research, plan, and acceptance criteria, sends completed implementation to
agent-test for broad/scripted verification, then sends the tested packet to agent-review.
Only findings classified as blockers or regressions enter the one-at-a-time fix loop. Once verified,
Team asks whether to create a PR and perform PR review.
loom runs the SAME pipeline over the SAME workers, but the control flow lives in code instead
of a model's context window. The loom agent does intake only (goal, criteria, scope, risk) and
makes one call to the loom custom tool; the tool runs the stdlib-Python conductor
(omw loom run), which drives the workers as real child sessions of the loom session over the
server HTTP API. You keep the native TUI experience -- cycle into workers with the arrow keys,
watch live progress on the tool card -- while routing, fix-loops, anti-spin, and the escalation
ladder (same session -> fresh session -> bigger model -> pause for you) are deterministic Python
with every transition in a SQLite ledger.
opencode --port 4096 # the TUI is the server; a pinned port lets the CLI reach it
# ... talk to `loom` in the TUI; or drive it headless:
omw loom status # jobs and their phases
omw loom watch # live event tail for the newest job
omw loom say "prefer WAL" # steer the running job (folded into the next dispatch)
omw loom resume --job 3 --note "use the staging endpoint" # continue a paused job
omw loom pr --job 3 # after your approval: branch/commit/push/PR + PR review
omw loom clean # drop finished jobs older than 7 days (+ their sessions)Both orchestrators ship side by side: Tab to team for v1, loom for v2, same workers --
an honest A/B. Tune via wire.json {"loom": {"step_timeout": 1800, "max_attempts": 3, ...}}.
OpenCode reserves the names build/plan and ignores overrides on them, so
omw sync disables the native pair and ships research/code in their place,
pointing the startup agent at --default-agent (default code, or wire.json
default_agent). omw sync --keep-builtins opts out.
Agent model preferences live in local default_models.json. --team-task-budget N is preserved
across re-syncs; without it, sync defaults the budget from the worker model's declared concurrency
(max-num-seqs).
By default, the built-in OpenCode and Hugging Face providers are disabled using
OpenCode's disabled_providers array. This keeps the provider definitions in your config
but prevents users from accidentally selecting them.
To enable these providers (e.g., if you're using their API keys), pass --add-default-providers:
omw sync --add-default-providersThis is idempotent: re-running without the flag re-applies the disabled list; with the flag,
providers are enabled. The providers remain managed by omw and will be pruned on the next
sync unless they're also running on your DGX endpoints (in which case they're kept as DGX
providers with their own dgx-* keys).
Curated capabilities + per-mode sampling live in omodel-manager's configs/*.toml
(one commented, cat/vi-friendly file per model, keyed by name-match). When a
discovered model matches, its per-mode presets become the agents above with sampling
enforced by the plugin. No match → generic code/reason. Add a model by dropping a
.toml in omodel-manager's configs/ — see that repo's configs/README.md.
omw sync --no-recipes opts out. Configs ship for Qwen3.6-27B, Qwen3.6-35B-A3B,
NVIDIA-Nemotron-3-Super, GLM-4.7-Flash, and the Gemma-4 pair. omw verify checks a live
model against its config.
omw sync --target copilot writes the same roster to the GitHub Copilot CLI instead of (or,
with --target all, alongside) OpenCode. It writes to Copilot's config home — the roster as
.agent.md files under agents/, settings.json (model + includeCoAuthoredBy: false), and an
otools-copilot.env/.ps1 snippet. The home is auto-detected: ~/.copilot on native
Windows/macOS/Linux, and — when you run omw in WSL but Copilot is installed on Windows — the
Windows-side C:\Users\<you>\.copilot (via /mnt/c). $COPILOT_HOME or --copilot-home overrides.
All three Copilot surfaces read ~/.copilot/agents/, so the same roster shows up in the
CLI/TUI (copilot → /agent), VS Code (Copilot Chat → the agents dropdown; reload the
window after syncing), and the desktop app (agent picker). The roster + settings are written even
with the DGX offline (so you can see them land); the endpoint is wired only when a model is live —
until then the agents run on Copilot's default hosted model.
Two things differ from OpenCode by Copilot's design: its CLI takes a single custom endpoint, so
the whole roster runs on one DGX model (the endpoint is env-only — hence the snippet you source
before copilot); and delegation is runtime-global by description with no subagent nesting, so
primaries become top-level agents, the workers become subagents, and agent-review is
explicit-invoke-only. A multi-model VS Code target is a planned follow-up.
omw sync --target copilot # write the Copilot roster + settings + env snippet
source ~/.copilot/otools-copilot.env # point Copilot at your DGX endpoint (bash/zsh)
copilot --agent code # run it| Command | What it does |
|---|---|
omw |
Home screen: status + suggested next steps. |
omw sync |
Build/refresh the OpenCode roster from the model configs. Carries the sync knobs (--hosts/--ports, --team-task-budget, --default-agent/--keep-builtins, --web-search, --sampling …, --dry-run, …). This is the "reset to known-good" button. |
omw sync --add-default-providers |
Enable built-in OpenCode and Hugging Face providers (by default, these are disabled and their models are hidden from the picker). |
omw agents [<name>] |
List primary agents; show one in detail. |
omw agents <name> --set-model REF |
Live-set an agent's model. |
omw agents team --set-work-budget N |
Live-set the team's delegation budget. |
omw subagents [<name>] [--set-model REF] |
List/inspect hidden workers; no name → set all workers. |
omw models [<name>] |
List models; <name> shows the per-role sampling table. |
omw models <name> --role R --set-temperature T / --set-thinking B |
Live-tweak one role's sampling/thinking. |
omw audit |
Offline side-by-side of the live config vs the known-good configs; flags drift. |
omw verify |
Probe live endpoints and compare to the declared capabilities (slow, opt-in). |
omw config [--set KEY VAL] [--edit] [--path] |
Show or persist settings in ~/.config/otools/wire.json. |
omw config --set-gh-token-coder / --set-gh-token-reviewer |
Store the two GitHub identity tokens (see below). Prompts with hidden input; pass none to clear. |
omw proxy on [<model>] / off [<model>] |
Route live models through a local debug proxy that logs every request/response (no name = all; a name = one). |
omw proxy read <id> / replay <id> [--output-curl] / status |
Read a logged exchange (colored, sectioned); re-issue it directly to the API (or emit curl); show proxy state. |
omw detect |
Report which agentic-dev tools are installed. |
omw shell-init |
Install the omw shell alias. |
Every --set-* edit touches only ~/.config/opencode/ (opencode.json + the sampling
plugin) — the declared configs stay pristine, so omw sync always restores a known-good
state and omw audit shows exactly what you've changed. Run omw <command> --help for
the full flag list of any command.
So agents commit and open PRs under a shared bot account while you review and
merge them — real two-party review — omw sync writes an OpenCode plugin
(plugins/otools-git-identity.js) that hands each shell a GitHub token. You set two tokens
once:
omw config --set-gh-token-coder # paste the BOT account's token (hidden input)
omw config --set-gh-token-reviewer # paste YOUR account's tokenEach is a GitHub PAT with Contents: Read/Write + Pull requests: Read/Write on the
repos. They're stored (chmod 600) at ~/.config/otools/gh_token_{coder,reviewer}. Coding
agents (research/team/code/agent/workers) commit and open PRs as the coder (bot);
agent-review approves and merges as the reviewer (you). github.com git is routed over
HTTPS+token automatically — no SSH keys, no ~/.gitconfig edits. Until both are set,
omw sync warns and agents fall back to your logged-in gh. Reload OpenCode after setting
them. Verify from inside OpenCode: gh api user --jq .login (→ bot) and
GH_TOKEN="$GH_TOKEN_REVIEWER" gh api user --jq .login (→ you).
omw proxy on transparently inserts a local proxy between OpenCode and your model
endpoints — no config guesswork, it reads the live provider list and rewrites those
baseURLs, mapping each back to the real upstream. It streams SSE through untouched
(so the TUI keeps working) while teeing the full request/response into proxy_logs/
(short 7-char ids, one <id>_req.json/<id>_res.json pair each, plus index.jsonl).
Then reload OpenCode, reproduce the issue, and inspect:
omw proxy on # or: omw proxy on qwen3.6-35b (one model)
# ... reproduce in OpenCode ...
omw proxy read <id> # human-readable, colored view of one exchange
omw proxy replay <id> # re-run that exact request straight at the API
omw proxy replay <id> --output-curl # ... or copy-paste it as curl
omw proxy off # restore config, stop the proxy- Non-destructive merge. The tool merges into your existing
opencode.json; it only prunes agents it manages (MANAGED_AGENTS), leaving your hand-written agents and providers alone. - Disabled providers by default. The built-in OpenCode and Hugging Face providers
are disabled by default using the
disabled_providersarray. Pass--add-default-providersto enable them (e.g., if you're using their API keys). - Anthropic config is preserved. A previously-set frontier team model — and its reasoning budget and task budget — survive re-syncs even without re-passing the flags, so your cloud config isn't wiped.
- Preview first.
--dry-runshows exactly what would be written. - Use
--allow-emptyonly if you deliberately want to write when nothing was discovered.
- Python 3 (standard library only).
- Reachable OpenAI-compatible endpoints.
- OpenCode installed (the config is still written if it isn't, so you can stage it).
See AGENTS.md for the architecture and extension points, and CONTRIBUTING.md for the branching/commit workflow.