Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

All notable changes to OpenCode Model Control are recorded here. The project follows [Semantic Versioning](https://semver.org/).

## 0.2.1 - 2026-09-01

- Made any available, capability-compatible known-paid model selectable in a role dropdown while Paid mode is active, regardless of provider. Selecting a disabled model is now the explicit opt-in that enables only that model for routing; Automatic never enables models by itself.
- Aligned role-dropdown checks with the core routing gates for saved availability, text output, tool-call capability, access, and modality. Unknown-cost, unavailable, and incompatible models remain blocked.
- Recompute capability-derived role profiles on catalog refresh, including empty capability arrays, so provider upgrades and downgrades cannot leave dynamic models with stale roles. Restore bundled curated profiles from the packaged catalog when migrating legacy snapshots that mislabeled them as capability-derived.
- Treat zero role scores as incompatible consistently across draft validation, routing, and generated OpenCode configuration.
- Added provider-agnostic regression coverage using an xAI/Grok-shaped paid model plus blocked cost, availability, capability, and automatic-selection cases.

## 0.2.0 - 2026-08-31

- Added attachment-aware Omc-Router media switching through the bundled local OpenCode plugin, with capability, modality, availability, enablement, and cost-policy gates that fail closed. Media-only analysis runs as a tool-free vision worker, while only explicit user-authored text classified as a code change may retain Omc-Router for the vision-to-code-to-review workflow.
Expand Down
26 changes: 14 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
# OpenCode Model Control

![OpenCode Model Control — Route smarter. Stay in control.](https://raw.githubusercontent.com/BitL8-ByteShort/opencode-model-control/v0.2.0/docs/assets/opencode-model-control-banner.png)
![OpenCode Model Control — Route smarter. Stay in control.](https://raw.githubusercontent.com/BitL8-ByteShort/opencode-model-control/v0.2.1/docs/assets/opencode-model-control-banner.png)

OpenCode Model Control is a local control panel and MCP companion for building a model team inside OpenCode. It discovers the models OpenCode currently exposes, lets the user decide which ones the router may use, assigns an orchestrator and specialist roles, and safely connects that policy to OpenCode.

The control panel runs on `127.0.0.1`. OpenCode remains responsible for provider authentication and model calls. Model Control does not request, extract, log, or transmit API-key or token material and does not connect directly to OpenRouter. Its guarded connector does read the local OpenCode config so it can preserve unrelated settings and create a private full-config backup. Before a manual runtime check, the local isolation guard also parses OpenCode's credential store only to inspect credential-type metadata; it does not copy secret fields into the check configuration or send them anywhere.

The running app is authoritative for model names, availability, pricing evidence, and role eligibility.

> **Release status:** Version `0.2.0` is published on [npm](https://www.npmjs.com/package/opencode-model-control/v/0.2.0) and as an [immutable GitHub release](https://github.com/BitL8-ByteShort/opencode-model-control/releases/tag/v0.2.0). Both channels serve the same verified tarball with SHA-256 `59c6094a9b7dd57b897ee59c41269b154861de408db7c138c22725d17a1e67df`. The [source repository](https://github.com/BitL8-ByteShort/opencode-model-control) is public. Linux fresh-install acceptance remains separately tracked and is not inferred from publication.
> **Release status:** This source tree is prepared as version `0.2.1`. A version in `package.json` is not proof that a distribution channel is live; verify the exact [npm version](https://www.npmjs.com/package/opencode-model-control/v/0.2.1) or [GitHub release](https://github.com/BitL8-ByteShort/opencode-model-control/releases/tag/v0.2.1) before installing. The [source repository](https://github.com/BitL8-ByteShort/opencode-model-control) is public. Linux fresh-install acceptance remains separately tracked and is not inferred from publication.

## What it does

- Reads OpenCode's resolved, all-provider model catalog rather than relying on a fixed list.
- Provides an **Update available models** action that runs a fresh OpenCode catalog refresh.
- Separates OpenCode discovery from Model Control enablement: newly discovered models are visible but disabled for routing until the user enables them.
- Separates OpenCode discovery from Model Control enablement: newly discovered models are visible but disabled for routing until the user enables one in Models or explicitly selects it for a compatible role.
- Provides a **Free / Paid** preference:
- **Free** permits only independently verified zero-cost models.
- **Paid** permits verified free and known paid models, prioritizing paid models for compatible automatic assignments.
Expand Down Expand Up @@ -51,16 +51,16 @@ The panel can open without OpenCode, but it cannot discover the user's current m
Install the exact npm version:

```sh
npm install --global opencode-model-control@0.2.0
npm install --global opencode-model-control@0.2.1
opencode-model-control
```

The first command installs `0.2.0` and its runtime dependencies. The second command starts the local panel and opens it in the default browser.
The first command installs `0.2.1` and its runtime dependencies. The second command starts the local panel and opens it in the default browser.

Then:

1. Click **Update available models** to read the models currently exposed by OpenCode.
2. Choose **Free** or **Paid**, enable the models Model Control is allowed to route to, choose whether Omc-Router should become the default agent, and save.
2. Choose **Free** or **Paid**, then enable models in Models or explicitly select compatible models for roles. A role selection enables only that chosen model. Choose whether Omc-Router should become the default agent, then save.
3. Click **Connect to OpenCode**.
4. Restart OpenCode so it loads the managed MCP, local routing plugin, and `omc-*` agents.

Expand All @@ -71,12 +71,12 @@ No JSON editing is required. Connect creates a private backup, safely merges onl
Close OpenCode and stop the running Model Control process with `Ctrl+C`, then run:

```sh
npm install --global opencode-model-control@0.2.0
npm install --global opencode-model-control@0.2.1
opencode-model-control --version
opencode-model-control
```

The version command must print `0.2.0`. In the reopened panel, click **Update available models**, review the Free/Paid preference and enabled models, click **Save changes**, then click **Update connection**. If the panel says it is disconnected, use **Connect to OpenCode** instead. Restart OpenCode and verify the managed connection:
The version command must print `0.2.1`. In the reopened panel, click **Update available models**, review the Free/Paid preference and enabled models, click **Save changes**, then click **Update connection**. If the panel says it is disconnected, use **Connect to OpenCode** instead. Restart OpenCode and verify the managed connection:

```sh
opencode-model-control status --json
Expand All @@ -98,7 +98,7 @@ Then:

1. Open the local panel (normally `http://127.0.0.1:47821`).
2. Click **Update available models** to re-read all models exposed by OpenCode's resolved provider configuration.
3. Choose **Free** or **Paid**, enable the models Model Control is allowed to route to, choose whether Omc-Router should become the default agent, and save.
3. Choose **Free** or **Paid**, then enable models in Models or explicitly select compatible models for roles. A role selection enables only that chosen model. Choose whether Omc-Router should become the default agent, then save.
4. Click **Connect to OpenCode**.
5. Restart OpenCode so it loads the managed MCP, local routing plugin, and `omc-*` agents.

Expand All @@ -111,11 +111,11 @@ The connector writes absolute Node and package CLI paths, so a source checkout d
To install the same tested tarball directly from GitHub:

```sh
npm install --global https://github.com/BitL8-ByteShort/opencode-model-control/releases/download/v0.2.0/opencode-model-control-0.2.0.tgz
npm install --global https://github.com/BitL8-ByteShort/opencode-model-control/releases/download/v0.2.1/opencode-model-control-0.2.1.tgz
opencode-model-control
```

The release publishes `opencode-model-control-0.2.0.tgz.sha256` beside the tarball. The checksum and source tag are also recorded in the public [release package ledger](https://github.com/BitL8-ByteShort/opencode-model-control/blob/v0.2.0/packages/README.md).
The release publishes `opencode-model-control-0.2.1.tgz.sha256` beside the tarball. The checksum and source tag are also recorded in the public [release package ledger](https://github.com/BitL8-ByteShort/opencode-model-control/blob/v0.2.1/packages/README.md).

## What “Update available models” means

Expand All @@ -128,7 +128,7 @@ OpenCode 1.18.x may add its standard `$schema` property when its CLI reads a pro
Catalog state is deliberately split into four concepts:

- **Discovered:** OpenCode reported the model.
- **Enabled in Model Control:** the user permits this router to select it. Newly discovered models start disabled here even if OpenCode exposes them.
- **Enabled in Model Control:** the user permits this router to select it. Newly discovered models start disabled even if OpenCode exposes them. Selecting an available, cost-allowed, compatible model in a role dropdown is an explicit opt-in that enables that one model; choosing Automatic never enables models.
- **Available:** the refreshed metadata reports it active.
- **Runtime access checked:** a manually confirmed bounded synthetic OpenCode run returned the expected sentinel. OpenCode may have retried a provider failure during that run. Refresh does not make this claim or incur a model charge, and a runtime-access pass is not benchmark evidence.

Expand All @@ -142,6 +142,8 @@ The two cost choices set both priority and permission. They never override task
- **Paid** means `paid-first + known-cost`. Known-paid models are preferred for compatible automatic assignments, but verified-free models remain eligible automatic candidates. It is not a paid-only mode.
- **Unknown pricing** is blocked in both modes. A name ending in `-free` or a zero normalized by OpenCode is not enough evidence by itself.

Paid mode grants permission but does not silently enable every discovered paid model. A compatible disabled model is marked **enable on selection** in role dropdowns; selecting it enables that exact model in the draft, and **Save changes** remains the commit point.

Selecting **Paid** can incur charges under the active OpenCode provider account. Model Control does not set or enforce provider-side budgets.

## Seamless routing boundaries
Expand Down
2 changes: 1 addition & 1 deletion docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ Pricing has three classes:

OpenCode may normalize absent price fields to zero. Therefore a zero from arbitrary CLI metadata is not, by itself, proof of free access.

The UI maps **Free** to `free-first + free-only`. It maps **Paid** to `paid-first + known-cost`. Paid mode permits both verified-free and known-paid models but prefers paid candidates after capability, availability, enablement, and qualified-evidence gates. Unknown pricing is never eligible.
The UI maps **Free** to `free-first + free-only`. It maps **Paid** to `paid-first + known-cost`. Paid mode permits both verified-free and known-paid models but prefers paid candidates after capability, availability, enablement, and qualified-evidence gates. Unknown pricing is never eligible. A deliberate compatible role selection is also an explicit model opt-in: it enables only that selected model in the unsaved draft. Automatic routing never enables models.

### Route planner

Expand Down
2 changes: 1 addition & 1 deletion docs/opencode-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ A model is:

A model name ending in `-free` is not sufficient evidence by itself. OpenCode may normalize missing pricing fields to zero, so arbitrary CLI zero values remain unknown unless independently verified.

Newly discovered models are visible and disabled by default. The user must explicitly allow Model Control to select them.
Newly discovered models are visible and disabled by default. The user must explicitly allow Model Control to select them. They can do that in Models or by deliberately choosing an available, cost-allowed, role-compatible model in a role dropdown; that selection atomically enables only the chosen model in the draft. Automatic selection never enables a model, and Save remains the commit point.

## Advanced developer tools

Expand Down
4 changes: 2 additions & 2 deletions docs/support-matrix.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ This matrix separates implemented behavior from compatibility that still needs l
| Local usage accounting | Implemented and live-tested on OpenCode 1.18.22 | Fixed aggregate DB query; 7/30/90-day and all-time windows; no prompt/content projection. |
| Usage cost values | Provider-reported estimate | OpenCode's recorded cost is displayed; it is not treated as a provider invoice. |
| Plugin-free fallback | Implemented, explicitly incomplete | Preserves a usable snapshot when plugin-aware discovery fails; plugin models may be absent. |
| Dynamic model records | Implemented | New records are visible and Model Control-disabled by default. |
| Dynamic model records | Implemented | New records are visible and Model Control-disabled by default. A compatible explicit role selection enables only that selected model; Automatic never enables models. Capability-derived roles are refreshed from current provider metadata, including empty capability sets, while bundled curated profiles are restored from the packaged catalog during legacy snapshot migration. |
| Verified-free mode | Implemented | Only independently verified exact-zero pricing is eligible. |
| Known-paid preference | Implemented | Paid mode allows verified free and known paid, preferring paid after hard gates. |
| Known-paid preference | Implemented | Paid mode allows verified free and known paid from any provider, preferring paid after hard gates. Compatible disabled models can be explicitly selected and enabled one at a time; unknown pricing remains blocked. |
| Unknown pricing | Blocked | Missing or ambiguous pricing is not assumed free and cannot auto-route. |
| Big Pickle primary | Configured, unbenchmarked | Text-first initial assignment; quality claims require benchmark evidence. |
| Attachment-aware media routing | Implemented; release acceptance pending | A media turn entering through `omc-router` selects the compatible saved vision model. Media-only analysis becomes a hard tool-free vision-worker turn; only explicit user-authored text classified as a code change retains Omc-Router. |
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "opencode-model-control",
"version": "0.2.0",
"version": "0.2.1",
"description": "A local model routing control panel and MCP companion for OpenCode.",
"keywords": [
"opencode",
Expand Down
6 changes: 6 additions & 0 deletions packages/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ This directory carries checksum-recorded copies of verified public release packa

Each tarball is produced with `npm pack` only after the full release gate passes. Its filename, version, and SHA-256 digest are recorded here so users can verify a direct download before installation.

## 0.2.1

- File: `opencode-model-control-0.2.1.tgz`
- SHA-256: `b0c0e161bec91ac384d12336d9786aa41870a65d3a291a72760a1e84fb3a489c`
- Source tag: `v0.2.1`

## 0.2.0

- File: `opencode-model-control-0.2.0.tgz`
Expand Down
Binary file added packages/opencode-model-control-0.2.1.tgz
Binary file not shown.
1 change: 1 addition & 0 deletions packages/opencode-model-control-0.2.1.tgz.sha256
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
b0c0e161bec91ac384d12336d9786aa41870a65d3a291a72760a1e84fb3a489c opencode-model-control-0.2.1.tgz
5 changes: 4 additions & 1 deletion src/core/catalog.js
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,10 @@ export function classifyModelPricing(model) {
}

export function modelSupports({ model, role, modalities, access }) {
if (!MODEL_ROLES.includes(role) || model?.roles?.[role] === undefined) return false;
const roleScore = model?.roles?.[role];
if (!MODEL_ROLES.includes(role) || !Number.isInteger(roleScore) || roleScore <= 0) {
return false;
}
if (role === "orchestrator" && model.canOrchestrate !== true) return false;
if (
(role === "orchestrator" || role === "code-worker" || role === "vision-worker") &&
Expand Down
Loading