merge: integrate goal loop and audited model routing

This commit is contained in:
Evandro committed 2026-09-25 14:22:53 -03:00
commit fda614e2e7
19 files changed
+29127 -104

No files matched your search

+4
View File
@@ -16,7 +16,11 @@ jobs:
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Isolamento Linux para testes do loop
run: sudo apt-get update && sudo apt-get install -y bubblewrap
- name: Lint das skills, agentes e hooks
run: python3 qa/lint_skills.py
- name: Testes do gate e dos hooks
run: python3 qa/test_gate.py
- name: Testes comportamentais de catálogo, roteador, adapters e loop
run: python3 -m unittest discover -s qa -p 'test_*.py' -q
+13
View File
@@ -1,5 +1,18 @@
# Changelog
## Unreleased (2026-09-25)
### Added
- Catalog sync/list/route for OpenCode and OMP with exact model IDs, public Zen/Go sources, OpenRouter reference tariffs, manually audited Artificial Analysis v1.5/account evidence, provenance, fixed score bands and fail-closed billing checks.
- Opt-in external goal loop with protected evaluator, isolated detached git worktrees, current quality-gate verification, budgets, evidence, stop/resume and no automatic merge or publish.
- Native OMP package installation with seven agents and skills; Hermes remains skills-only. Claude Code/OpenCode/OMP goal-loop runners use constrained role tools.
- Full 2026-09-25 Zen/Go catalog CSV with public-source hashes, missing-score/price coverage and account-eligibility exclusions; CLI and integration regressions.
### Security
- Autonomous evaluator and quality gate require Linux bubblewrap and run without network access; agent CLIs retain network access for their configured providers. Neither the worktree nor this sandbox guarantees provider-only egress.
- Detached attempts keep `.git` read-only to untrusted processes, revalidate the worktree before staging, and gate/score separate clean copies of each candidate commit. Unreported paid usage blocks automatic resume.
- OMP discovery and dispatch validate each advertised thinking level and preserve slash-bearing model IDs; routing requires a matching exact harness or explicit proxy approval and an explicit budget for Zen. OpenRouter long-context overrides affect comparative costs, and archived CSV staleness can be replayed at a fixed UTC time.
## 2.0.0 (2026-09-24)
### Added
+165 -82
View File
@@ -2,125 +2,208 @@
# Dev Workflows
**A Claude Code plugin (also for opencode and Hermes Agent) that sizes the process to the request**: a router picks the tier, least-privilege agents do the work, and a deterministic quality gate decides when it is done.
**A proportional development workflow for coding agents.**
Claude Code plugin · OpenCode and OMP adapters · Hermes skills-only installation
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
[![Agent Skills](https://img.shields.io/badge/Agent%20Skills-1.0-8A2BE2)](https://agentskills.io)
[![CI](https://github.com/evandrodevbr/dev-workflows/actions/workflows/ci.yml/badge.svg)](.github/workflows/ci.yml)
**🇧🇷 [Ler em português](README.pt-BR.md)**
[Português (Brasil)](README.pt-BR.md)
[Overview](#overview) · [Install](#install) · [Daily workflow](#daily-workflow) ·
[Goal loop](#optional-goal-driven-loop) · [Model routing](#model-catalog-and-routing) ·
[Safety](#safety-and-limitations)
</div>
---
## Overview
## Why
Agents can write code quickly; deciding **how much process a change needs** and **whether it was actually verified** is harder. Dev Workflows supplies a small workflow router, least-privilege agents, and a deterministic quality gate. Two separate command-line tools add model discovery and goal-driven iteration when you explicitly use them.
Agents write code fast and are bad at two things: knowing when a task deserves more process, and
admitting what they did not verify. This plugin handles both:
- **Process proportional to the request.** A typo does not get a design review; an auth change does.
- **Proof, not claims.** "Done" requires a quality-gate report on the current diff. A tool that is not installed shows up as *unverified*, never as passed.
- **Least code.** Reuse before writing, delete before adding, no dependency without a reason.
- **Security from live sources.** A model's CVE knowledge stops at its training cutoff, so reviews query OSV.dev and stamp the date.
## How it works
`dev-router` loads first and declares a tier:
| Tier | When | What runs |
| Capability | What it does | How it starts |
|---|---|---|
| 0, trivial | nothing changes behavior | the change + gate tier 0 |
| 1, small | 1–3 files, no new public surface | `wf-bugfix` or `wf-refactor`, regression test, gate tier 1 |
| 2, feature | new endpoint/screen, contract change, new dependency | explore, short plan, TDD, independent review, gate tier 2 |
| 3, large/risky | several modules, existing data, architecture, release | EARS spec + ADR approved by you, reviews, security audit, gate tier 3 |
| **Development workflow** | Chooses a tier (0–3), loads relevant skills/agents, and checks the current diff. | Install the plugin or skills. |
| **Model catalog** | Shows exact provider IDs, account eligibility, evidence, scores, and reference prices without invoking a model. | Run `scripts/model_catalog.py`. |
| **Goal loop** | Measures an application goal, tests isolated changes, and retains only verified improvements. | Configure the project and explicitly run `scripts/goal_loop.py`. |
Security triggers raise the tier at any point: auth, money, personal data, uploads, raw SQL,
shell/exec, deserialization, schema migrations, new dependencies, features that call an LLM.
## What is inside
| Kind | Items |
|---|---|
| Router and rules | `dev-router`, `lean-code` |
| Workflows | `wf-bugfix`, `wf-refactor`, `wf-frontend`, `wf-backend`, `wf-architecture`, `wf-security-review`, `wf-readme` |
| Agents | `explorer` (haiku, read-only), `planner` (opus, read-only), `implementer` (sonnet), `reviewer` (opus, read-only, sees only the diff), `security-auditor` (opus, read-only), `ui-critic` (sonnet, read-only), `verifier` (haiku, runs the gate) |
| Hooks | `Stop`: blocks "done" while code changed without a fresh passing gate · `PreToolUse`: denies `--no-verify` and force-push, asks before `reset --hard`, `clean -f`, `DROP TABLE` · `PostToolUse`: formats edited files with the project's own formatter |
| Quality gate | [`scripts/quality-gate`](scripts/quality-gate): lint, typecheck, tests, gitleaks (tier 0); diff coverage, semgrep, dead code (tier 1); build, mutation testing, osv-scanner, architecture rules, duplication (tier 2); trivy, requirement→test traceability (tier 3) |
| Vendored skills | security pillar (OWASP secure-agent-playbook, UnitOneAI SecuritySkills, safedeps, hermaguard) and taste-skill for frontend. Origin and license: [`skills/NOTICE.md`](skills/NOTICE.md) |
The gate runs only the checks of the requested tier, only on the diff, and needs no AI: it is
plain tooling. Checks that need the app running (Lighthouse CI budgets, Playwright + axe, schemathesis,
k6) are added per project in `.dev-workflows.toml`. Reference:
[`skills/dev-router/references/quality-gate.md`](skills/dev-router/references/quality-gate.md).
**Installing the plugin does not start the goal loop, buy model access, or alter your project.** The model's coding-benchmark score and your application's goal score are different measurements.
## Install
```bash
git clone https://github.com/evandrodevbr/dev-workflows && cd dev-workflows
Clone the repository, then choose the runtime you use:
python3 scripts/install.py claude # plugin: skills + agents + hooks
python3 scripts/install.py opencode # skills, agents and a plugin in ~/.config/opencode
python3 scripts/install.py hermes # skills only, in ~/.hermes/skills
```bash
git clone https://github.com/evandrodevbr/dev-workflows
cd dev-workflows
python3 scripts/install.py claude # Claude Code: plugin, agents, skills, hooks
python3 scripts/install.py opencode # OpenCode: plugin, agents, skills
python3 scripts/install.py omp # OMP: native package, agents, skills
python3 scripts/install.py hermes # Hermes Agent: skills only
```
Claude Code without cloning:
For Claude Code, you can instead install from its marketplace without cloning:
```text
/plugin marketplace add evandrodevbr/dev-workflows
/plugin install dev-workflows@dev-workflows
```
Differences between agents:
| Runtime | Installation result | Gate behavior |
|---|---|---|
| Claude Code | Plugin with seven agents, skills, and Claude hooks | `Stop` hook blocks an unverified completion. |
| OpenCode | Plugin and deny-by-default subagents | Its end-of-turn hook warns; the external goal loop enforces the gate itself. |
| OMP | Linked native plugin with seven agents and skills | No copied Claude hooks; the external goal loop enforces the gate. |
| Hermes Agent | Skills only | Run the gate manually; there is no Hermes goal-loop executor. |
- **opencode** cannot block the end of a turn, so a missing or failing gate is logged instead of blocking. Agents are converted to opencode subagents with the same permissions.
- **Hermes** gets the skills only; run the gate yourself.
- For opencode and Hermes the copies point at your checkout, so keep it in place (or re-run the install after moving it).
OpenCode and Hermes copies refer to this checkout; keep it in place or reinstall after moving it. The generated OMP package is self-contained. See the [skill inventory](docs/SKILLS.md) for vendored sources and optional external skills.
Turn the `Stop` hook off for one session with `DW_GATE=off`.
## Daily workflow
## External skills (optional)
The `dev-router` skill selects a tier and `lean-code` favors reuse, deletion, and the smallest justified change. Higher-risk work raises the tier; authentication, money, personal data, uploads, raw SQL, shell execution, schema migrations, new dependencies, and LLM integrations are explicit triggers.
Workflows use these when installed and fall back to their own rules when not. Install commands:
[`docs/SKILLS.md`](docs/SKILLS.md).
| Tier | Typical change | Minimum workflow |
|---|---|---|
| **0 — trivial** | No behavior change | Make the change; run the tier-0 gate. |
| **1 — small** | Localized behavior change, no new public surface | Reproduce or characterize behavior, test the change, run tier 1. |
| **2 — feature** | New endpoint/screen, contract change, or cross-file feature | Plan briefly, test, review independently, run tier 2. |
| **3 — high risk** | Architecture, existing data, migration, or release | Approve a spec/ADR, review and audit, run tier 3. |
| Area | Skills |
|---|---|
| Frontend | `frontend-design` (Anthropic), `impeccable` (pbakaus), `vercel-react-best-practices`, `vercel-composition-patterns` (Vercel Labs), `animate` (emilkowalski), `web-design`, `avoid-ai-writing` |
| Backend | `secure-coding`, `bola-detector`, `auth-rbac-scaffold`, `injection-checker`, `openapi-hardener`, `security-test-generator` (apisec-inc) |
| Architecture | `system-design`, `c4-architecture`, `isaqb-architecture-governance`, `secure-architecture-governance` (Kotivskyi) |
| README | `readme-crafter`, `good-readme`, `curating-readme` |
The [quality gate](scripts/quality-gate) runs ordinary project tools against the current diff, including the checks required for the chosen tier. **`pass` is evidence; missing tools are `incomplete`, not silently green.** Project-specific commands and checks live in `.dev-workflows.toml`; see the [gate reference](skills/dev-router/references/quality-gate.md). Claude's `Stop`, `PreToolUse`, and `PostToolUse` hooks preserve gate, dangerous-command, and formatting behavior. `DW_GATE=off` disables Claude's `Stop` hook for one session; it does **not** override the external goal loop's gate.
## Quality of this repository
Optional frontend, backend, architecture, security, and documentation skills are listed with their origins and installation instructions in [docs/SKILLS.md](docs/SKILLS.md). Workflows can operate without those external skills.
## Optional goal-driven loop
The loop is an **external controller**, not an agent promise to keep trying. It runs only on a clean Git checkout, measures a baseline, and commits each candidate inside a detached attempt worktree. The gate and evaluator run in separate fresh worktrees made from that exact candidate commit, so agent-created ignored files cannot inflate the accepted score. It stops at the target or an explicit iteration, time, stagnation, or authorization limit. Your original branch is not merged, reset, or published.
### 1. Prepare the project
You need Python 3.11+, Git, Linux `bubblewrap`, the selected agent CLI and its account, the project's gate tools, and an evaluator maintained **outside** the editable checkout. The evaluator must write JSON to stdout with `schema_version: 1`, the configured metric/value/unit/direction, passing `checks`, and evidence files under `DW_REPORT_DIR`. Its approved SHA-256 is checked before execution. See the [evaluator contract](docs/goal-loop-model-routing-spec.md#4-contratos-de-dados-e-interface-proposta).
Keep your project's existing gate `[commands]` and add the following to its `.dev-workflows.toml`. This example uses an explicitly chosen, **unranked** Claude subscription alias; it does not invent an Artificial Analysis score or a per-token subscription price.
```toml
[loop]
enabled = false # set true only when you authorize a run
harness = "claude"
tier = 1 # localized change; raise the tier for larger/riskier work
max_iterations = 3
max_minutes = 30
max_stagnant = 2
min_improvement = 1
max_paid_usd = 0
[loop.goal]
name = "app_quality"
unit = "points"
direction = "maximize"
target = 80
[loop.evaluator]
argv = ["python3", "/absolute/outside/checkout/evaluate.py"]
trusted_sha256 = "<paste the evaluator's 64-character SHA-256>"
required_checks = ["test", "lint"]
[models.roles.implementer]
model_key = "sonnet"
billing_mode = "claude_subscription"
manual_unranked_approval = true
```
Replace the path, digest, goal, and limits with values you have reviewed. Confirm the digest with `sha256sum /absolute/outside/checkout/evaluate.py`; required checks must be configured and available in the app. A higher tier can require additional agent roles and gate tools. **The example is not ready to run until its placeholders are replaced and `enabled` is set deliberately.**
### 2. Plan, run, inspect
From the **app checkout** (not this repository), set `DW` to this repository's absolute path:
```bash
python3 qa/lint_skills.py # frontmatter, size limits, references, links, machine-specific paths
python3 qa/test_gate.py # quality gate and hooks on a throwaway repo
python3 qa/check_upstream.py # vendored skills behind their upstream
DW=/absolute/path/to/dev-workflows
python3 "$DW/scripts/goal_loop.py" plan --config .dev-workflows.toml
# Review the plan; then set enabled = true and commit the app config.
python3 "$DW/scripts/goal_loop.py" run --config .dev-workflows.toml
# Copy run_id from the run's JSON output into RUN_ID.
RUN_ID=your-run-id
python3 "$DW/scripts/goal_loop.py" status --config .dev-workflows.toml --run "$RUN_ID"
python3 "$DW/scripts/goal_loop.py" resume --config .dev-workflows.toml --run "$RUN_ID"
python3 "$DW/scripts/goal_loop.py" stop --config .dev-workflows.toml --run "$RUN_ID"
```
`plan` preflights the evaluator, isolation, gate, and routes without calling an agent. `run` evaluates the same goal from baseline through each attempt; a current `pass` gate and required checks must precede acceptance. `status` reports baseline, best score, target, attempts, gate and evidence. `resume` rechecks the configuration, evaluator, gate, base, and model route; a paid call with unreported usage cannot be resumed automatically. `stop` prevents subsequent attempts rather than killing an in-flight call.
State and evidence live outside the app at `$XDG_STATE_HOME/dev-workflows` (by default `~/.local/state/dev-workflows`). Inspect the winning worktree and commit before **you** decide whether to apply its diff. The controller never applies or publishes it for you.
## Model catalog and routing
Catalog commands inspect sources and local account evidence; they **do not dispatch models**:
```bash
# Run these from the dev-workflows repository.
python3 scripts/model_catalog.py sync --tool opencode --providers opencode,opencode-go
python3 scripts/model_catalog.py list --tool opencode --show-missing --format csv
python3 scripts/model_catalog.py route --tool opencode --role planner \
--providers opencode,opencode-go --explain
# For configured OMP providers, discover their local models instead:
python3 scripts/model_catalog.py sync --tool omp --providers your-provider
```
| Evidence | Source | Meaning |
|---|---|---|
| Model IDs and variants | Public [Zen](https://opencode.ai/zen/v1/models) and [Go](https://opencode.ai/zen/go/v1/models) catalogs; local tool discovery | A public listing or local login alone **does not prove** entitlement. Zen and Go are distinct billing routes. |
| Comparative prices | [OpenRouter Models API](https://openrouter.ai/api/v1/models) | USD/token, displayed in USD/1M for matched IDs; published long-context overrides affect reference costs. These are **not** Zen, Go, or Claude billing. Missing cache components are `n/d`, never zero. |
| Coding scores | Authorized, attributed [Artificial Analysis Coding Agent Index](https://artificialanalysis.ai/agents/coding-agents) v1.5 snapshot | Manual audited import only; exact scores require a matching runtime harness and model effort. Cross-harness scores require explicit proxy approval. No automatic scraping or borrowed Intelligence Index scores. |
| Eligibility and native cost | Your audited account evidence, native tariffs, balances, and Go quotas | Required for paid/eligible routing; missing or stale evidence blocks automatic selection. |
Fixed coding-score bands are **light `[10,20)`**, **medium `[20,50)`**, and **high `[50,100]`**. The router filters by tool, provider, account, evidence, role, and budget, then compares real native cost inside the best-score plateau; OpenRouter prices remain reference only. An empty band stays empty rather than acquiring a fabricated score. A manually fixed Claude alias is labeled `unranked`.
To supply your own authorized data, `sync` accepts `--aa-snapshot`, `--availability-snapshot`, and `--price-overrides` (including `native_tariffs`). See the [validated input contracts](docs/goal-loop-model-routing-spec.md#4-contratos-de-dados-e-interface-proposta). A paid `route` also needs a task token profile (`--tokens`), explicit providers, and an appropriate `--budget-usd`; routing alone never makes a paid call.
### Reproducible public snapshot
The [captured CSV](docs/model-catalog-zen-go-2026-09-25.csv) contains **122 public models** from 2026-09-25 07:18:38 UTC: 80 Zen, 42 Go, eight curated OpenRouter price matches, **0/122 licensed AA scores imported**, and no locally confirmed account eligibility. It is a catalog, **not** a recommendation or invoice. Reproduce its exact bytes offline from the [archived normalized JSON snapshot](docs/model-catalog-snapshot-2026-09-25/catalog-opencode.json):
```bash
python3 scripts/model_catalog.py list --tool opencode --show-missing --format csv \
--cache-dir docs/model-catalog-snapshot-2026-09-25 \
--as-of-utc 2026-09-25T07:18:38Z
```
The CSV output SHA-256 is `80e2930877b20e5c47d4fd18f394c17a4683b257ca715496e91c63520d528230`; the archived JSON SHA-256 is `a5a1ec44587976a9fe96399bb275662ccdf90e1d8149ac7857f03ae05bb83dcc`. A new `sync` obtains **current** catalogs and may yield different rows or prices. With no authorized benchmark or confirmed account evidence, `route` reports no eligible scored model rather than pretending one is available.
## Safety and limitations
- **No implicit spending.** Zen and pay-as-you-go routes require an explicit task budget; dispatch needs recent audited balance and native prices, a nonzero cap, a task estimate, and interactive authorization before each call. Go checks the three per-model quota windows (5h, weekly, monthly) and does not silently fall back to paid Zen balance. Unknown real usage pauses the loop and blocks automatic resume; an estimate is **not a hard billing limit**. Claude subscriptions are not converted into fictional USD/token costs.
- **Isolation has boundaries.** The evaluator and quality gate run under Linux `bubblewrap` without network access. The agent CLI can edit its isolated worktree but its `.git` pointer is mounted read-only and rechecked before Git writes; it retains network access for providers and can read host files. This is **not** provider-only egress isolation. Add stronger isolation before using sensitive code or data.
- **Evidence beats agent output.** Missing tools, failed or stale gates, invalid evaluator results, changed protected files, and unavailable models do not count as success. No install, merge, publish, destructive Git operation, or cleanup of winning worktrees is performed by the loop.
- **No measured quality uplift claim.** The CLI was exercised on a disposable app with a fake Claude CLI and fake scanner: the app score moved from **0 to 2 in two gate-approved iterations**, without paid inference or a real account entitlement check. Whether the kit improves agent-produced code across projects still needs an A/B benchmark; public [SkillsBench](https://arxiv.org/abs/2602.12670) and [SWE-Skills-Bench](https://arxiv.org/abs/2603.15401) results show skills are not automatically beneficial.
## Verify this repository
```bash
python3 qa/lint_skills.py
python3 qa/test_gate.py
python3 -m unittest discover -s qa -p 'test_*.py' -q
claude plugin validate --strict .claude-plugin/plugin.json
```
CI runs the first two on every PR; the upstream check runs monthly.
CI runs skill lint, gate/hook tests, and the behavioral suite on every PR. `python3 qa/check_upstream.py` checks vendored skills against upstream separately each month. See the [changelog](CHANGELOG.md) and the [full goal-loop specification](docs/goal-loop-model-routing-spec.md) for contracts, requirements, and limitations.
**Not measured yet:** whether the kit improves the code an agent produces. Public studies
([SkillsBench](https://arxiv.org/abs/2602.12670), [SWE-Skills-Bench](https://arxiv.org/abs/2603.15401))
show skills can also make results worse, so the next step is an A/B benchmark (with vs. without the
kit) on [Harbor](https://github.com/harbor-framework/harbor) with hidden tests, mutation score and
security checks.
## Repository map
## Layout
```
.claude-plugin/ plugin.json, marketplace.json
skills/ dev-router, lean-code, wf-* workflows, vendored skills (NOTICE.md)
agents/ explorer, planner, implementer, reviewer, security-auditor, ui-critic, verifier
hooks/hooks.json Stop, PreToolUse, PostToolUse
scripts/ quality-gate, install.py, hooks/*.py
adapters/opencode/ opencode plugin
qa/ lint, gate tests, upstream check
docs/SKILLS.md skill inventory and install commands
```
| Path | Purpose |
|---|---|
| `skills/`, `agents/`, `hooks/` | Canonical workflows, least-privilege agents, Claude hooks |
| `scripts/quality-gate`, `scripts/install.py` | Deterministic verification and installation |
| `scripts/model_catalog.py`, `scripts/model_router.py` | Provenance-aware inventory and per-role selection |
| `scripts/goal_loop.py`, `scripts/harness_runner.py` | External controller and runtime invocation |
| `adapters/opencode/`, `adapters/omp/` | Native integration packages |
| `qa/`, `docs/` | Behavioral tests, source inventory, specification, captured data |
## License
[MIT](LICENSE) © 2026 [Evandro Fonseca Junior](https://github.com/evandrodevbr). Vendored skills keep their own licenses ([`skills/NOTICE.md`](skills/NOTICE.md)).
[MIT](LICENSE) © 2026 [Evandro Fonseca Junior](https://github.com/evandrodevbr). Vendored skills retain their own licenses; see [`skills/NOTICE.md`](skills/NOTICE.md).
+73 -8
View File
@@ -2,7 +2,7 @@
# Dev Workflows
**Plugin do Claude Code (também para opencode e Hermes Agent) que ajusta o processo ao tamanho do pedido**: um roteador escolhe o nível, agentes com permissão mínima fazem o trabalho e um gate de qualidade determinístico decide quando terminou.
**Plugin do Claude Code (também para OpenCode e OMP; Hermes recebe só skills) que ajusta o processo ao tamanho do pedido**: um roteador escolhe o nível, agentes com permissão mínima fazem o trabalho e um gate de qualidade determinístico decide quando terminou.
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
[![Agent Skills](https://img.shields.io/badge/Agent%20Skills-1.0-8A2BE2)](https://agentskills.io)
@@ -62,6 +62,7 @@ git clone https://github.com/evandrodevbr/dev-workflows && cd dev-workflows
python3 scripts/install.py claude # plugin: skills + agentes + hooks
python3 scripts/install.py opencode # skills, agentes e plugin em ~/.config/opencode
python3 scripts/install.py hermes # só skills, em ~/.hermes/skills
python3 scripts/install.py omp # pacote nativo OMP: skills + agentes (sem hooks Claude)
```
Claude Code sem clonar:
@@ -73,9 +74,10 @@ Claude Code sem clonar:
Diferenças entre os agentes:
- **opencode** não consegue bloquear o fim do turno, então gate ausente ou falho vira aviso no log em vez de bloqueio. Os agentes viram subagentes do opencode com as mesmas permissões.
- **Hermes** recebe só as skills; rode o gate você mesmo.
- No opencode e no Hermes as cópias apontam para o seu clone: mantenha-o no lugar (ou rode a instalação de novo depois de mover).
- **OpenCode** não consegue bloquear o fim do turno, então gate ausente ou falho vira aviso no log. Seus subagentes têm ferramentas negadas por padrão; o controlador externo verifica o gate por conta própria.
- **OMP** usa plugin nativo com skills e sete agentes, sem hooks Claude. O controlador externo impõe o gate.
- **Hermes** recebe só as skills; rode o gate você mesmo. Não existe executor Hermes para o loop.
- No OpenCode e no Hermes as cópias apontam para o seu clone: mantenha-o no lugar (ou reinstale depois de mover). O pacote OMP é construído independentemente do clone.
Desligue o hook de `Stop` numa sessão com `DW_GATE=off`.
@@ -96,11 +98,12 @@ instalação: [`docs/SKILLS.md`](docs/SKILLS.md).
```bash
python3 qa/lint_skills.py # frontmatter, limites de tamanho, referências, links, caminhos de máquina
python3 qa/test_gate.py # gate e hooks num repositório descartável
python3 -m unittest discover -s qa -p 'test_*.py' -q # catálogo, roteador, adapters, loop
python3 qa/check_upstream.py # skills vendorizadas atrás do upstream
claude plugin validate --strict .claude-plugin/plugin.json
```
O CI roda os dois primeiros em todo PR; a checagem de upstream roda todo mês.
O CI roda lint, testes do gate/hooks e a suíte comportamental em todo PR; a checagem de upstream roda todo mês.
**Ainda não medido:** se o kit melhora o código que um agente produz. Estudos públicos
([SkillsBench](https://arxiv.org/abs/2602.12670), [SWE-Skills-Bench](https://arxiv.org/abs/2603.15401))
@@ -108,6 +111,67 @@ mostram que skills também podem piorar o resultado, então o próximo passo é
sem o kit) no [Harbor](https://github.com/harbor-framework/harbor), com testes ocultos, score de
mutação e checagens de segurança.
## Catálogo de modelos e loop de meta opt-in
A [spec de roteamento e loop](docs/goal-loop-model-routing-spec.md) está implementada em CLIs independentes; instalar um plugin **nunca inicia o loop**. Requisitos: Python 3.11+, Git, `bubblewrap` no Linux, CLI de agente suportada configurada, avaliador externo aprovado, checkout limpo e ferramentas do gate do projeto. Não rode em projetos sensíveis sem isolamento adicional: a CLI do agente pode acessar a rede e ler arquivos do host; **não** há sandbox de rede restrita só ao provider. Avaliador e gate rodam sem acesso à rede.
Para inspecionar modelos sem chamar nenhum deles (neste repositório):
```bash
python3 scripts/model_catalog.py sync --tool opencode --providers opencode,opencode-go
python3 scripts/model_catalog.py list --tool opencode --show-missing --format csv
python3 scripts/model_catalog.py route --tool opencode --role planner --providers opencode,opencode-go --explain
```
`sync` consulta fontes públicas [Zen](https://opencode.ai/zen/v1/models), [Go](https://opencode.ai/zen/go/v1/models), [OpenRouter](https://openrouter.ai/api/v1/models) e `opencode models <provider> --refresh` local; para OMP, passe `--tool omp --providers <provider-configurado>` para descobrir modelos locais. Lista, login armazenado ou tarifa OpenRouter **não comprovam** acesso da conta, cota Go, saldo Zen ou cobrança real. Rota pontuada elegível exige seus próprios `--availability-snapshot` e `--aa-snapshot` auditados; para cobranças/cotas nativas, `--price-overrides` com `native_tariffs`. Veja os [contratos](docs/goal-loop-model-routing-spec.md#4-contratos-de-dados-e-interface-proposta) e validadores de `scripts/model_catalog.py`. O Coding Agent Index v1.5 da AA é importado manualmente, com autorização e atribuição: sem scraping da leaderboard ou notas inventadas. Faixas fixas de nota de código: `[10,20)`, `[20,50)`, `[50,100]`; modelos inacessíveis ou sem nota não vencem uma rota pontuada. Preços OpenRouter em USD/1M são **comparativos**, não cobrança Zen/Go/Claude; cache ausente é `n/d`, não gratuito.
Uma nota `exact` exige o mesmo harness e esforço de execução; outro harness só entra como `proxy` autorizado. No OMP, apenas esforços `thinking` anunciados pelo modelo local são elegíveis, inclusive IDs de modelo com `/`. Overrides públicos de contexto longo do OpenRouter entram no custo **referencial** do perfil de tokens.
A [tabela CSV completa capturada](docs/model-catalog-zen-go-2026-09-25.csv) inclui **122 modelos públicos** (Zen 80, Go 42) em 2026-09-25 07:18:38 UTC: **0/122 notas AA licenciadas importadas**, oito pareamentos de preço OpenRouter curados e nenhum acesso de conta confirmado localmente nesta captura. Reproduza **exatamente estes bytes, sem rede**, usando o [snapshot normalizado arquivado](docs/model-catalog-snapshot-2026-09-25/catalog-opencode.json) com `python3 scripts/model_catalog.py list --tool opencode --show-missing --format csv --cache-dir docs/model-catalog-snapshot-2026-09-25 --as-of-utc 2026-09-25T07:18:38Z`; o SHA-256 da saída é `80e2930877b20e5c47d4fd18f394c17a4683b257ca715496e91c63520d528230`. Sem `--as-of-utc`, o relatório de obsolescência usa o horário atual. Rode `sync` e `list --format csv` para catálogos/preços *atuais*. Dados públicos não são fatura nem garantia de acesso.
No `.dev-workflows.toml` **do aplicativo**, preserve seus `[commands]` do gate e defina um avaliador independente mantido fora do checkout. O stdout deve ser JSON com `schema_version: 1`, métrica/valor/unidade/direção configuradas, `checks` aprovados e evidências geradas sob `DW_REPORT_DIR` (veja o [contrato do avaliador](docs/goal-loop-model-routing-spec.md#4-contratos-de-dados-e-interface-proposta)). Exemplo com assinatura Claude e alias fixo, deliberadamente **sem ranking**:
```toml
[loop]
enabled = false # mude para true apenas quando decidir executar
harness = "claude"
tier = 1 # mudança de comportamento pequena; aumente para tarefas de risco
max_iterations = 3
max_minutes = 15
max_stagnant = 2
min_improvement = 1
max_paid_usd = 0
[loop.goal]
name = "app_quality"
unit = "points"
direction = "maximize"
target = 80
[loop.evaluator]
argv = ["python3", "/caminho/absoluto/fora/do/checkout/evaluate.py"]
trusted_sha256 = "<cole os 64 caracteres do SHA-256 do avaliador>"
required_checks = ["test", "lint"]
[models.roles.implementer]
model_key = "sonnet"
billing_mode = "claude_subscription"
manual_unranked_approval = true
```
Aprove o arquivo/hash do avaliador (`sha256sum /caminho/absoluto/fora/do/checkout/evaluate.py`), defina meta mensurável e comandos do gate. Depois, **num checkout limpo do app** (troque `DW` pelo caminho absoluto deste repositório):
```bash
DW=/caminho/absoluto/para/dev-workflows
python3 "$DW/scripts/goal_loop.py" plan --config .dev-workflows.toml
# Mude enabled = true no app, faça commit dessa escolha deliberada e então:
python3 "$DW/scripts/goal_loop.py" run --config .dev-workflows.toml
python3 "$DW/scripts/goal_loop.py" status --config .dev-workflows.toml --run <run-id>
python3 "$DW/scripts/goal_loop.py" resume --config .dev-workflows.toml --run <run-id>
python3 "$DW/scripts/goal_loop.py" stop --config .dev-workflows.toml --run <run-id>
```
`plan` não chama agentes; `run` mede o score inicial do app e tenta mudanças em worktrees separados. Cada tentativa cria um commit candidato detached; o gate e o avaliador executam em cópias limpas e separadas desse commit, sem arquivos ignorados criados pelo agente. Só aceita melhora após gate `pass` atual, checks obrigatórios e avaliação independente. Não faz merge, publicação ou exclusão da sua branch/worktrees; inspecione `status` e o worktree/commit vencedor antes de decidir aplicar. Estado/evidências ficam em `$XDG_STATE_HOME/dev-workflows` (padrão `~/.local/state/dev-workflows`). `resume` revalida configuração/avaliador/gate/base/rota; `stop` solicita parar novas tentativas, sem interromper imediatamente uma chamada em andamento. Zen/pay-as-you-go requer auditoria recente de conta/saldo, estimativa nativa, orçamento explícito e positivo **e** autorização interativa antes de cada chamada; consumo real desconhecido pausa o loop e impede retomada automática, pois estimativas não são limite rígido de cobrança. Go exige cotas recentes por modelo para 5h/semana/mês, sem fallback para saldo Zen. Assinatura Claude **não** recebe custo fictício USD/token nem nota AA emprestada do alias.
## Estrutura
```
@@ -115,9 +179,10 @@ mutação e checagens de segurança.
skills/ dev-router, lean-code, workflows wf-*, skills vendorizadas (NOTICE.md)
agents/ explorer, planner, implementer, reviewer, security-auditor, ui-critic, verifier
hooks/hooks.json Stop, PreToolUse, PostToolUse
scripts/ quality-gate, install.py, hooks/*.py
adapters/opencode/ plugin do opencode
qa/ lint, testes do gate, checagem de upstream
scripts/ quality-gate, instalação, catálogo/roteador, loop, executores e hooks
adapters/opencode/ plugin do OpenCode
adapters/omp/ construtor do pacote nativo OMP
qa/ lint, testes do gate e de integração, checagem de upstream
docs/SKILLS.md inventário de skills e comandos de instalação
```
+168
View File
@@ -0,0 +1,168 @@
"""Build the native OMP package from the canonical dev-workflows checkout."""
from __future__ import annotations
import hashlib
import json
import os
import re
import shutil
import tempfile
from pathlib import Path
OWNER_MARKER = ".dev-workflows-omp-package"
def _owner_value(src: Path) -> str:
return f"dev-workflows\nsource_root={src}\n"
def _content_digest(package: Path) -> str:
h = hashlib.sha256()
for path in sorted(package.rglob("*")):
if path.is_symlink():
raise FileExistsError(f"symlink em pacote gerado: {path}")
if not path.is_file() or path.name == OWNER_MARKER:
continue
h.update(path.relative_to(package).as_posix().encode("utf-8"))
h.update(b"\0")
h.update(str(path.stat().st_mode & 0o777).encode("ascii"))
with path.open("rb") as src:
for chunk in iter(lambda: src.read(1024 * 1024), b""):
h.update(chunk)
return h.hexdigest()
AGENT_NAMES = (
"explorer", "implementer", "planner", "reviewer",
"security-auditor", "ui-critic", "verifier",
)
MODEL_ID = re.compile(r"^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+(?::(?:none|minimal|low|medium|high|xhigh|max))?$")
TOOL_NAMES = {
"Read": "read", "Edit": "edit", "Write": "write", "Bash": "bash",
"Grep": "grep", "Glob": "glob", "WebFetch": "web_search",
}
def _agent(src: Path, name: str, models: dict[str, str], package_root: Path) -> str:
text = (src / "agents" / f"{name}.md").read_text(encoding="utf-8")
match = re.match(r"\A---\s*\n(.*?)\n---\s*\n(.*)\Z", text, re.S)
if not match:
raise ValueError(f"frontmatter inválido em agents/{name}.md")
raw, prompt = match.groups()
meta: dict[str, str] = {}
for line in raw.splitlines():
key, sep, value = line.partition(":")
if sep:
meta[key.strip()] = value.strip()
if meta.get("name") != name or not meta.get("description"):
raise ValueError(f"metadados incompletos em agents/{name}.md")
source_tools = [item.strip() for item in meta.get("tools", "").split(",") if item.strip()]
# An explicit OMP allowlist prevents read-only agents from inheriting write tools.
tools = list(dict.fromkeys(TOOL_NAMES[item] for item in source_tools if item in TOOL_NAMES))
if not tools:
raise ValueError(f"nenhuma ferramenta OMP reconhecida em agents/{name}.md")
lines = ["---", f"name: {name}", f"description: {meta['description']}", "tools: " + ", ".join(tools)]
skills = re.search(r"^skills:\s*\[(.*?)\]\s*$", raw, re.M)
if skills:
values = [value.strip().strip("'\"") for value in skills.group(1).split(",") if value.strip()]
if values:
lines.append("autoloadSkills:")
lines.extend(f" - {value}" for value in values)
model = models.get(name)
if model is not None:
if not isinstance(model, str) or not MODEL_ID.fullmatch(model):
raise ValueError(f"ID de modelo inválido para {name}: {model!r}")
lines.append(f"model: {model}")
body = prompt.replace("${CLAUDE_PLUGIN_ROOT}", str(package_root))
return "\n".join(lines + ["---", "", body])
def build_package(src_root, dest, models=None):
"""Atomically build an owned OMP plugin package at *dest*.
``models`` maps canonical agent names (roles) to verified concrete
``provider/model[:thinking]`` selectors. Missing roles intentionally omit
``model`` so OMP inherits the parent model.
"""
src = Path(src_root).resolve()
target = Path(dest).expanduser().absolute()
roles = {} if models is None else dict(models)
unknown = set(roles) - set(AGENT_NAMES)
if unknown:
raise ValueError("papéis desconhecidos: " + ", ".join(sorted(unknown)))
if not (src / "agents").is_dir() or not (src / "skills").is_dir():
raise ValueError(f"checkout canônico inválido: {src}")
if target.is_symlink():
raise FileExistsError(f"destino é symlink; recusando substituir: {target}")
if target.exists():
marker = target / OWNER_MARKER
if not target.is_dir() or not marker.is_file():
raise FileExistsError(f"destino existente não pertence a dev-workflows: {target}")
if marker.read_text(encoding="utf-8") != _owner_value(src) + f"sha256={_content_digest(target)}\n":
raise FileExistsError(f"pacote existente tem alterações manuais ou origem diferente: {target}")
target.parent.mkdir(parents=True, exist_ok=True)
stage = Path(tempfile.mkdtemp(prefix=f".{target.name}.stage-", dir=target.parent))
backup = None
try:
skills_src = src / "skills"
skills_dest = stage / "skills"
shutil.copytree(skills_src, skills_dest, symlinks=False,
ignore=shutil.ignore_patterns(".git", "__pycache__", "*.pyc"))
skill_count = sum(1 for path in skills_dest.glob("*/SKILL.md") if path.is_file())
for path in skills_dest.rglob("*"):
if not path.is_file():
continue
try:
content = path.read_text(encoding="utf-8")
except UnicodeError:
continue
if "${CLAUDE_PLUGIN_ROOT}" in content:
path.write_text(content.replace("${CLAUDE_PLUGIN_ROOT}", str(target)), encoding="utf-8")
if skill_count != 21:
raise ValueError(f"esperadas 21 skills canônicas; encontradas {skill_count}")
agents_dest = stage / "agents"
agents_dest.mkdir()
for name in AGENT_NAMES:
if not (src / "agents" / f"{name}.md").is_file():
raise ValueError(f"agente canônico ausente: {name}")
(agents_dest / f"{name}.md").write_text(_agent(src, name, roles, target), encoding="utf-8")
# The quality-gate executable is a package asset; Claude hooks are deliberately
# excluded. The loop/controller remains responsible for enforcing its verdict.
gate = src / "scripts" / "quality-gate"
if gate.is_file():
(stage / "scripts").mkdir()
shutil.copy2(gate, stage / "scripts" / "quality-gate")
manifest = {
"name": "dev-workflows",
"version": "1.0.0",
"description": "Skills e agentes nativos para oh-my-pi; gate imposto pelo controlador externo.",
"omp": {"extensions": []},
}
(stage / "package.json").write_text(json.dumps(manifest, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
(stage / OWNER_MARKER).write_text(_owner_value(src) + f"sha256={_content_digest(stage)}\n", encoding="utf-8")
if target.exists():
backup = Path(tempfile.mkdtemp(prefix=f".{target.name}.backup-", dir=target.parent))
backup.rmdir()
os.replace(target, backup)
try:
os.replace(stage, target)
except BaseException:
if backup is not None:
os.replace(backup, target)
backup = None
raise
if backup is not None:
shutil.rmtree(backup)
backup = None
return target
finally:
if stage.exists():
shutil.rmtree(stage)
if backup is not None and backup.exists():
if not target.exists():
os.replace(backup, target)
else:
shutil.rmtree(backup)
+4 -2
View File
@@ -1,7 +1,9 @@
# Skills: inventário e origem
Cada skill é um diretório `skills/<nome>/SKILL.md`. O plugin carrega todas; `scripts/install.py`
copia para o opencode ou o Hermes.
Cada skill é um diretório `skills/<nome>/SKILL.md`. O plugin Claude carrega todas;
`scripts/install.py` instala skills e agentes em OpenCode ou OMP e apenas skills no Hermes.
O adapter OMP gera um pacote nativo independente em `~/.omp/plugins/dev-workflows`,
registra os sete agentes do repositório e não reutiliza os hooks Claude.
## Do próprio repositório
+246
View File
@@ -0,0 +1,246 @@
# Spec: loop de melhoria por meta e roteamento de modelos por ferramenta
**Estado:** implementada como CLIs opt-in; ranking e despacho pagos dependem de evidência válida da conta, benchmark autorizado e autorização pontual. Nesta captura não há notas AA importadas nem elegibilidade de conta confirmada.
**Consulta de fontes:** 2026-09-25 (UTC). **Escopo:** `dev-workflows` como kit multi-ferramenta, não somente OMP.
**Decisões já recebidas:** faixas de qualidade por **notas fixas**, Claude Code usado por **assinatura**, OpenRouter como fonte dos preços unitários de **referência** para cruzar os modelos do OpenCode.
## 1. Problema e resultado esperado
Na base anterior, `skills/dev-router/SKILL.md` dimensionava tarefas em níveis 0–3; `agents/*.md` fixavam Haiku/Sonnet/Opus; `scripts/quality-gate` escrevia `.dev-workflows/gate.json`; o hook Claude bloqueava o encerramento sem gate atual, enquanto o adapter OpenCode apenas avisava. Agora catálogo, roteador e controlador externo acrescentam avaliação de meta sem substituir esses mecanismos; `scripts/install.py` inclui OMP nativo, mantendo Hermes apenas com skills.
Entregar duas capacidades independentes e combináveis:
1. **Roteador:** listar os modelos realmente utilizáveis por ferramenta/conta, cruzar preços OpenRouter e evidência de benchmark de programação, mostrar ranking e escolher um modelo por função dentro de uma faixa de nota e de um orçamento explícitos.
2. **Controlador externo de experimentos:** medir um objetivo do **aplicativo** com avaliador independente, executar mudanças limitadas em worktrees isolados, aplicar o quality gate, aceitar apenas melhorias válidas e repetir até atingir o alvo ou um limite. Instalar skills/agentes não liga esse controlador automaticamente.
**Duas escalas diferentes:** `coding_score` (Artificial Analysis, seleção do agente/modelo, 0–100) não é `app_score` (avaliador específico do projeto, com unidade/direção/alvo configuráveis). Não usar um como prova do outro.
### Fora de escopo
Assinar serviços, criar chaves, alterar a cobrança Zen/Go, prometer preços iguais entre gateways, extrair dados protegidos da Artificial Analysis, publicar resultados/código, remover worktrees com mudanças, alterar testes protegidos, reimplementar o quality gate, ou rodar o loop em projetos sem objetivo verificável. Não adotar um framework Ralph como dependência obrigatória: aproveitar o padrão de contexto fresco e verificação externa com o Python já usado pelo projeto.
## 2. Fontes e interpretação
| Informação | Autoridade / campo | Regra |
|---|---|---|
| Catálogo Zen | [Zen `/v1/models`](https://opencode.ai/zen/v1/models), [docs Zen](https://opencode.ai/docs/zen); ID de uso `opencode/<id>` | Lista pública não prova acesso da conta nem cobrança. Zen tem modelos Claude; não excluir a família por suposição. |
| Catálogo Go | [Go `/v1/models`](https://opencode.ai/zen/go/v1/models), [docs Go](https://opencode.ai/docs/go); ID `opencode-go/<id>` | Assinatura de US$10/mês; cotas **por modelo** em equivalentes USD: 20% do limite mensal a cada 5h, 50% semanal, 100% mensal. A lista atual inclui GPT Luna, mas não Claude; reconsultar. |
| Acesso OpenCode local | [Modelos e providers](https://opencode.ai/docs/models), CLI `opencode models <provider> --refresh`; autenticação local/conta | Interseção com IDs exatos do provider instalado e habilitado; lista pública e credencial, isoladamente, não bastam. Erro de autorização retira candidato. |
| Preço comparativo | [OpenRouter Models API](https://openrouter.ai/docs/api/api-reference/models/get-models), `GET /api/v1/models` | `prompt`, `completion`, `input_cache_read`, `input_cache_write` são USD **por token**: multiplicar por 1.000.000 para mostrar USD/1M. Campo ausente = `n/d`, nunca zero. IDs OpenRouter não são IDs OpenCode. |
| Preço real e limites | Docs/console [Zen](https://opencode.ai/docs/zen) e [Go](https://opencode.ai/docs/go), ou plano da ferramenta usada | **Não** cobrar, estimar saldo Zen nem debitar cota Go por preço OpenRouter. Considerar overrides de contexto, janelas de pico e cache; quando indisponível, bloquear despacho automático pago. |
| Benchmark principal | [Artificial Analysis Coding Agent Index](https://artificialanalysis.ai/agents/coding-agents), [metodologia v1.5](https://artificialanalysis.ai/methodology/coding-agents-benchmarking) | Média de DeepSWE v1.1, Terminal-Bench 4.0 e SWE-Atlas-QnA; guardar agente/harness, variante, esforço, fallback, versão, data, link e score. Score do harness **não** é propriedade intrínseca de toda rota do modelo. |
| API AA | [Data API](https://artificialanalysis.ai/data-api/docs) e [API legada](https://artificialanalysis.ai/api-reference) | Endpoints autenticados de modelos expõem índices de natureza/versão distintas; a documentação consultada não oferece export público documentado do **Coding Agent Index v1.5**. `artificial_analysis_coding_index` da API legada, quando disponível, não é automaticamente o índice de agentes v1.5. Nunca trocar pelo Intelligence Index. Respeitar termos e atribuição. |
**Ingestão do benchmark:** preferir export/API oficial **documentado e autorizado** para o índice de agentes; até existir, aceitar snapshot auditado/importado manualmente da página pública com a atribuição e evidência por linha, observando seus termos. Sem scraping automático de interface privada, sem inventar pontuações para preencher lacunas. Qualquer outro benchmark entra com `metric_id` diferente e ranking separado; não juntar scores entre índices, versões ou harnesses sem justificativa experimental.
### Amostra auditável de cruzamento (não é ranking completo nem tabela de cobranças)
Valores observados em 2026-09-25: preço **OpenRouter** em USD/1M tokens (entrada / saída / leitura de cache / escrita de cache); nota do **Coding Agent Index v1.5**, com harness e variante indicados. A presença nos catálogos públicos não afirma elegibilidade de nenhuma conta.
| Modelo e IDs de exemplo | Preço OpenRouter | Nota AA da variante avaliada | Observação |
|---|---|---|---|
| GLM 5.3: `z-ai/glm-5.3`; `opencode/glm-5.3`; `opencode-go/glm-5.3` | 1,40 / 4,40 / 0,26 / n/d | 54, OpenCode (max) | Go publica cota mensal de US$15 para este modelo; benchmark no OpenCode não prova equivalência do backend de todas as rotas. |
| GPT-6 Luna: `openai/gpt-6-luna`; `opencode/gpt-6-luna`; `opencode-go/gpt-6-luna` | 0,10 / 0,50 / 0,01 / 0,125 | 41, Codex (max) | Faixa **média pela nota**, apesar do preço baixo; Go publica cota mensal de US$15. OpenRouter aplica preços diferentes acima de 272k tokens. |
| GPT-6 Sol: `openai/gpt-6-sol`; `opencode/gpt-6-sol` | 2,00 / 10,00 / 0,20 / 2,50 | 57, Codex (max) | Pontuação em outro harness; preço muda acima de 272k tokens. |
| Claude Opus 5.5: `anthropic/claude-opus-5.5`; `opencode/claude-opus-5-5` | 4,00 / 20,00 / 0,20 / 5,00 | 66, Claude Code (max) | Zen oferece esse ID publicamente; não presumir acesso na conta nem equiparar preço OpenRouter à assinatura Claude. |
| Kimi K3: `moonshotai/kimi-k3`; `opencode-go/kimi-k3`; `opencode/kimi-k3` | 0,8845 / 10,5346 / 0,33 / n/d | 52, Kimi Code CLI | Variante avaliada em outro harness; Go publica cota mensal de US$15. |
| Claude Sonnet/Haiku, MiMo-V2.6-Pro | IDs conforme catálogo de cada ferramenta; pareamento exige revisão | **n/d** | Não foi localizada nota dessas variantes no recorte público consultado; não atribuir nota de outra família/harness. |
Os preços acima vêm do [JSON OpenRouter](https://openrouter.ai/api/v1/models); notas da [leaderboard](https://artificialanalysis.ai/agents/coding-agents); cotas e IDs das [docs Go](https://opencode.ai/docs/go) e [Zen](https://opencode.ai/docs/zen). Cache `n/d` significa *não informado*, não gratuito. Listar também condição de preço/contexto e origem por modelo na saída gerada; dados mudam.
## 3. Política de roteamento
### 3.1 Faixas e funções
Usar **nota fixa** de 0 a 100; cortes configuráveis, defaults abaixo. Faixa não é preço nem tamanho físico do modelo:
| Faixa de qualidade | Intervalo | Uso padrão | Restrições |
|---|---|---|---|
| `leve` | `[10, 20)` | exploração/leitura em volume, coleta de dados públicos, sumarização mecânica e relatório do `verifier` | Agentes só de leitura; se nenhum candidato medido, faixa fica vazia. Nota `<10` inelegível por padrão. |
| `media` | `[20, 50)` | `implementer`, `ui-critic` nível 2 | Exigir ferramentas e contexto suficientes; escalar tarefas de alto risco para `alta`. |
| `alta` | `[50, 100]` | `planner`, `reviewer`, `security-auditor`, implementação nível 3/risco | Planejamento/revisão independentes e limites de custo. Notas `>80` continuam nesta **terceira** faixa. |
Não assumir que haverá candidato em todas as faixas: os exemplos publicados de 2026-09-25 não preenchem a faixa `leve`. Se vazia, registrar `no_scored_candidate`; propor o menor custo de outra faixa que cumpra o piso **após** orçamento/autorizações, ou usar um modelo fixado pelo usuário e rotular `unranked`; não afirmar que esta opção venceu no benchmark. `dev-router` continua a escolher nível e gatilhos de segurança; a faixa nunca reduz nível/gate nem torna revisão opcional.
### 3.2 Elegibilidade, custo e seleção
Para cada função, aplicar nesta ordem:
1. Escolher ferramenta/harness **em uso**, provider e conta de cobrança permitidos pelo usuário. Elegível só se `(provider, id, variante)` constar do catálogo local revalidado, autenticação/entitlement não negado e houver contexto, modalidade, tool calling e permissões requeridos. IDs e versões vinculados por mapa curado com proveniência; sem `fuzzy match` de nomes. `opencode/*` e `opencode-go/*` são rotas distintas. OMP pode usar esses providers se realmente configurados; Claude Code não vira multi-provider por declarar um ID Zen.
2. Para seleção **pontuada**, exigir benchmark de métrica/versão única e mapeamento de variante. `exact`: harness, modelo, esforço e caminho avaliados equivalentes; `proxy`: modelo e esforço compatíveis, mas harness/provider diferem, com risco explícito. Proxy só se a política da função autorizar; para migração/auth/segurança de nível 3, exigir `exact` ou aprovação humana da incerteza. `unranked` não entra em fronteira de qualidade nem ganha score emprestado.
3. Filtrar pelo intervalo da função e pelo custo/limite de cobrança autorizado. `score_top = max(score)` dos elegíveis da faixa; formar platô `score >= score_top - delta_points` (**pontos de nota**, não porcentagem). Defaults: `delta_points = 2` para `alta`, `3` para `media` e `leve`. No platô, escolher **menor consumo relevante para a ferramenta** no perfil de tokens da função: tarifa Zen para Zen, débito de cota Go para Go, consumo observado da assinatura para Claude quando medível. Publicar também o ranking **comparativo OpenRouter**, mas não usá-lo como custo real de outro gateway. Se o consumo relevante for desconhecido, não alegar escolha ótima: manter rota estática ou pedir seleção explícita. Desempate: nota maior, maior folga de cota, ID lexicográfico. Reportar top absoluto, economia estimada e fronteira de Pareto (nota e custo na mesma base).
4. Custo **referencial** por tarefa: `C_OR = u*P_entrada + o*P_saida + r*P_cache_leitura + w*P_cache_escrita + taxas_extras`, com `u,o,r,w` em tokens e preços da API OpenRouter **em USD por token**. Equivalentemente, se usar valores exibidos **em USD/1M**, dividir a soma dos quatro produtos por `1_000_000`. Usar `Decimal`, sem ponto flutuante para moeda. Se o perfil usa cache e seu preço não é informado, `C_OR = n/d`, sem comparar artificialmente como zero; componente com zero tokens não requer tarifa. Respeitar overrides de contexto/TTL/endpoint. Perfil de tokens vem de medições do próprio harness ou configuração explícita; previsão é **estimativa**, não fatura.
5. Zen: orçamento real conservador calculado com tarifa **Zen**, independente de `C_OR`, e saldo/limite confirmados; Go: verificar cota restante **do modelo** nas três janelas e estimar débito pela **tarifa Go**, não por `C_OR`. Quando saldo/restante não puder ser confirmado, não iniciar despacho automático com risco de cobrança; permitir execução manual fora do loop. Claude por assinatura: mostrar `C_OR` só como comparação, contar tokens/limites observáveis e parar ao atingir aviso de plano; sem consumo comparável não afirmar economia entre Opus/Sonnet/Haiku nem converter USD OpenRouter em cobrança. Nenhum fallback Go→saldo Zen sem autorização explícita separada; a opção `Use balance` da console pode cobrar automaticamente quando a cota acabar.
6. Se seleção mudar, exibir motivo (novo score, preço, disponibilidade, quota, contexto) e não trocar a ferramenta/provider/assinatura silenciosamente. Falha de autenticação, preço obsoleto, métrica ausente, índice diferente, rate-limit ou limite esgotado = `unavailable`/pausa; fallback só para rota previamente permitida que ainda cumpre requisitos e orçamento.
Na implementação, o ID de modelo OMP é opaco (pode conter `/`); apenas seu `selector` é qualificado pelo provider, e variantes `#esforço` só são elegíveis quando o `thinking` da CLI local anuncia esse esforço. `exact` exige o harness da ferramenta em execução; outra origem exige `proxy` autorizado. Rotas Zen e OMP pay-as-you-go exigem `--budget-usd` explícito antes mesmo de serem selecionadas. Overrides publicados pela API OpenRouter acima de um limiar de tokens entram apenas no preço comparativo do perfil.
**Exemplo de custo comparativo, não fatura:** perfil hipotético de 50k tokens de entrada sem cache, 150k de leitura de cache, 10k de saída e 0 de escrita dá aproximadamente US$0,0115 no OpenRouter para GPT-6 Luna e US$0,153 para GLM-5.3 nas tarifas-base observadas. A primeira tem nota 41 (`media`), a segunda 54 (`alta`); não chamar Luna de faixa `leve` por ser barata. Não usar esse perfil fictício para cobrar ou fixar o ranking final.
**Atualização:** cada snapshot contém data UTC e hash. Revalidar catálogo local por sessão, preços antes de aprovar gasto (24h no máximo), quotas antes de cada execução e score ao mudar versão do índice (recaptura pelo menos a cada 30 dias). Dados obsoletos impedem **autoescolha paga**; `models list` ainda os mostra como `stale`. Nenhum refresh automático de AA sem fonte/permissão documentada.
## 4. Contratos de dados e interface proposta
Manter a config do projeto em `.dev-workflows.toml` (já lida pelo gate), adicionando seções **sem alterar** `[commands]`, `[thresholds]`, `[spec]` e `[[check]]` existentes. `~/.config` pode conter preferências de conta, nunca chaves em arquivos do projeto. Exemplo de contrato, não arquivo configurado:
```toml
[loop]
enabled = false # somente comando explícito inicia experimento
harness = "opencode" # claude | opencode | omp; Hermes após adapter real
max_iterations = 8
max_minutes = 90
max_stagnant = 2
min_improvement = 0.5
max_paid_usd = 0 # >0 só com autorização interativa para Zen/pay-as-you-go
[loop.goal]
name = "qualidade_do_app"
direction = "maximize" # minimize também permitido
unit = "points" # unidade do produto, não do AA
baseline_required = true
target = 80.0
[loop.evaluator]
argv = ["python3", "/caminho/fora/do/worktree/evaluate.py", "--json"]
timeout_seconds = 600
trusted_sha256 = "<hash aprovado do avaliador e testes protegidos>"
required_checks = ["test", "lint"]
require_gate_verdict = "pass" # incomplete não é sucesso do loop
[models]
benchmark_metric = "aa_coding_agent_index_v1.5"
allow_proxy_score = false
max_price_age_hours = 24
max_score_age_days = 30
[models.bands]
leve = [10, 20]
media = [20, 50]
alta = [50, 100] # último limite inclusivo
[models.roles.explorer]
band = "leve"
max_loss_points = 3
[models.roles.implementer]
band = "media"
max_loss_points = 3
[models.roles.planner]
band = "alta"
max_loss_points = 2
```
**Contrato de avaliação (stdout exclusivamente JSON, erro em stderr):**
```json
{"schema_version":1,"metric":"qualidade_do_app","value":81.2,"unit":"points","direction":"maximize","checks":{"regression":"pass","security":"pass"},"evidence":["/relatorios/avaliacao.json"]}
```
Apenas o processo controlador interpreta `value`; saída ausente, NaN, métrica/unidade/direção divergente, evidência não verificável, prazo excedido, exit não zero, ou check obrigatório diferente de `pass` é **falha**, nunca score zero. Nomes de caminhos são ilustrativos; o avaliador real e seu alvo são definidos pelo projeto. Repetir baseline e candidato sob o mesmo avaliador, versão, dados e sementes. Expor variabilidade: para avaliador estocástico, fixar sementes/repetições e comparar média/intervalo conforme config do projeto, sem inferir melhoria de ruído.
**Registro de modelo:** `model_key=(provider,model_id,variant)`, `tool`, `billing_mode`, `openrouter_id`, `openrouter_canonical_slug`, `or_price_per_token={input,output,cache_read?,cache_write?,cache_write_1h?}`, `price_conditions`, `zen_or_go_native_tariff?`, `quota_window_remaining?`, `score={metric_id,version,value?,agent,harness,variant,settings,match_grade,source_url,observed_at}`, `availability={listed,authenticated,entitled,verified_at}`, `source_hash`. Tipos monetários como string decimal, `null` para desconhecido. Não gravar API keys, prompts do app ou dados privados no ranking. Não confundir variantes `max/high` do benchmark com preço base sem estimar seus tokens.
**Comandos de produto implementados:**
```text
python3 scripts/model_catalog.py sync --tool opencode --providers opencode,opencode-go
python3 scripts/model_catalog.py list --tool opencode --show-missing --format csv
python3 scripts/model_catalog.py route --tool opencode --role planner --explain
python3 scripts/goal_loop.py plan --config .dev-workflows.toml
python3 scripts/goal_loop.py run --config .dev-workflows.toml
python3 scripts/goal_loop.py status --run <id>
python3 scripts/goal_loop.py resume --run <id>
python3 scripts/goal_loop.py stop --run <id>
```
**Tabela completa gerada, não preenchida manualmente nesta spec:** uma linha por `(ferramenta, provider, ID, variante)` de **todos** os modelos publicados para Zen e Go no snapshot, inclusive os indisponíveis na conta e os sem nota. Colunas CSV/JSON: `nome`, `tool`, `provider/model#variant`, `openrouter_id`, `preco_or_entrada_usd_1m`, `preco_or_saida_usd_1m`, `preco_or_cache_leitura_usd_1m`, `preco_or_cache_escrita_usd_1m`, `condicao_de_preco`, `coding_index_versao`, `coding_index_nota`, `benchmark_por_componente_se_publicado`, `harness_aa`, `reasoning_aa`, `grau_do_match`, `faixa`, `preco_native_ou_cota`, `disponivel_na_conta`, `motivo_da_exclusao`, `fonte` e `capturado_em`. Reportar cobertura `pontuados/total` por ferramenta/faixa; ordenar ranking só entre notas comparáveis. `n/d` permanece explícito para score ou preço ausente, não omitir linhas. Export não contém credenciais nem dados do usuário.
`sync` de AA só aceita snapshot manual licenciado/verificado ou API específica oficialmente documentada; não há comando para raspar leaderboard não documentado. `plan` é sem gastos/mutações: imprime fontes, notas e `n/d`, mapeamentos, cotas, perfil de tokens, rotas por papel, baseline/evaluator e riscos. `run` exige aprovação explícita para orçamento pago, comandos com efeitos externos e mudanças de provider; nunca ativar por instalar o plugin. `status` mostra score inicial/melhor/meta, iterações, custo real/estimado separados, snapshots, gate e motivos de pausa. `stop` cancela novas tentativas e não apaga worktrees.
**Captura reproduzível da tabela:** [`model-catalog-zen-go-2026-09-25.csv`](model-catalog-zen-go-2026-09-25.csv), gerada pelos comandos `sync --tool opencode --providers opencode,opencode-go` e `list --tool opencode --show-missing --format csv` em **2026-09-25T07:18:38Z**. Contém 80 modelos Zen e 42 Go, cobertura AA 0/122 (não foi fornecido snapshot autorizado), oito pareamentos curados de preços OpenRouter e acesso local não confirmado (`opencode models --refresh` falhou para ambos); nenhum deles é automaticamente elegível. Hash do snapshot `1930d91de7992963aec39d4188f36d97a849ead60f4dc91ae66dc4b38c708cd7`; hashes dos corpos das fontes: Zen `1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4`, Go `4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4`, OpenRouter `0d552d4f08b7c600c0aa2d8f8b926e1356856fd81a6c9ad0c02c5a3f3a7eab3c`. SHA-256 do CSV `80e2930877b20e5c47d4fd18f394c17a4683b257ca715496e91c63520d528230`. Rodar `sync` novamente atualiza preços/listas e **não** reproduz necessariamente os mesmos bytes históricos; preserve o snapshot JSON local se precisar reprocessar a captura exata. Os dados públicos de [Zen](https://opencode.ai/zen/v1/models), [Go](https://opencode.ai/zen/go/v1/models) e [OpenRouter](https://openrouter.ai/api/v1/models) não são prova de acesso ou fatura.
O [snapshot normalizado arquivado](model-catalog-snapshot-2026-09-25/catalog-opencode.json) permite reproduzir a captura **offline**: `python3 scripts/model_catalog.py list --tool opencode --show-missing --format csv --cache-dir docs/model-catalog-snapshot-2026-09-25 --as-of-utc 2026-09-25T07:18:38Z` gera exatamente o CSV acima (SHA-256 comprovado na execução CLI). Sem `--as-of-utc`, a obsolescência é recalculada com o horário atual e os bytes históricos podem mudar. SHA-256 dos bytes do JSON `a5a1ec44587976a9fe96399bb275662ccdf90e1d8149ac7857f03ae05bb83dcc`; o arquivo contém os 122 registros Zen/Go normalizados e 460 entradas públicas OpenRouter, sem evidência privada de conta nem AA licenciada.
**Importação auditada pelo usuário:** `--aa-snapshot` exige `metric_id=aa_coding_agent_index`, `version=1.5`, `ingestion=manual_audited`, `terms_accepted=true` **somente após aceitar os termos**, atribuição, URL oficial HTTPS, data UTC e linhas com ID/variante, score, agente, harness, configurações, match e URL da evidência. `--availability-snapshot` exige `tool`, `ingestion=manual_audited`, `user_confirmed=true`, data UTC e linhas com ID exato, `local_listed`, `authenticated`, `entitled`, `verified_at` e origem; não inclua tokens/chaves. `--price-overrides` pode incluir `native_tariffs` indexado por `model_key`: Zen/OMP payg exige tarifa USD/token, `available_balance_usd` e confirmação de conta/saldo recente; Go exige `quota_window_remaining` e `quota_window_debit` por modelo em `5h`, `weekly`, `monthly` e `use_balance_fallback=false`. Sem evidência atual das permissões e do perfil de tokens da tarefa, o roteador permanece indisponível; o comando `route` nunca invoca modelos.
**Limite de isolamento:** o agente usa ferramentas por papel e worktree com escrita limitada; seu ponteiro `.git` é montado somente para leitura e revalidado antes de operações Git do controlador. A CLI compartilha a rede para alcançar providers e pode ler arquivos do host. O avaliador e o gate usam `bubblewrap --unshare-net`; não confundir com filtro de egress do agente nem isolamento contra código malicioso do próprio usuário. Sem cotas/saldo auditados recentes, uso real confiável e autorização interativa, qualquer caminho cobrado é bloqueado ou pausado; uma chamada paga sem consumo reportado não pode ser retomada automaticamente. Previsões não impõem teto rígido de faturamento. A prova de execução sem gasto usa uma CLI Claude fictícia e verificador fictício em repositório descartável: baseline 0 → score 2 em duas iterações com gate aprovado; não comprova cobrança/entitlement de uma conta real.
### Adaptadores e responsabilidades
- **Núcleo Python sem SDK proprietário:** descoberta, tabela/relatório, política, estado transacional do loop e leitura do `gate.json`. Processo do controlador fora da pasta editável pelo agente; metadados por execução fora do worktree e artefatos `.dev-workflows/` ignorados para Git quando gerados no projeto. Sem polling/serviço silencioso.
- **Claude Code:** usar `claude -p --model` e subagentes `agents/*.md` com aliases permitidos `haiku|sonnet|opus|inherit`; não escrever `provider/model` incompatível no frontmatter canônico. Instalação via plugin existente; preservar hooks e autorização da ferramenta. Resolver versão/modelo da conta antes de anunciar score; `model` alias não prova variante exata. Assinatura não é precificação por token.
- **OpenCode:** usar `opencode run --model provider/id#variant --agent ...` conforme versão local. `scripts/install.py` gera agentes em `~/.config/opencode/agents` e plugin de hooks; estender conversão para `model` por papel/conta com **deny-by-default** de ferramentas nos subagentes de leitura, sem herdar permissão `* allow`. Não sobrepor arquivo existente não pertencente ao pacote. O plugin OpenCode apenas avisa no fim: controlador deve bloquear por conta própria em `gate.json`.
- **OMP:** adicionar alvo `omp` ao instalador com package/adapter OMP próprio, skills/agentes nativos e papéis `modelRoles` resolvidos no runtime, sem reusar diretamente `hooks/hooks.json` do Claude. OMP descobre agentes de extensões e aceita aliases de papel `@nome` ([docs](https://github.com/can1357/oh-my-pi/blob/main/docs/task-agent-discovery.md)); se papel não estiver configurado, herdar do pai ou bloquear com diagnóstico — nunca criar ID fictício. Hooks só com port nativo e testes; sem eles, controlador externo impõe gate. Não depender do worktree local de um usuário para distribuição.
- **Hermes:** instalação atual é só de skills; não alegar suporte a subagentes ou loop até existir executor/adapter testado. Scripts de ranking/report ainda podem operar fora do Hermes.
## 5. Algoritmo do loop
```text
INICIALIZAR: validar config, meta, avaliador protegido, orçamento, permissões,
working tree do usuário e catálogo; obter baseline em sandbox isolado.
SE baseline já atinge target E checks/gate exigidos passaram: finalizar sem editar.
PARA i em 1..max_iterations, respeitando relógio/orçamento:
criar worktree descartável A PARTIR do melhor estado aceito (nunca reset no tree do usuário)
planejar UMA hipótese de melhoria com contexto fresco + feedback anterior e papel roteado
implementar mudança pequena dentro de escopo e permissões do dev-router
verificar arquivos protegidos, ponteiro Git detached e isolamento; criar commit candidato
rodar quality-gate --tier N em worktree limpo do commit; validar base, diff, tempo e checks
SE fail/incomplete obrigatório: rejeitar e registrar motivo, sem declarar sucesso
SENÃO executar avaliador independente em OUTRO worktree limpo do mesmo commit
SE score válido, não regrediu e melhorou >= min_improvement: guardar commit como melhor
SENÃO: marcar tentativa rejeitada e incrementar estagnação
persistir decisão, custo/uso, evidências e hashes atomicamente
SE melhor.score atinge target E todos os checks obrigatórios passam: parar com success
SE estagnação/limite/cancelamento: parar com estado explícito, não success
FIM: produzir patch/worktree do melhor estado; usuário decide se incorpora.
```
Estados da execução: `planned → baselined → running → success|exhausted|paused|cancelled|error`; resultados por tentativa: `accepted|rejected|paused|interrupted`. `success` só vem do avaliador **externo** atual + gate `pass` + invariantes; texto do agente, `<promise>COMPLETE</promise>`, exit zero isolado e `incomplete` nunca são conclusão. Rejeição não apaga evidência nem altera branch do usuário. `resume` confere hash do avaliador, config, snapshot de modelos, branch/base e último estado aceito; se houve edição concorrente do usuário ou atualização de dependência crítica, pausa até decisão. Uma única execução ativa por projeto, escrita atômica com lock; interrupção é retomável sem contabilizar a mesma tentativa duas vezes, salvo chamada paga de consumo indeterminado.
**Controle de riscos:** agente não pode escrever avaliador/testes ocultos, metas, snapshots de catálogo, relatório de execução ou hashes de aceitação; executar verificação em contexto separado do workspace editável, com checkout limpo dos checks/dados aprovados. Config/linhas de comando, páginas externas e saída do agente são dados não confiáveis, não autorização para instalar dependências, enviar dados, gastar saldo, publicar, executar migrations, modificar serviços de produção ou desativar gate. Para ações com efeito externo, legal, financeiro ou dados sensíveis, interromper para aprovação explícita do usuário no momento da ação. Nenhum `--dangerously-skip-permissions`, `--auto` indiscriminado ou force-push. Guardar diffs sem segredos e limitar retenção de logs.
## 6. Requisitos verificáveis (EARS)
- **REQ-001** WHEN `models sync` for chamado, THE SYSTEM SHALL identificar IDs exatos e variantes dos catálogos Zen/Go e da ferramenta local sem presumir acesso pela lista pública.
- **REQ-002** WHEN preços forem importados, THE SYSTEM SHALL preservar cada preço OpenRouter por token, cache read/write separados, condições, ID, URL, data e unidade USD/1M apresentada.
- **REQ-003** IF um preço/campo de cache estiver ausente, THEN THE SYSTEM SHALL mostrá-lo como `n/d` e impedir custo comparativo inválido para o perfil afetado.
- **REQ-004** WHEN uma nota AA for importada, THE SYSTEM SHALL preservar índice, versão, harness, agente, variante, configurações, pontuação, proveniência e data.
- **REQ-005** IF índice, variante, versão, origem ou correspondência não forem compatíveis, THEN THE SYSTEM SHALL rejeitar a comparação/roteamento pontuado, sem substituir por Intelligence Index.
- **REQ-006** WHEN `models list` for chamado, THE SYSTEM SHALL listar modelos disponíveis e indisponíveis, ID por ferramenta, faixas fixas, preço entrada/saída/cache, nota ou `n/d`, licença de cobrança e justificativa da elegibilidade.
- **REQ-007** WHEN escolher modelo por papel, THE SYSTEM SHALL filtrar requisitos, nota/intervalo e orçamento, selecionar menor custo dentro do platô de pontos do melhor da faixa e explicar escolhas/empates.
- **REQ-008** IF uma faixa estiver vazia, THEN THE SYSTEM SHALL reportar ausência, oferecer opção explícita rotulada (ou rota fixa `unranked`) e nunca fabricar uma nota para preencher a faixa.
- **REQ-009** IF provider, ID ou conta não estiverem efetivamente disponíveis, THEN THE SYSTEM SHALL não despachar o modelo, ainda que conste das docs públicas.
- **REQ-010** IF uma rota Go exceder uma janela de cota ou cair em `Use balance` sem autorização de pagamento, THEN THE SYSTEM SHALL pausar antes da chamada cobrada.
- **REQ-011** WHEN mostrar custo, THE SYSTEM SHALL distinguir `C_OR` de referência, cobrança Zen, débito de cota Go e assinatura Claude; tokens estimados não são fatura.
- **REQ-012** IF metadados pagos estiverem expirados ou indisponíveis, THEN THE SYSTEM SHALL bloquear seleção automática cobrada, mantendo relatório legível.
- **REQ-013** WHEN `plan` for chamado, THE SYSTEM SHALL validar objetivo, avaliador, isolamento, modelos, gate, riscos e orçamento **sem** executar agentes, criar branches nem gastar tokens.
- **REQ-014** IF a base do projeto tiver mudanças do usuário, THEN THE SYSTEM SHALL evitar apagá-las ou absorvê-las sem consentimento e exigir snapshot/base deliberados.
- **REQ-015** WHEN `run` for autorizado, THE SYSTEM SHALL medir baseline pelo mesmo avaliador protegido e contexto usado nas tentativas.
- **REQ-016** WHILE o loop estiver ativo, THE SYSTEM SHALL limitar tentativas por iteração, tempo, custo, estagnação e permissões; manter hipótese/contexto novo por iteração.
- **REQ-017** WHEN um agente modificar código, THE SYSTEM SHALL rodar o tier do `dev-router` e validar `gate.json` atual e checks obrigatórios antes de medir sucesso.
- **REQ-018** IF gate `fail` ou `incomplete` obrigatório, regressão, score inválido ou tampering ocorrer, THEN THE SYSTEM SHALL rejeitar a tentativa com evidência, sem alterar o melhor estado.
- **REQ-019** WHEN houver melhoria válida, THE SYSTEM SHALL promover somente o estado isolado vencedor e registrar score, dados, gate, custo e hashes que sustentam a decisão.
- **REQ-020** IF o score atingir a meta com checks válidos, THEN THE SYSTEM SHALL parar como `success` e oferecer patch/worktree, **sem** aplicar/publicar na branch do usuário.
- **REQ-021** IF limite, cancelamento ou erro ocorrer primeiro, THEN THE SYSTEM SHALL parar como `exhausted|cancelled|error` com melhor evidência e sem afirmar que atingiu a meta.
- **REQ-022** WHEN `resume` for chamado, THE SYSTEM SHALL verificar invariantes/hashes e retomar sem duplicar gastos/tentativas; mudança concorrente exige pausa.
- **REQ-023** WHILE qualquer adapter estiver ativo, THE SYSTEM SHALL preservar restrições de ferramentas/hook/gate aplicáveis e nunca promover permissões de agentes de leitura por herança.
- **REQ-024** WHEN gerar documentação ou ranking com dados AA, THE SYSTEM SHALL atribuir fonte e respeitar seus termos, mantendo métricas de índices diferentes em tabelas separadas.
## 7. Plano de implementação e prova de aceitação
| Ordem | Entrega e locais previstos | Requisitos | Prova comportamental |
|---|---|---|---|
| 1 | `scripts/model_catalog.py` + módulo pequeno de parsing em `scripts/` e fixtures em `qa/` | 001–006, 011, 012, 024 | Importar JSON oficial OpenRouter e snapshot AA consentido; testar preço com/sem cache, 1M, override 272k, desambiguação de alias e índices não misturados; `models list` real sem chave AA quando snapshot local existe. |
| 2 | `scripts/model_router.py`, contrato TOML e `qa/test_model_router.py` | 007–012 | Matriz Zen vs Go vs Claude/OMP; falta de score/faixa vazia, custo no platô, proxy, quota Go 5h/semana/mês, queda para saldo Zen negada, empate determinístico. Teste de integração com catálogo CLI local, sem despachar modelo pago. |
| 3 | `scripts/goal_loop.py`, estado isolado e `qa/test_goal_loop.py` | 013–022 | Projeto temporário com avaliador que mede qualidade real: baseline abaixo, primeira tentativa melhora, segunda atinge meta; gate atual obrigatório; regressão/`incomplete`/tampering rejeitados; retomada, limite e árvore de trabalho suja preservada. Teste executa CLI e inspeciona worktrees e relatórios, não somente mocks. |
| 4 | Converter por ferramenta em `scripts/install.py`, `adapters/opencode/`, novo `adapters/omp/`, `agents/`, `skills/dev-router/` | 001, 007, 009, 023 | Smoke de instalação e descoberta dos 7 agentes por runtime, modelos resolvidos e ferramenta de leitura sem permissão de escrita; OpenCode warning não substitui veredito do controlador; Hermes segue explicitamente skills-only. |
| 5 | README em inglês/português, `docs/SKILLS.md`, `CHANGELOG.md`, testes CI | Todos | Quickstart com `plan`/`run`/`resume`, fontes/atribuição, preços dinâmicos, caso `n/d` e gates; `qa/lint_skills.py`, `qa/test_gate.py` e novos testes verdes. |
**Critérios de pronto do produto:** um projeto descartável atinge meta numérica apenas após duas iterações comprovadas; falha de gate nunca encerra como sucesso; Zen e Go escolhem listas distintas sem cobrança cruzada; preço OpenRouter e tarifa real aparecem separados; modelos sem benchmark não entram no ranking por nota; Claude por assinatura não recebe custo fictício; estado retoma após interrupção; nenhuma branch/arquivo do usuário é destruído. Testar também um caso em que meta não é atingida antes de `max_iterations`. Roteamento sozinho não conta como entrega do loop, nem o inverso.
**Migração e reversão:** manter o comportamento atual por padrão (`[loop].enabled=false`, agentes existentes preservados); ativar explicitamente por projeto e ferramenta após diagnóstico; distribuir adapter OMP nativo sem presumir o worktree local; remover/corrigir caminhos antigos de modelo ao ativar roteamento em cada runtime. Desativar execução retornando `enabled=false` e usar papéis estáticos atuais. Não excluir relatórios/worktrees automaticamente; fornecer passos de recuperação e escolha de aplicação do patch. Spec nível 3: revisar com o usuário antes da implementação, conforme `agents/planner.md`.
## 8. Prompt original de implementação (registro histórico)
> Implemente no `dev-workflows` a spec `docs/goal-loop-model-routing-spec.md`, sem reduzir nenhum REQ-001…024. Preserve `dev-router`, quality gate e hooks atuais. Comece pelo importador de catálogo com proveniência e pelo roteador, depois integre Claude Code, OpenCode e OMP, e por fim o controlador de loop com worktrees/avaliador independente; Hermes permanece skills-only até existir adapter real. Use faixas **fixas de nota de código** `[10,20)`, `[20,50)`, `[50,100]`, não quantis relativos. Descubra apenas modelos acessíveis à conta/ferramenta. Cruze IDs curados Zen/Go/Claude/OMP com tarifas **OpenRouter** de entrada, saída, leitura e escrita de cache; marque campos faltantes `n/d` e informe os preços OpenRouter como **referência**, distintos da cobrança Zen, cota Go e assinatura Claude. Use exclusivamente um índice/versionamento de programação da Artificial Analysis por ranking; atribua fonte, guarde variante/harness e jamais converta nota do Intelligence Index em nota de código. Mostre ranking auditável por papel, escolha o modelo de menor custo dentro do platô dos melhores da faixa, bloqueie seleção cobrada sem autorização e nunca faça fallback Go→Zen cobrado sem aceite. No loop, estabeleça baseline, aceite apenas melhoria numérica com gate/checks obrigatórios aprovados e avaliador protegido, pare ao atingir alvo ou orçamento e preserve o trabalho do usuário. Entregue testes comportamentais, smoke CLI real, docs, tabela reproduzível com IDs/notas/preços `n/d` e limites honestamente reportados. Não apresente instalação de skills como se fosse o loop em funcionamento.
File diff suppressed because it is too large. Load diff
+123
View File
@@ -0,0 +1,123 @@
nome,tool,model_key,openrouter_id,preco_or_entrada_usd_1m,preco_or_saida_usd_1m,preco_or_cache_leitura_usd_1m,preco_or_cache_escrita_usd_1m,preco_or_cache_escrita_1h_usd_1m,condicao_de_preco,coding_index_versao,coding_index_nota,benchmark_por_componente_se_publicado,harness_aa,reasoning_aa,grau_do_match,faixa,preco_native_ou_cota,disponivel_na_conta,motivo_da_exclusao,fonte,capturado_em,stale,stale_reasons,availability,billing_mode,source_hash,or_price_per_token,score
deepseek-flash,opencode,opencode-go/deepseek-flash,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
deepseek-v4-flash,opencode,opencode-go/deepseek-v4-flash,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
deepseek-v4-flash-vision-exp,opencode,opencode-go/deepseek-v4-flash-vision-exp,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
deepseek-v4-pro,opencode,opencode-go/deepseek-v4-pro,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
deepseek-v4.1-flash,opencode,opencode-go/deepseek-v4.1-flash,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
glm-5,opencode,opencode-go/glm-5,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
glm-5.1,opencode,opencode-go/glm-5.1,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
glm-5.2,opencode,opencode-go/glm-5.2,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
glm-5.3,opencode,opencode-go/glm-5.3,z-ai/glm-5.3,1.4000000,4.4000000,0.26000000,n/d,n/d,"{""context_length"": 1310720, ""per_request_limits"": null, ""pricing_metadata"": {}, ""top_provider"": {""context_length"": 1048575, ""is_moderated"": false, ""max_completion_tokens"": 943717}, ""unsupported_negative_prices"": {}}",n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": ""https://openrouter.ai/api/v1/models""}",2026-09-25T07:18:38Z,False,[],"{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": ""0.00000026"", ""cache_write"": null, ""cache_write_1h"": null, ""cache_write_24h"": null, ""cache_write_5m"": null, ""input"": ""0.0000014"", ""output"": ""0.0000044""}",n/d
glm-5.3-flash,opencode,opencode-go/glm-5.3-flash,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
gpt-5.6-luna,opencode,opencode-go/gpt-5.6-luna,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
gpt-6-luna,opencode,opencode-go/gpt-6-luna,openai/gpt-6-luna,0.1000000,0.5000000,0.01000000,0.125000000,n/d,"{""context_length"": 1050000, ""per_request_limits"": null, ""pricing_metadata"": {""overrides"": [{""completion"": ""0.00000075"", ""input_cache_read"": ""0.00000002"", ""input_cache_write"": ""0.00000025"", ""min_prompt_tokens"": 272000, ""prompt"": ""0.0000002""}], ""web_search"": ""0.01""}, ""top_provider"": {""context_length"": 1050000, ""is_moderated"": true, ""max_completion_tokens"": 128000}, ""unsupported_negative_prices"": {}}",n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": ""https://openrouter.ai/api/v1/models""}",2026-09-25T07:18:38Z,False,[],"{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": ""0.00000001"", ""cache_write"": ""0.000000125"", ""cache_write_1h"": null, ""cache_write_24h"": null, ""cache_write_5m"": null, ""input"": ""0.0000001"", ""output"": ""0.0000005""}",n/d
grok-4.5,opencode,opencode-go/grok-4.5,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
grok-4.6,opencode,opencode-go/grok-4.6,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
grok-4.7,opencode,opencode-go/grok-4.7,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
hy3,opencode,opencode-go/hy3,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
hy3-preview,opencode,opencode-go/hy3-preview,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
hy4-preview,opencode,opencode-go/hy4-preview,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
kimi-k2.5,opencode,opencode-go/kimi-k2.5,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
kimi-k2.6,opencode,opencode-go/kimi-k2.6,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
kimi-k2.7-code,opencode,opencode-go/kimi-k2.7-code,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
kimi-k3,opencode,opencode-go/kimi-k3,moonshotai/kimi-k3,3.000000,15.000000,0.3000000,n/d,n/d,"{""context_length"": 1048576, ""per_request_limits"": null, ""pricing_metadata"": {}, ""top_provider"": {""context_length"": 1048576, ""is_moderated"": false, ""max_completion_tokens"": 943718}, ""unsupported_negative_prices"": {}}",n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": ""https://openrouter.ai/api/v1/models""}",2026-09-25T07:18:38Z,False,[],"{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": ""0.0000003"", ""cache_write"": null, ""cache_write_1h"": null, ""cache_write_24h"": null, ""cache_write_5m"": null, ""input"": ""0.000003"", ""output"": ""0.000015""}",n/d
longcat-2.0,opencode,opencode-go/longcat-2.0,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
mimo-v2-omni,opencode,opencode-go/mimo-v2-omni,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
mimo-v2-pro,opencode,opencode-go/mimo-v2-pro,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
mimo-v2.5,opencode,opencode-go/mimo-v2.5,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
mimo-v2.5-pro,opencode,opencode-go/mimo-v2.5-pro,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
mimo-v2.6-flash,opencode,opencode-go/mimo-v2.6-flash,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
mimo-v2.6-pro,opencode,opencode-go/mimo-v2.6-pro,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
minimax-m2.5,opencode,opencode-go/minimax-m2.5,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
minimax-m2.7,opencode,opencode-go/minimax-m2.7,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
minimax-m3,opencode,opencode-go/minimax-m3,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
muse-spark-1.2-contributor,opencode,opencode-go/muse-spark-1.2-contributor,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
muse-spark-1.3-contributor,opencode,opencode-go/muse-spark-1.3-contributor,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
omen-alpha,opencode,opencode-go/omen-alpha,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
qwen3.5-plus,opencode,opencode-go/qwen3.5-plus,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
qwen3.6-plus,opencode,opencode-go/qwen3.6-plus,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
qwen3.7-max,opencode,opencode-go/qwen3.7-max,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
qwen3.7-plus,opencode,opencode-go/qwen3.7-plus,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
qwen3.8-flash,opencode,opencode-go/qwen3.8-flash,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
qwen3.8-max,opencode,opencode-go/qwen3.8-max,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
space-bunny-free,opencode,opencode-go/space-bunny-free,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/go/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",go_quota,4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
big-pickle,opencode,opencode/big-pickle,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
claude-fable-5,opencode,opencode/claude-fable-5,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
claude-fable-5-1,opencode,opencode/claude-fable-5-1,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
claude-haiku-4-5,opencode,opencode/claude-haiku-4-5,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
claude-opus-4-5,opencode,opencode/claude-opus-4-5,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
claude-opus-4-6,opencode,opencode/claude-opus-4-6,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
claude-opus-4-7,opencode,opencode/claude-opus-4-7,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
claude-opus-4-8,opencode,opencode/claude-opus-4-8,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
claude-opus-5,opencode,opencode/claude-opus-5,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
claude-opus-5-5,opencode,opencode/claude-opus-5-5,anthropic/claude-opus-5.5,4.000000,20.00000,0.2000000,5.000000,8.000000,"{""context_length"": 1000000, ""per_request_limits"": null, ""pricing_metadata"": {""web_search"": ""0.01""}, ""top_provider"": {""context_length"": 1000000, ""is_moderated"": true, ""max_completion_tokens"": 128000}, ""unsupported_negative_prices"": {}}",n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": ""https://openrouter.ai/api/v1/models""}",2026-09-25T07:18:38Z,False,[],"{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": ""0.0000002"", ""cache_write"": ""0.000005"", ""cache_write_1h"": ""0.000008"", ""cache_write_24h"": null, ""cache_write_5m"": null, ""input"": ""0.000004"", ""output"": ""0.00002""}",n/d
claude-sonnet-4,opencode,opencode/claude-sonnet-4,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
claude-sonnet-4-5,opencode,opencode/claude-sonnet-4-5,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
claude-sonnet-4-6,opencode,opencode/claude-sonnet-4-6,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
claude-sonnet-5,opencode,opencode/claude-sonnet-5,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
deepseek-v4-flash,opencode,opencode/deepseek-v4-flash,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
deepseek-v4-flash-free,opencode,opencode/deepseek-v4-flash-free,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
deepseek-v4-flash-vision-exp,opencode,opencode/deepseek-v4-flash-vision-exp,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
deepseek-v4-pro,opencode,opencode/deepseek-v4-pro,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
deepseek-v4.1-flash,opencode,opencode/deepseek-v4.1-flash,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
gemini-3-flash,opencode,opencode/gemini-3-flash,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
gemini-3.1-pro,opencode,opencode/gemini-3.1-pro,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
gemini-3.5-flash,opencode,opencode/gemini-3.5-flash,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
gemini-3.5-flash-lite,opencode,opencode/gemini-3.5-flash-lite,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
gemini-3.6-flash,opencode,opencode/gemini-3.6-flash,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
gemini-3.7-flash,opencode,opencode/gemini-3.7-flash,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
gemini-3.8-flash,opencode,opencode/gemini-3.8-flash,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
glm-5,opencode,opencode/glm-5,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
glm-5.1,opencode,opencode/glm-5.1,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
glm-5.2,opencode,opencode/glm-5.2,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
glm-5.3,opencode,opencode/glm-5.3,z-ai/glm-5.3,1.4000000,4.4000000,0.26000000,n/d,n/d,"{""context_length"": 1310720, ""per_request_limits"": null, ""pricing_metadata"": {}, ""top_provider"": {""context_length"": 1048575, ""is_moderated"": false, ""max_completion_tokens"": 943717}, ""unsupported_negative_prices"": {}}",n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": ""https://openrouter.ai/api/v1/models""}",2026-09-25T07:18:38Z,False,[],"{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": ""0.00000026"", ""cache_write"": null, ""cache_write_1h"": null, ""cache_write_24h"": null, ""cache_write_5m"": null, ""input"": ""0.0000014"", ""output"": ""0.0000044""}",n/d
glm-5.3-flash,opencode,opencode/glm-5.3-flash,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
gpt-5,opencode,opencode/gpt-5,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
gpt-5-codex,opencode,opencode/gpt-5-codex,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
gpt-5-nano,opencode,opencode/gpt-5-nano,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
gpt-5.1,opencode,opencode/gpt-5.1,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
gpt-5.1-codex,opencode,opencode/gpt-5.1-codex,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
gpt-5.1-codex-max,opencode,opencode/gpt-5.1-codex-max,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
gpt-5.1-codex-mini,opencode,opencode/gpt-5.1-codex-mini,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
gpt-5.2,opencode,opencode/gpt-5.2,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
gpt-5.2-codex,opencode,opencode/gpt-5.2-codex,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
gpt-5.3-codex,opencode,opencode/gpt-5.3-codex,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
gpt-5.3-codex-spark,opencode,opencode/gpt-5.3-codex-spark,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
gpt-5.4,opencode,opencode/gpt-5.4,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
gpt-5.4-mini,opencode,opencode/gpt-5.4-mini,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
gpt-5.4-nano,opencode,opencode/gpt-5.4-nano,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
gpt-5.4-pro,opencode,opencode/gpt-5.4-pro,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
gpt-5.5,opencode,opencode/gpt-5.5,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
gpt-5.5-pro,opencode,opencode/gpt-5.5-pro,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
gpt-5.6-luna,opencode,opencode/gpt-5.6-luna,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
gpt-5.6-sol,opencode,opencode/gpt-5.6-sol,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
gpt-5.6-terra,opencode,opencode/gpt-5.6-terra,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
gpt-6-astra,opencode,opencode/gpt-6-astra,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
gpt-6-luna,opencode,opencode/gpt-6-luna,openai/gpt-6-luna,0.1000000,0.5000000,0.01000000,0.125000000,n/d,"{""context_length"": 1050000, ""per_request_limits"": null, ""pricing_metadata"": {""overrides"": [{""completion"": ""0.00000075"", ""input_cache_read"": ""0.00000002"", ""input_cache_write"": ""0.00000025"", ""min_prompt_tokens"": 272000, ""prompt"": ""0.0000002""}], ""web_search"": ""0.01""}, ""top_provider"": {""context_length"": 1050000, ""is_moderated"": true, ""max_completion_tokens"": 128000}, ""unsupported_negative_prices"": {}}",n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": ""https://openrouter.ai/api/v1/models""}",2026-09-25T07:18:38Z,False,[],"{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": ""0.00000001"", ""cache_write"": ""0.000000125"", ""cache_write_1h"": null, ""cache_write_24h"": null, ""cache_write_5m"": null, ""input"": ""0.0000001"", ""output"": ""0.0000005""}",n/d
gpt-6-sol,opencode,opencode/gpt-6-sol,openai/gpt-6-sol,2.000000,10.00000,0.2000000,2.5000000,n/d,"{""context_length"": 1050000, ""per_request_limits"": null, ""pricing_metadata"": {""overrides"": [{""completion"": ""0.000015"", ""input_cache_read"": ""0.0000004"", ""input_cache_write"": ""0.000005"", ""min_prompt_tokens"": 272000, ""prompt"": ""0.000004""}], ""web_search"": ""0.01""}, ""top_provider"": {""context_length"": 1050000, ""is_moderated"": true, ""max_completion_tokens"": 128000}, ""unsupported_negative_prices"": {}}",n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": ""https://openrouter.ai/api/v1/models""}",2026-09-25T07:18:38Z,False,[],"{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": ""0.0000002"", ""cache_write"": ""0.0000025"", ""cache_write_1h"": null, ""cache_write_24h"": null, ""cache_write_5m"": null, ""input"": ""0.000002"", ""output"": ""0.00001""}",n/d
grok-4.5,opencode,opencode/grok-4.5,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
grok-4.6,opencode,opencode/grok-4.6,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
grok-4.7,opencode,opencode/grok-4.7,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
grok-build-0.1,opencode,opencode/grok-build-0.1,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
jev-1.13,opencode,opencode/jev-1.13,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
jev-1.13-free,opencode,opencode/jev-1.13-free,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
kimi-k2.5,opencode,opencode/kimi-k2.5,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
kimi-k2.6,opencode,opencode/kimi-k2.6,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
kimi-k2.7-code,opencode,opencode/kimi-k2.7-code,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
kimi-k3,opencode,opencode/kimi-k3,moonshotai/kimi-k3,3.000000,15.000000,0.3000000,n/d,n/d,"{""context_length"": 1048576, ""per_request_limits"": null, ""pricing_metadata"": {}, ""top_provider"": {""context_length"": 1048576, ""is_moderated"": false, ""max_completion_tokens"": 943718}, ""unsupported_negative_prices"": {}}",n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": ""https://openrouter.ai/api/v1/models""}",2026-09-25T07:18:38Z,False,[],"{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": ""0.0000003"", ""cache_write"": null, ""cache_write_1h"": null, ""cache_write_24h"": null, ""cache_write_5m"": null, ""input"": ""0.000003"", ""output"": ""0.000015""}",n/d
ling-3.0-flash-fin-free,opencode,opencode/ling-3.0-flash-fin-free,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
mimo-v2.5-free,opencode,opencode/mimo-v2.5-free,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
mimo-v2.6-flash-free,opencode,opencode/mimo-v2.6-flash-free,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
minimax-m2.5,opencode,opencode/minimax-m2.5,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
minimax-m2.7,opencode,opencode/minimax-m2.7,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
minimax-m3,opencode,opencode/minimax-m3,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
muse-spark-1.2,opencode,opencode/muse-spark-1.2,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
muse-spark-1.2-contributor-free,opencode,opencode/muse-spark-1.2-contributor-free,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
muse-spark-1.3,opencode,opencode/muse-spark-1.3,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
muse-spark-1.3-contributor-free,opencode,opencode/muse-spark-1.3-contributor-free,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
nemotron-3-ultra-free,opencode,opencode/nemotron-3-ultra-free,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
nemotron-3.5-lightning-free,opencode,opencode/nemotron-3.5-lightning-free,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
qwen3.5-plus,opencode,opencode/qwen3.5-plus,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
qwen3.6-plus,opencode,opencode/qwen3.6-plus,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
qwen3.8-flash,opencode,opencode/qwen3.8-flash,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
space-bunny-free,opencode,opencode/space-bunny-free,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,n/d,descoberta_local_falhou,"{""benchmark"": null, ""catalog"": ""https://opencode.ai/zen/v1/models"", ""openrouter"": null}",2026-09-25T07:18:38Z,True,"[""preco_referencial_ausente""]","{""account_verified_at"": null, ""authenticated"": null, ""balance_confirmed"": null, ""balance_verified_at"": null, ""entitled"": null, ""evidence_hash"": null, ""listed"": true, ""local_listed"": null, ""local_verified_at"": null, ""source"": null, ""verified_at"": null}",zen_balance,1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4,"{""cache_read"": null, ""cache_write"": null, ""input"": null, ""output"": null}",n/d
1 nome tool model_key openrouter_id preco_or_entrada_usd_1m preco_or_saida_usd_1m preco_or_cache_leitura_usd_1m preco_or_cache_escrita_usd_1m preco_or_cache_escrita_1h_usd_1m condicao_de_preco coding_index_versao coding_index_nota benchmark_por_componente_se_publicado harness_aa reasoning_aa grau_do_match faixa preco_native_ou_cota disponivel_na_conta motivo_da_exclusao fonte capturado_em stale stale_reasons availability billing_mode source_hash or_price_per_token score
2 deepseek-flash opencode opencode-go/deepseek-flash n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
3 deepseek-v4-flash opencode opencode-go/deepseek-v4-flash n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
4 deepseek-v4-flash-vision-exp opencode opencode-go/deepseek-v4-flash-vision-exp n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
5 deepseek-v4-pro opencode opencode-go/deepseek-v4-pro n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
6 deepseek-v4.1-flash opencode opencode-go/deepseek-v4.1-flash n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
7 glm-5 opencode opencode-go/glm-5 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
8 glm-5.1 opencode opencode-go/glm-5.1 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
9 glm-5.2 opencode opencode-go/glm-5.2 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
10 glm-5.3 opencode opencode-go/glm-5.3 z-ai/glm-5.3 1.4000000 4.4000000 0.26000000 n/d n/d {"context_length": 1310720, "per_request_limits": null, "pricing_metadata": {}, "top_provider": {"context_length": 1048575, "is_moderated": false, "max_completion_tokens": 943717}, "unsupported_negative_prices": {}} n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": "https://openrouter.ai/api/v1/models"} 2026-09-25T07:18:38Z False [] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": "0.00000026", "cache_write": null, "cache_write_1h": null, "cache_write_24h": null, "cache_write_5m": null, "input": "0.0000014", "output": "0.0000044"} n/d
11 glm-5.3-flash opencode opencode-go/glm-5.3-flash n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
12 gpt-5.6-luna opencode opencode-go/gpt-5.6-luna n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
13 gpt-6-luna opencode opencode-go/gpt-6-luna openai/gpt-6-luna 0.1000000 0.5000000 0.01000000 0.125000000 n/d {"context_length": 1050000, "per_request_limits": null, "pricing_metadata": {"overrides": [{"completion": "0.00000075", "input_cache_read": "0.00000002", "input_cache_write": "0.00000025", "min_prompt_tokens": 272000, "prompt": "0.0000002"}], "web_search": "0.01"}, "top_provider": {"context_length": 1050000, "is_moderated": true, "max_completion_tokens": 128000}, "unsupported_negative_prices": {}} n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": "https://openrouter.ai/api/v1/models"} 2026-09-25T07:18:38Z False [] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": "0.00000001", "cache_write": "0.000000125", "cache_write_1h": null, "cache_write_24h": null, "cache_write_5m": null, "input": "0.0000001", "output": "0.0000005"} n/d
14 grok-4.5 opencode opencode-go/grok-4.5 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
15 grok-4.6 opencode opencode-go/grok-4.6 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
16 grok-4.7 opencode opencode-go/grok-4.7 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
17 hy3 opencode opencode-go/hy3 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
18 hy3-preview opencode opencode-go/hy3-preview n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
19 hy4-preview opencode opencode-go/hy4-preview n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
20 kimi-k2.5 opencode opencode-go/kimi-k2.5 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
21 kimi-k2.6 opencode opencode-go/kimi-k2.6 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
22 kimi-k2.7-code opencode opencode-go/kimi-k2.7-code n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
23 kimi-k3 opencode opencode-go/kimi-k3 moonshotai/kimi-k3 3.000000 15.000000 0.3000000 n/d n/d {"context_length": 1048576, "per_request_limits": null, "pricing_metadata": {}, "top_provider": {"context_length": 1048576, "is_moderated": false, "max_completion_tokens": 943718}, "unsupported_negative_prices": {}} n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": "https://openrouter.ai/api/v1/models"} 2026-09-25T07:18:38Z False [] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": "0.0000003", "cache_write": null, "cache_write_1h": null, "cache_write_24h": null, "cache_write_5m": null, "input": "0.000003", "output": "0.000015"} n/d
24 longcat-2.0 opencode opencode-go/longcat-2.0 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
25 mimo-v2-omni opencode opencode-go/mimo-v2-omni n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
26 mimo-v2-pro opencode opencode-go/mimo-v2-pro n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
27 mimo-v2.5 opencode opencode-go/mimo-v2.5 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
28 mimo-v2.5-pro opencode opencode-go/mimo-v2.5-pro n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
29 mimo-v2.6-flash opencode opencode-go/mimo-v2.6-flash n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
30 mimo-v2.6-pro opencode opencode-go/mimo-v2.6-pro n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
31 minimax-m2.5 opencode opencode-go/minimax-m2.5 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
32 minimax-m2.7 opencode opencode-go/minimax-m2.7 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
33 minimax-m3 opencode opencode-go/minimax-m3 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
34 muse-spark-1.2-contributor opencode opencode-go/muse-spark-1.2-contributor n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
35 muse-spark-1.3-contributor opencode opencode-go/muse-spark-1.3-contributor n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
36 omen-alpha opencode opencode-go/omen-alpha n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
37 qwen3.5-plus opencode opencode-go/qwen3.5-plus n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
38 qwen3.6-plus opencode opencode-go/qwen3.6-plus n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
39 qwen3.7-max opencode opencode-go/qwen3.7-max n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
40 qwen3.7-plus opencode opencode-go/qwen3.7-plus n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
41 qwen3.8-flash opencode opencode-go/qwen3.8-flash n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
42 qwen3.8-max opencode opencode-go/qwen3.8-max n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
43 space-bunny-free opencode opencode-go/space-bunny-free n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/go/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} go_quota 4f3c2a14e77fa546f5ba833d85cca088918ab2ade7e4a0eaf8c5d9a478b48ae4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
44 big-pickle opencode opencode/big-pickle n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
45 claude-fable-5 opencode opencode/claude-fable-5 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
46 claude-fable-5-1 opencode opencode/claude-fable-5-1 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
47 claude-haiku-4-5 opencode opencode/claude-haiku-4-5 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
48 claude-opus-4-5 opencode opencode/claude-opus-4-5 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
49 claude-opus-4-6 opencode opencode/claude-opus-4-6 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
50 claude-opus-4-7 opencode opencode/claude-opus-4-7 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
51 claude-opus-4-8 opencode opencode/claude-opus-4-8 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
52 claude-opus-5 opencode opencode/claude-opus-5 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
53 claude-opus-5-5 opencode opencode/claude-opus-5-5 anthropic/claude-opus-5.5 4.000000 20.00000 0.2000000 5.000000 8.000000 {"context_length": 1000000, "per_request_limits": null, "pricing_metadata": {"web_search": "0.01"}, "top_provider": {"context_length": 1000000, "is_moderated": true, "max_completion_tokens": 128000}, "unsupported_negative_prices": {}} n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": "https://openrouter.ai/api/v1/models"} 2026-09-25T07:18:38Z False [] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": "0.0000002", "cache_write": "0.000005", "cache_write_1h": "0.000008", "cache_write_24h": null, "cache_write_5m": null, "input": "0.000004", "output": "0.00002"} n/d
54 claude-sonnet-4 opencode opencode/claude-sonnet-4 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
55 claude-sonnet-4-5 opencode opencode/claude-sonnet-4-5 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
56 claude-sonnet-4-6 opencode opencode/claude-sonnet-4-6 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
57 claude-sonnet-5 opencode opencode/claude-sonnet-5 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
58 deepseek-v4-flash opencode opencode/deepseek-v4-flash n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
59 deepseek-v4-flash-free opencode opencode/deepseek-v4-flash-free n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
60 deepseek-v4-flash-vision-exp opencode opencode/deepseek-v4-flash-vision-exp n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
61 deepseek-v4-pro opencode opencode/deepseek-v4-pro n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
62 deepseek-v4.1-flash opencode opencode/deepseek-v4.1-flash n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
63 gemini-3-flash opencode opencode/gemini-3-flash n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
64 gemini-3.1-pro opencode opencode/gemini-3.1-pro n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
65 gemini-3.5-flash opencode opencode/gemini-3.5-flash n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
66 gemini-3.5-flash-lite opencode opencode/gemini-3.5-flash-lite n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
67 gemini-3.6-flash opencode opencode/gemini-3.6-flash n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
68 gemini-3.7-flash opencode opencode/gemini-3.7-flash n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
69 gemini-3.8-flash opencode opencode/gemini-3.8-flash n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
70 glm-5 opencode opencode/glm-5 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
71 glm-5.1 opencode opencode/glm-5.1 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
72 glm-5.2 opencode opencode/glm-5.2 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
73 glm-5.3 opencode opencode/glm-5.3 z-ai/glm-5.3 1.4000000 4.4000000 0.26000000 n/d n/d {"context_length": 1310720, "per_request_limits": null, "pricing_metadata": {}, "top_provider": {"context_length": 1048575, "is_moderated": false, "max_completion_tokens": 943717}, "unsupported_negative_prices": {}} n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": "https://openrouter.ai/api/v1/models"} 2026-09-25T07:18:38Z False [] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": "0.00000026", "cache_write": null, "cache_write_1h": null, "cache_write_24h": null, "cache_write_5m": null, "input": "0.0000014", "output": "0.0000044"} n/d
74 glm-5.3-flash opencode opencode/glm-5.3-flash n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
75 gpt-5 opencode opencode/gpt-5 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
76 gpt-5-codex opencode opencode/gpt-5-codex n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
77 gpt-5-nano opencode opencode/gpt-5-nano n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
78 gpt-5.1 opencode opencode/gpt-5.1 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
79 gpt-5.1-codex opencode opencode/gpt-5.1-codex n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
80 gpt-5.1-codex-max opencode opencode/gpt-5.1-codex-max n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
81 gpt-5.1-codex-mini opencode opencode/gpt-5.1-codex-mini n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
82 gpt-5.2 opencode opencode/gpt-5.2 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
83 gpt-5.2-codex opencode opencode/gpt-5.2-codex n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
84 gpt-5.3-codex opencode opencode/gpt-5.3-codex n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
85 gpt-5.3-codex-spark opencode opencode/gpt-5.3-codex-spark n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
86 gpt-5.4 opencode opencode/gpt-5.4 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
87 gpt-5.4-mini opencode opencode/gpt-5.4-mini n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
88 gpt-5.4-nano opencode opencode/gpt-5.4-nano n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
89 gpt-5.4-pro opencode opencode/gpt-5.4-pro n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
90 gpt-5.5 opencode opencode/gpt-5.5 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
91 gpt-5.5-pro opencode opencode/gpt-5.5-pro n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
92 gpt-5.6-luna opencode opencode/gpt-5.6-luna n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
93 gpt-5.6-sol opencode opencode/gpt-5.6-sol n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
94 gpt-5.6-terra opencode opencode/gpt-5.6-terra n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
95 gpt-6-astra opencode opencode/gpt-6-astra n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
96 gpt-6-luna opencode opencode/gpt-6-luna openai/gpt-6-luna 0.1000000 0.5000000 0.01000000 0.125000000 n/d {"context_length": 1050000, "per_request_limits": null, "pricing_metadata": {"overrides": [{"completion": "0.00000075", "input_cache_read": "0.00000002", "input_cache_write": "0.00000025", "min_prompt_tokens": 272000, "prompt": "0.0000002"}], "web_search": "0.01"}, "top_provider": {"context_length": 1050000, "is_moderated": true, "max_completion_tokens": 128000}, "unsupported_negative_prices": {}} n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": "https://openrouter.ai/api/v1/models"} 2026-09-25T07:18:38Z False [] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": "0.00000001", "cache_write": "0.000000125", "cache_write_1h": null, "cache_write_24h": null, "cache_write_5m": null, "input": "0.0000001", "output": "0.0000005"} n/d
97 gpt-6-sol opencode opencode/gpt-6-sol openai/gpt-6-sol 2.000000 10.00000 0.2000000 2.5000000 n/d {"context_length": 1050000, "per_request_limits": null, "pricing_metadata": {"overrides": [{"completion": "0.000015", "input_cache_read": "0.0000004", "input_cache_write": "0.000005", "min_prompt_tokens": 272000, "prompt": "0.000004"}], "web_search": "0.01"}, "top_provider": {"context_length": 1050000, "is_moderated": true, "max_completion_tokens": 128000}, "unsupported_negative_prices": {}} n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": "https://openrouter.ai/api/v1/models"} 2026-09-25T07:18:38Z False [] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": "0.0000002", "cache_write": "0.0000025", "cache_write_1h": null, "cache_write_24h": null, "cache_write_5m": null, "input": "0.000002", "output": "0.00001"} n/d
98 grok-4.5 opencode opencode/grok-4.5 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
99 grok-4.6 opencode opencode/grok-4.6 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
100 grok-4.7 opencode opencode/grok-4.7 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
101 grok-build-0.1 opencode opencode/grok-build-0.1 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
102 jev-1.13 opencode opencode/jev-1.13 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
103 jev-1.13-free opencode opencode/jev-1.13-free n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
104 kimi-k2.5 opencode opencode/kimi-k2.5 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
105 kimi-k2.6 opencode opencode/kimi-k2.6 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
106 kimi-k2.7-code opencode opencode/kimi-k2.7-code n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
107 kimi-k3 opencode opencode/kimi-k3 moonshotai/kimi-k3 3.000000 15.000000 0.3000000 n/d n/d {"context_length": 1048576, "per_request_limits": null, "pricing_metadata": {}, "top_provider": {"context_length": 1048576, "is_moderated": false, "max_completion_tokens": 943718}, "unsupported_negative_prices": {}} n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": "https://openrouter.ai/api/v1/models"} 2026-09-25T07:18:38Z False [] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": "0.0000003", "cache_write": null, "cache_write_1h": null, "cache_write_24h": null, "cache_write_5m": null, "input": "0.000003", "output": "0.000015"} n/d
108 ling-3.0-flash-fin-free opencode opencode/ling-3.0-flash-fin-free n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
109 mimo-v2.5-free opencode opencode/mimo-v2.5-free n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
110 mimo-v2.6-flash-free opencode opencode/mimo-v2.6-flash-free n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
111 minimax-m2.5 opencode opencode/minimax-m2.5 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
112 minimax-m2.7 opencode opencode/minimax-m2.7 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
113 minimax-m3 opencode opencode/minimax-m3 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
114 muse-spark-1.2 opencode opencode/muse-spark-1.2 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
115 muse-spark-1.2-contributor-free opencode opencode/muse-spark-1.2-contributor-free n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
116 muse-spark-1.3 opencode opencode/muse-spark-1.3 n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
117 muse-spark-1.3-contributor-free opencode opencode/muse-spark-1.3-contributor-free n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
118 nemotron-3-ultra-free opencode opencode/nemotron-3-ultra-free n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
119 nemotron-3.5-lightning-free opencode opencode/nemotron-3.5-lightning-free n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
120 qwen3.5-plus opencode opencode/qwen3.5-plus n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
121 qwen3.6-plus opencode opencode/qwen3.6-plus n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
122 qwen3.8-flash opencode opencode/qwen3.8-flash n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
123 space-bunny-free opencode opencode/space-bunny-free n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d n/d descoberta_local_falhou {"benchmark": null, "catalog": "https://opencode.ai/zen/v1/models", "openrouter": null} 2026-09-25T07:18:38Z True ["preco_referencial_ausente"] {"account_verified_at": null, "authenticated": null, "balance_confirmed": null, "balance_verified_at": null, "entitled": null, "evidence_hash": null, "listed": true, "local_listed": null, "local_verified_at": null, "source": null, "verified_at": null} zen_balance 1b8d7a3dd18412473419eed98e32be003db5307754a1c5ab0f491ff33b4806a4 {"cache_read": null, "cache_write": null, "input": null, "output": null} n/d
+416
View File
@@ -0,0 +1,416 @@
#!/usr/bin/env python3
"""Adapter and headless-runner behavior tests; fake CLIs never contact providers."""
import importlib.util
import json
import os
import pathlib
import sys
import shutil
import unittest
import tempfile
from unittest import mock
ROOT = pathlib.Path(__file__).resolve().parents[1]
REAL_WHICH = shutil.which
def load_module(name, path):
spec = importlib.util.spec_from_file_location(name, path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
installer = load_module("dev_workflows_install", ROOT / "scripts" / "install.py")
harness = load_module("dev_workflows_harness", ROOT / "scripts" / "harness_runner.py")
class AdapterTest(unittest.TestCase):
def test_omp_install_preserves_unowned_destination_and_skips_link(self):
with tempfile.TemporaryDirectory() as temp:
base = pathlib.Path(temp) / ".omp"
dest = base / "plugins" / "dev-workflows"
dest.mkdir(parents=True)
(dest / "user-data").write_text("preserve", encoding="utf-8")
runner = mock.Mock()
with self.assertRaises(SystemExit):
installer.install_omp(base=str(base), runner=runner)
runner.assert_not_called()
self.assertEqual((dest / "user-data").read_text(encoding="utf-8"), "preserve")
def test_omp_install_keeps_package_for_recovery_if_link_fails(self):
with tempfile.TemporaryDirectory() as temp:
base = pathlib.Path(temp) / ".omp"
runner = mock.Mock(return_value=mock.Mock(returncode=7))
with self.assertRaisesRegex(SystemExit, "falhou com código 7"):
installer.install_omp(base=str(base), runner=runner)
self.assertTrue((base / "plugins" / "dev-workflows" / ".dev-workflows-omp-package").is_file())
class HarnessRunnerTest(unittest.TestCase):
def setUp(self):
self.temp = tempfile.TemporaryDirectory()
self.root = pathlib.Path(self.temp.name)
self.cwd = self.root / "state" / "project" / "run" / "worktrees" / "iteration-001"
self.cwd.mkdir(parents=True)
gitdir = self.root / "project" / ".git" / "worktrees" / "iteration-001"
gitdir.mkdir(parents=True)
(self.cwd / ".git").write_text(f"gitdir: {gitdir}\n", encoding="utf-8")
self.bin = self.root / "bin"
self.bin.mkdir()
self.trace = self.root / "calls.jsonl"
self.cache = self.root / "catalog"
self.cache.mkdir()
self._fake_cli()
def tearDown(self):
self.temp.cleanup()
def _fake_cli(self):
executable = self.bin / "fake-cli"
executable.write_text(
"#!" + sys.executable + "\n"
"import json, os, pathlib, sys\n"
"name = pathlib.Path(sys.argv[0]).name\n"
"args = sys.argv[1:]\n"
"with open(os.environ['DW_TRACE'], 'a', encoding='utf-8') as out:\n"
" out.write(json.dumps({'name': name, 'args': args, 'cwd': os.getcwd(), 'marker': os.getenv('DW_MARKER')}) + '\\n')\n"
"if name == 'claude' and args[:3] == ['auth', 'status', '--json']:\n"
" print(os.environ.get('DW_CLAUDE_AUTH', '{\\\"loggedIn\\\": true}'))\n"
"elif name == 'opencode' and args[:1] == ['models']:\n"
" print(os.environ.get('DW_MODELS', ''))\n"
"elif name == 'omp' and args[:2] == ['models', args[1] if len(args) > 1 else '']:\n"
" print(os.environ.get('DW_MODELS_JSON', '[]'))\n"
"else:\n"
" print('fake response')\n"
" print('sk-secret-must-not-escape', file=sys.stderr)\n",
encoding="utf-8",
)
executable.chmod(0o755)
for name in ("claude", "opencode", "omp"):
(self.bin / name).symlink_to(executable)
def _env(self, **extra):
value = os.environ.copy()
value.update({
"PATH": str(self.bin) + os.pathsep + value.get("PATH", ""),
"DEV_WORKFLOWS_MODEL_CACHE": str(self.cache),
"DW_TRACE": str(self.trace),
"DW_MARKER": "test-env",
})
value.update(extra)
return value
def _snapshot(self, tool, model_key, *, entitled=True, variant=None, provider=None, model_id=None):
row = {
"tool": tool,
"model_key": model_key,
"availability": {
"local_listed": True,
"authenticated": True,
"entitled": entitled,
"source": "manual_audited",
"verified_at": "2026-09-25T12:00:00Z",
},
}
if variant is not None:
row.update({"variant": variant, "provider": provider, "model_id": model_id})
(self.cache / f"catalog-{tool}.json").write_text(
json.dumps({"schema_version": 1, "tool": tool, "models": [row]}), encoding="utf-8"
)
def _calls(self):
if not self.trace.exists():
return []
return [json.loads(line) for line in self.trace.read_text(encoding="utf-8").splitlines()]
def _fake_bwrap(self):
trace = self.root / "bwrap.jsonl"
executable = self.bin / "bwrap"
executable.write_text(
"#!" + sys.executable + "\n"
"import json, os, pathlib, sys\n"
"args = sys.argv[1:]\n"
"with open(os.environ['DW_BWRAP_TRACE'], 'a', encoding='utf-8') as out:\n"
" out.write(json.dumps(args) + '\\n')\n"
"command = args[args.index('--') + 1:]\n"
"tool = pathlib.Path(command[0]).name\n"
"if tool == 'omp' and 'models' in command:\n"
" print(os.environ.get('DW_MODELS_JSON', '[]'))\n"
"elif tool == 'opencode' and 'models' in command:\n"
" print(os.environ.get('DW_MODELS', ''))\n"
"elif tool == 'claude' and command[1:3] == ['auth', 'status']:\n"
" print(os.environ.get('DW_CLAUDE_AUTH', '{\\\"loggedIn\\\": true}'))\n"
"else:\n"
" print('fake wrapped response')\n",
encoding="utf-8",
)
executable.chmod(0o755)
return trace
def _invoke_with_fake_bwrap(self, *args, **kwargs):
def find_executable(name, path=None):
if name == "bwrap":
return str(self.bin / "bwrap")
return REAL_WHICH(name, path=path)
with mock.patch.object(harness.shutil, "which", side_effect=find_executable):
return harness.invoke(*args, **kwargs)
def test_claude_alias_and_dontask_preserve_default_permission_gate(self):
result = harness.invoke("claude", "reviewer", "Review safely", str(self.cwd), "opus", env=self._env())
self.assertEqual(result["returncode"], 0)
calls = self._calls()
self.assertEqual(calls[0]["args"], ["auth", "status", "--json"])
call = calls[1]
args = call["args"]
self.assertIn("--permission-mode", args)
self.assertEqual(args[args.index("--permission-mode") + 1], "dontAsk")
self.assertIn("--agent", args)
self.assertIn("reviewer", args)
self.assertEqual(args[args.index("--model") + 1], "opus")
self.assertNotIn("--dangerously-skip-permissions", args)
self.assertEqual(call["cwd"], str(self.cwd))
self.assertEqual(call["marker"], "test-env")
self.assertIsNone(result["usage"])
self.assertNotIn("sk-secret", result["output"])
def test_claude_inherit_keeps_role_alias_without_model_override(self):
result = harness.invoke("claude", "explorer", "Map the project", str(self.cwd), "inherit", env=self._env())
self.assertEqual(result["returncode"], 0)
calls = self._calls()
self.assertEqual(calls[0]["args"], ["auth", "status", "--json"])
args = calls[1]["args"]
self.assertIn("--agent", args)
self.assertNotIn("--model", args)
self.assertNotIn("--dangerously-skip-permissions", args)
def test_sonnet_alias_is_passed_without_rewriting_the_plugin(self):
harness.invoke("claude", "ui-critic", "Critique only", str(self.cwd), "sonnet", env=self._env())
calls = self._calls()
args = calls[1]["args"]
self.assertEqual(args[args.index("--model") + 1], "sonnet")
self.assertEqual(args[args.index("--agent") + 1], "ui-critic")
def test_claude_alias_is_blocked_when_local_auth_status_is_negative(self):
with self.assertRaisesRegex(harness.HarnessError, "auth status"):
harness.invoke(
"claude", "reviewer", "Review", str(self.cwd), "opus",
env=self._env(DW_CLAUDE_AUTH='{"loggedIn": false}'),
)
calls = self._calls()
self.assertEqual(len(calls), 1)
self.assertEqual(calls[0]["args"], ["auth", "status", "--json"])
def test_opencode_uses_exact_variant_and_role_agent_without_auto_approval(self):
model_key = "openai/gpt-6-luna#high"
self._snapshot("opencode", model_key)
result = harness.invoke(
"opencode", "planner", "Plan only", str(self.cwd), model_key,
env=self._env(DW_MODELS="gpt-6-luna"),
)
self.assertEqual(result["returncode"], 0)
calls = self._calls()
self.assertEqual(calls[0]["args"], ["models", "openai"])
args = calls[1]["args"]
self.assertEqual(args[:3], ["run", "--agent", "planner"])
self.assertEqual(args[args.index("--model") + 1], model_key)
self.assertNotIn("--auto", args)
self.assertEqual(calls[1]["cwd"], str(self.cwd))
self.assertIn("stderr omitido por segurança", result["output"])
self.assertNotIn("sk-secret", result["output"])
def test_omp_runs_with_exact_tools_and_always_ask(self):
model_key = "openai/gpt-6-luna#high"
self._snapshot("omp", model_key, variant="high", provider="openai", model_id="gpt-6-luna")
result = harness.invoke(
"omp", "explorer", "Inspect only", str(self.cwd), model_key,
env=self._env(DW_MODELS_JSON=json.dumps([{"provider": "openai", "id": "gpt-6-luna",
"thinking": ["low", "high"]}])),
)
self.assertEqual(result["returncode"], 0)
calls = self._calls()
self.assertEqual(calls[0]["args"], ["models", "openai", "--json"])
args = calls[1]["args"]
self.assertEqual(args[0], "-p")
self.assertEqual(args[args.index("--model") + 1], "openai/gpt-6-luna")
self.assertEqual(args[args.index("--thinking") + 1], "high")
self.assertEqual(args[args.index("--approval-mode") + 1], "always-ask")
self.assertNotIn("--auto-approve", args)
self.assertEqual(args[args.index("--tools") + 1], "read,grep,glob")
self.assertEqual(args[args.index("--cwd") + 1], str(self.cwd))
def test_omp_unknown_thinking_variant_is_rejected_before_listing_or_dispatch(self):
model_key = "openai/model#unsupported"
self._snapshot("omp", model_key, variant="unsupported", provider="openai", model_id="model")
with self.assertRaisesRegex(harness.HarnessError, "variante"):
harness.invoke("omp", "explorer", "Inspect", str(self.cwd), model_key, env=self._env())
self.assertEqual(self._calls(), [])
def test_omp_rejects_thinking_not_supported_by_current_model_listing(self):
model_key = "openai/gpt-6-luna#high"
self._snapshot("omp", model_key, variant="high", provider="openai", model_id="gpt-6-luna")
listed = {"models": [{"provider": "openai", "id": "gpt-6-luna", "thinking": ["low"]}]}
with self.assertRaisesRegex(harness.HarnessError, "indisponível"):
harness.invoke("omp", "explorer", "Inspect", str(self.cwd), model_key,
env=self._env(DW_MODELS_JSON=json.dumps(listed)))
self.assertEqual([call["args"] for call in self._calls()], [["models", "openai", "--json"]])
def test_omp_slash_model_id_keeps_provider_and_qualified_selector(self):
model_key = "openrouter/anthropic/claude-sonnet-4.6"
self._snapshot("omp", model_key)
listed = {"models": [{"provider": "openrouter", "id": "anthropic/claude-sonnet-4.6",
"selector": model_key, "thinking": None}]}
result = harness.invoke("omp", "explorer", "Inspect", str(self.cwd), model_key,
env=self._env(DW_MODELS_JSON=json.dumps(listed)))
self.assertEqual(result["returncode"], 0)
calls = self._calls()
self.assertEqual(calls[0]["args"], ["models", "openrouter", "--json"])
self.assertEqual(calls[1]["args"][calls[1]["args"].index("--model") + 1], model_key)
def test_autonomous_omp_uses_bwrap_and_bounded_tools_with_auto_approval(self):
model_key = "openai/gpt-6-luna#high"
self._snapshot("omp", model_key, variant="high", provider="openai", model_id="gpt-6-luna")
trace = self._fake_bwrap()
result = self._invoke_with_fake_bwrap(
"omp", "implementer", "Inspect only", str(self.cwd), model_key,
env=self._env(
DEV_WORKFLOWS_AUTONOMOUS="1",
DW_BWRAP_TRACE=str(trace),
DW_MODELS_JSON=json.dumps([{"provider": "openai", "id": "gpt-6-luna",
"thinking": ["low", "high"]}]),
),
)
self.assertEqual(result["returncode"], 0)
self.assertEqual(self._calls(), [])
calls = [json.loads(line) for line in trace.read_text(encoding="utf-8").splitlines()]
self.assertEqual(len(calls), 2)
for args in calls:
self.assertEqual(args[:6], ["--unshare-all", "--share-net", "--die-with-parent", "--ro-bind", "/", "/"])
binds = [args[index + 1:index + 3] for index, value in enumerate(args) if value == "--bind"]
self.assertIn([str(self.cwd), str(self.cwd)], binds)
readonly = [args[index + 1:index + 3] for index, value in enumerate(args) if value == "--ro-bind"]
self.assertIn([str(self.cwd / ".git"), str(self.cwd / ".git")], readonly)
preflight = calls[0][calls[0].index("--") + 1:]
self.assertEqual(pathlib.Path(preflight[0]).name, "omp")
self.assertEqual(preflight[1:4], ["--no-extensions", "models", "openai"])
command = calls[1][calls[1].index("--") + 1:]
self.assertEqual(pathlib.Path(command[0]).name, "omp")
self.assertEqual(command[1], "-p")
for flag in ("--no-extensions", "--no-lsp", "--no-session", "--auto-approve"):
self.assertIn(flag, command)
self.assertEqual(command[command.index("--model") + 1], "openai/gpt-6-luna")
self.assertEqual(command[command.index("--thinking") + 1], "high")
self.assertEqual(command[command.index("--tools") + 1], "read,grep,glob,edit,write")
self.assertNotIn("bash", command)
self.assertNotIn("web_search", command)
def test_autonomous_opencode_uses_pure_mode_and_synthetic_deny_agent(self):
model_key = "openai/gpt-6-luna#high"
self._snapshot("opencode", model_key)
trace = self._fake_bwrap()
meta, prompt = harness._agent("implementer")
generated = harness._opencode_loop_agent(meta, prompt)
self.assertIn(' "*": deny', generated)
self.assertIn(" bash: deny", generated)
self.assertIn(" edit: allow", generated)
self.assertIn(" task: deny", generated)
result = self._invoke_with_fake_bwrap(
"opencode", "implementer", "Implement safely", str(self.cwd), model_key,
env=self._env(DEV_WORKFLOWS_AUTONOMOUS="1", DW_BWRAP_TRACE=str(trace), DW_MODELS="gpt-6-luna"),
)
self.assertEqual(result["returncode"], 0)
self.assertEqual(self._calls(), [])
calls = [json.loads(line) for line in trace.read_text(encoding="utf-8").splitlines()]
self.assertEqual(len(calls), 2)
preflight = calls[0][calls[0].index("--") + 1:]
self.assertEqual(pathlib.Path(preflight[0]).name, "opencode")
self.assertEqual(preflight[1:3], ["--pure", "models"])
command = calls[1][calls[1].index("--") + 1:]
self.assertEqual(pathlib.Path(command[0]).name, "opencode")
self.assertEqual(command[1:4], ["--pure", "run", "--agent"])
agent_name = command[4]
self.assertRegex(agent_name, r"\Adev-workflows-loop-implementer-[0-9a-f]{16}\Z")
self.assertIn("--file", calls[1])
def test_autonomous_claude_uses_bare_mode_and_declared_safe_tools(self):
trace = self._fake_bwrap()
result = self._invoke_with_fake_bwrap(
"claude", "reviewer", "Review only", str(self.cwd), "opus",
env=self._env(DEV_WORKFLOWS_AUTONOMOUS="1", DW_BWRAP_TRACE=str(trace)),
)
self.assertEqual(result["returncode"], 0)
self.assertEqual(self._calls(), [])
calls = [json.loads(line) for line in trace.read_text(encoding="utf-8").splitlines()]
self.assertEqual(len(calls), 2)
auth = calls[0][calls[0].index("--") + 1:]
self.assertEqual(pathlib.Path(auth[0]).name, "claude")
self.assertEqual(auth[1:], ["auth", "status", "--json"])
command = calls[1][calls[1].index("--") + 1:]
self.assertIn("--bare", command)
self.assertIn("--no-session-persistence", command)
self.assertEqual(command[command.index("--permission-mode") + 1], "dontAsk")
agent_config = json.loads(command[command.index("--agents") + 1])
self.assertEqual(agent_config["reviewer"]["tools"], ["Read", "Grep", "Glob"])
self.assertEqual(command[command.index("--tools") + 1], "Read,Grep,Glob")
self.assertNotIn("Bash", command)
def test_autonomous_mode_fails_closed_without_bwrap(self):
self._snapshot("omp", "openai/gpt-6-luna")
def find_without_bwrap(name, path=None):
return None if name == "bwrap" else REAL_WHICH(name, path=path)
with mock.patch.object(harness.shutil, "which", side_effect=find_without_bwrap):
with self.assertRaisesRegex(harness.HarnessError, "bwrap"):
harness.invoke(
"omp", "explorer", "Inspect", str(self.cwd), "openai/gpt-6-luna",
env=self._env(PATH=str(self.bin), DEV_WORKFLOWS_AUTONOMOUS="1"),
)
self.assertEqual(self._calls(), [])
def test_autonomous_rejects_non_worktree_cwd_before_dispatch(self):
other = self.root / "ordinary-directory"
other.mkdir()
with self.assertRaisesRegex(harness.HarnessError, "worktree"):
harness.invoke(
"omp", "explorer", "Inspect", str(other), "openai/gpt-6-luna",
env=self._env(DEV_WORKFLOWS_AUTONOMOUS="1"),
)
self.assertEqual(self._calls(), [])
def test_autonomous_does_not_resolve_cli_from_writable_worktree(self):
self._snapshot("opencode", "openai/gpt-6-luna")
shadow = self.cwd / "opencode"
shadow.write_text("#!/bin/sh\nexit 0\n", encoding="utf-8")
shadow.chmod(0o755)
with self.assertRaisesRegex(harness.HarnessError, "PATH seguro"):
harness.invoke(
"opencode", "planner", "Plan", str(self.cwd), "openai/gpt-6-luna",
env=self._env(PATH=str(self.cwd), DEV_WORKFLOWS_AUTONOMOUS="1"),
)
self.assertEqual(self._calls(), [])
def test_unentitled_model_is_blocked_before_cli_is_started(self):
self._snapshot("opencode", "openai/gpt-6-luna", entitled=False)
with self.assertRaisesRegex(harness.HarnessError, "autorização local"):
harness.invoke(
"opencode", "planner", "Plan", str(self.cwd), "openai/gpt-6-luna",
env=self._env(DW_MODELS="gpt-6-luna"),
)
self.assertEqual(self._calls(), [])
def test_model_absent_from_local_cli_is_blocked_before_agent_dispatch(self):
self._snapshot("opencode", "openai/gpt-6-luna")
with self.assertRaisesRegex(harness.HarnessError, "indisponível na CLI local"):
harness.invoke(
"opencode", "planner", "Plan", str(self.cwd), "openai/gpt-6-luna",
env=self._env(DW_MODELS="openai/different-model"),
)
calls = self._calls()
self.assertEqual(len(calls), 1)
self.assertEqual(calls[0]["args"], ["models", "openai"])
if __name__ == "__main__":
unittest.main(verbosity=1)
+388
View File
@@ -0,0 +1,388 @@
#!/usr/bin/env python3
"""End-to-end controller tests on disposable repositories, using the real gate/evaluator."""
import hashlib
import io
import json
import os
from pathlib import Path
import subprocess
import sys
import tempfile
import types
import unittest
from unittest.mock import patch
SCRIPTS = Path(__file__).resolve().parent.parent / "scripts"
sys.path.insert(0, str(SCRIPTS))
import goal_loop as loop
def git(repo, *args):
p = subprocess.run(["git", *args], cwd=repo, capture_output=True, text=True)
if p.returncode:
raise AssertionError(p.stderr)
return p.stdout.strip()
class GoalLoopTest(unittest.TestCase):
def setUp(self):
self.tmp = tempfile.TemporaryDirectory()
self.addCleanup(self.tmp.cleanup)
root = Path(self.tmp.name)
self.repo = root / "app"
self.repo.mkdir()
self.state = root / "state"
self.bin = root / "bin"
self.bin.mkdir()
scanner = self.bin / "gitleaks"
scanner.write_text("#!/bin/sh\nexit 0\n")
scanner.chmod(0o755)
self.env = patch.dict(os.environ, {"DW_STATE_HOME": str(self.state),
"PATH": str(self.bin) + os.pathsep + os.environ["PATH"]})
self.env.start()
self.addCleanup(self.env.stop)
git(self.repo, "init", "-q")
git(self.repo, "config", "user.name", "test")
git(self.repo, "config", "user.email", "[email protected]")
(self.repo / "calc.py").write_text("VALUE = 0\n")
(self.repo / "verify.py").write_text("import runpy\nassert runpy.run_path('calc.py')['VALUE'] >= 0\n")
self.evaluator = root / "evaluator.py"
self.evaluator.write_text(
"import json, os, pathlib, runpy\n"
"value = runpy.run_path('calc.py')['VALUE']\n"
"folder = pathlib.Path(os.environ['DW_REPORT_DIR'])\n"
"evidence = folder / 'result.json'\n"
"evidence.write_text(json.dumps({'measured': value}))\n"
"print(json.dumps({'schema_version': 1, 'metric': 'quality', 'value': value, "
"'unit': 'points', 'direction': 'maximize', 'checks': {'regression': 'pass'}, "
"'evidence': [str(evidence)]}))\n")
self.config = self.repo / ".dev-workflows.toml"
self.write_config()
git(self.repo, "add", "-A")
git(self.repo, "commit", "-qm", "baseline")
self.original = git(self.repo, "rev-parse", "HEAD")
def write_config(self, target=2, iterations=4, stagnant=2, tier=0, billing="claude_subscription"):
checksum = hashlib.sha256(self.evaluator.read_bytes()).hexdigest()
self.config.write_text(
f"[commands]\ntest = \"python3 verify.py\"\nlint = \"true\"\ntypecheck = \"true\"\n"
f"[loop]\nenabled = true\nharness = \"claude\"\ntier = {tier}\n"
f"max_iterations = {iterations}\nmax_minutes = 5\nmax_stagnant = {stagnant}\n"
"min_improvement = 1\nmax_paid_usd = 0\n"
f"[loop.goal]\nname = \"quality\"\nunit = \"points\"\ndirection = \"maximize\"\ntarget = {target}\n"
"[loop.evaluator]\n"
f"argv = [\"python3\", \"{self.evaluator}\"]\n"
f"trusted_sha256 = \"{checksum}\"\nrequired_checks = [\"test\", \"lint\"]\n"
"[models.roles.implementer]\n"
f"model_key = \"sonnet\"\nbilling_mode = \"{billing}\"\nmanual_unranked_approval = true\n")
if tier >= 2:
with self.config.open("a") as config:
for role in ("planner", "reviewer"):
config.write(f"[models.roles.{role}]\nmodel_key = \"opus\"\n"
"billing_mode = \"claude_subscription\"\nmanual_unranked_approval = true\n")
if tier >= 3:
config.write("[models.roles.security-auditor]\nmodel_key = \"opus\"\n"
"billing_mode = \"claude_subscription\"\nmanual_unranked_approval = true\n")
def runner(self, behavior):
def invoke(tool, role, prompt, cwd, model_key, timeout=900, env=None):
if role in ("planner", "reviewer", "security-auditor"):
return {"returncode": 0, "output": '{"verdict":"pass","findings":[]}', "usage": {}}
value = int((Path(cwd) / "calc.py").read_text().split("=")[1].strip())
next_value = behavior(value, cwd)
(Path(cwd) / "calc.py").write_text(f"VALUE = {next_value}\n")
return {"returncode": 0, "output": "changed one behavior", "usage": {}}
return patch.dict(sys.modules, {"harness_runner": types.SimpleNamespace(invoke=invoke)})
def test_plan_does_not_create_worktree_or_invoke_agent(self):
before = git(self.repo, "worktree", "list", "--porcelain")
result = loop.plan(self.config)
self.assertEqual(result["baseline"], "not_run")
self.assertEqual(result["gate_preflight"]["test"], "run")
self.assertEqual(git(self.repo, "worktree", "list", "--porcelain"), before)
self.assertFalse(self.state.exists())
def test_two_measured_changes_reach_target_without_touching_user_branch(self):
with self.runner(lambda value, _: value + 1):
result = loop.new_run(self.config)
self.assertEqual(result["status"], "success", result)
self.assertEqual([a["result"] for a in result["attempts"]], ["accepted", "accepted"])
self.assertEqual(result["best_score"], "2")
self.assertEqual(git(self.repo, "rev-parse", "HEAD"), self.original)
self.assertEqual((self.repo / "calc.py").read_text(), "VALUE = 0\n")
self.assertEqual((Path(result["best_worktree"]) / "calc.py").read_text(), "VALUE = 2\n")
self.assertNotIn(".dev-workflows/gate.json", git(Path(result["best_worktree"]), "ls-files"))
self.assertEqual(result["attempts"][1]["gate"]["checks"]["test"], "pass")
def test_limit_preserves_best_improvement_without_claiming_target(self):
self.write_config(target=3, iterations=2)
git(self.repo, "add", ".dev-workflows.toml")
git(self.repo, "commit", "-qm", "target-three")
with self.runner(lambda value, _: value + 1):
result = loop.new_run(self.config)
self.assertEqual(result["status"], "exhausted", result)
self.assertEqual(result["best_score"], "2")
self.assertEqual([a["result"] for a in result["attempts"]], ["accepted", "accepted"])
self.assertEqual((self.repo / "calc.py").read_text(), "VALUE = 0\n")
def test_measured_improvement_can_remove_obsolete_code(self):
(self.repo / "legacy.py").write_text("OLD = True\n")
self.evaluator.write_text(self.evaluator.read_text().replace(
"value = runpy.run_path('calc.py')['VALUE']",
"value = runpy.run_path('calc.py')['VALUE'] + int(not pathlib.Path('legacy.py').exists())"))
self.write_config(target=1, iterations=1)
git(self.repo, "add", "-A")
git(self.repo, "commit", "-qm", "legacy-baseline")
def invoke(tool, role, prompt, cwd, model_key, timeout=900, env=None):
(Path(cwd) / "legacy.py").unlink()
return {"returncode": 0, "output": "removed legacy", "usage": {}}
with patch.dict(sys.modules, {"harness_runner": types.SimpleNamespace(invoke=invoke)}):
result = loop.new_run(self.config)
self.assertEqual(result["status"], "success", result)
self.assertFalse((Path(result["best_worktree"]) / "legacy.py").exists())
self.assertTrue((self.repo / "legacy.py").exists())
def test_baseline_at_target_exits_without_editing(self):
self.write_config(target=0)
git(self.repo, "add", ".dev-workflows.toml")
git(self.repo, "commit", "-qm", "zero-target")
with self.runner(lambda _value, _cwd: self.fail("agente não deveria ser chamado")):
result = loop.new_run(self.config)
self.assertEqual(result["status"], "success", result)
self.assertEqual(result["iteration"], 0)
self.assertEqual(result["attempts"], [])
def test_evaluator_cannot_modify_original_checkout(self):
self.evaluator.write_text(
self.evaluator.read_text() +
f"open({str(self.repo / 'calc.py')!r}, 'w').write('VALUE = 999\\n')\n")
self.write_config(target=1)
git(self.repo, "add", ".dev-workflows.toml")
git(self.repo, "commit", "-qm", "protected-evaluator")
with self.runner(lambda value, _: value + 1):
result = loop.new_run(self.config)
self.assertEqual(result["status"], "error", result)
self.assertIn("avaliador", result["error"])
self.assertEqual((self.repo / "calc.py").read_text(), "VALUE = 0\n")
def test_gate_failure_rejects_regression_without_replacing_best(self):
calls = 0
def changes(value, _):
nonlocal calls
calls += 1
return -1 if calls == 1 else 1
self.write_config(target=1)
git(self.repo, "add", ".dev-workflows.toml")
git(self.repo, "commit", "-qm", "target-one")
with self.runner(changes):
result = loop.new_run(self.config)
self.assertEqual(result["status"], "success", result)
self.assertEqual([a["result"] for a in result["attempts"]], ["rejected", "accepted"])
self.assertIn("quality gate", result["attempts"][0]["reason"])
self.assertEqual(result["best_score"], "1")
self.assertEqual((self.repo / "calc.py").read_text(), "VALUE = 0\n")
def test_incomplete_gate_never_counts_as_success(self):
self.write_config(target=1, iterations=1)
git(self.repo, "add", ".dev-workflows.toml")
git(self.repo, "commit", "-qm", "one-iteration")
# No gitleaks in PATH: a security check is unverified, not green.
with patch.dict(os.environ, {"PATH": os.environ["PATH"].replace(str(self.bin) + os.pathsep, "")}), \
self.runner(lambda value, _: 1):
result = loop.new_run(self.config)
self.assertEqual(result["status"], "exhausted", result)
self.assertEqual(result["best_score"], "0")
self.assertIn("quality gate", result["attempts"][0]["reason"])
def test_tampered_config_in_candidate_is_rejected(self):
self.write_config(target=1, iterations=1)
git(self.repo, "add", ".dev-workflows.toml")
git(self.repo, "commit", "-qm", "one-iteration")
def tamper(value, cwd):
with (Path(cwd) / ".dev-workflows.toml").open("a") as f:
f.write("\n# altered by agent\n")
return 1
with self.runner(tamper):
result = loop.new_run(self.config)
self.assertEqual(result["status"], "exhausted", result)
self.assertEqual(result["attempts"][0]["result"], "rejected")
self.assertIn("protegido", result["attempts"][0]["reason"])
def test_redirected_git_pointer_cannot_stage_on_original_branch(self):
self.write_config(target=1, iterations=1)
git(self.repo, "add", ".dev-workflows.toml")
git(self.repo, "commit", "-qm", "one-iteration")
original = git(self.repo, "rev-parse", "HEAD")
def redirect(_value, cwd):
(Path(cwd) / ".git").write_text(f"gitdir: {self.repo / '.git'}\n")
return 1
with self.runner(redirect):
result = loop.new_run(self.config)
self.assertEqual(result["status"], "exhausted", result)
self.assertEqual(result["attempts"][0]["result"], "rejected")
self.assertIn("ponteiro .git", result["attempts"][0]["reason"])
self.assertEqual(git(self.repo, "rev-parse", "HEAD"), original)
self.assertEqual(git(self.repo, "status", "--porcelain"), "")
self.assertEqual((self.repo / "calc.py").read_text(), "VALUE = 0\n")
def test_ignored_agent_file_cannot_inflate_accepted_score(self):
(self.repo / ".gitignore").write_text("score.txt\n")
self.evaluator.write_text(self.evaluator.read_text().replace(
"value = runpy.run_path('calc.py')['VALUE']",
"value = int(pathlib.Path('score.txt').read_text()) if pathlib.Path('score.txt').exists() else 0"))
self.write_config(target=2, iterations=1)
git(self.repo, "add", "-A")
git(self.repo, "commit", "-qm", "ignore-uncommitted-score")
def inflate(_value, cwd):
(Path(cwd) / "score.txt").write_text("2\n")
return 1
with self.runner(inflate):
result = loop.new_run(self.config)
self.assertEqual(result["status"], "exhausted", result)
self.assertEqual(result["best_score"], "0")
self.assertEqual(result["attempts"][0]["result"], "rejected")
self.assertIn("score 0", result["attempts"][0]["reason"])
self.assertEqual((self.repo / "calc.py").read_text(), "VALUE = 0\n")
def test_missing_evidence_cannot_claim_improvement(self):
self.evaluator.write_text(self.evaluator.read_text().replace(
"'evidence': [str(evidence)]", "'evidence': [str(evidence)] if value == 0 else []"))
self.write_config(target=1, iterations=1)
git(self.repo, "add", ".dev-workflows.toml")
git(self.repo, "commit", "-qm", "evidence-required")
with self.runner(lambda _value, _cwd: 1):
result = loop.new_run(self.config)
self.assertEqual(result["status"], "paused", result)
self.assertEqual(result["best_score"], "0")
self.assertEqual(result["attempts"][0]["result"], "paused")
self.assertIn("evidência", result["attempts"][0]["reason"])
def test_dirty_tree_is_refused_and_preserved(self):
(self.repo / "calc.py").write_text("VALUE = 99\n")
with self.assertRaisesRegex(loop.LoopError, "alterações"):
loop.new_run(self.config)
self.assertFalse(self.state.exists())
self.assertEqual((self.repo / "calc.py").read_text(), "VALUE = 99\n")
def test_status_and_stop_work_after_unrelated_user_edit(self):
self.write_config(iterations=1)
git(self.repo, "add", ".dev-workflows.toml")
git(self.repo, "commit", "-qm", "one-iteration")
with self.runner(lambda value, _: value + 1):
result = loop.new_run(self.config)
self.assertEqual(result["status"], "exhausted")
(self.repo / "calc.py").write_text("VALUE = 99\n")
run_id = result["run_id"]
for action in ("status", "stop"):
with patch("sys.stdout", new_callable=io.StringIO) as captured:
exit_code = loop.main([action, "--config", str(self.config), "--run", run_id])
self.assertEqual(exit_code, 0)
self.assertEqual(json.loads(captured.getvalue())["best_score"], "1")
self.assertTrue((loop.state_root(self.repo) / run_id / "stop.requested").is_file())
self.assertEqual((self.repo / "calc.py").read_text(), "VALUE = 99\n")
def test_independent_review_failure_rejects_measured_gain(self):
self.write_config(target=1, tier=2, iterations=1)
git(self.repo, "add", ".dev-workflows.toml")
git(self.repo, "commit", "-qm", "review-required")
def invoke(tool, role, prompt, cwd, model_key, timeout=900, env=None):
if role == "implementer":
(Path(cwd) / "calc.py").write_text("VALUE = 1\n")
return {"returncode": 0, "output": "changed behavior", "usage": {}}
return {"returncode": 0, "output": '{"verdict":"fail","findings":["regression"]}'
if role == "reviewer" else "plan", "usage": {}}
actual_gate = loop.gate_result
# Keep a real passing gate; tier-2 scanners are not installed in the disposable app.
def gate_with_available_checks(repo, base, tier, required, changes, deadline=None):
return actual_gate(repo, base, 0, required, changes, deadline)
with (patch.dict(sys.modules, {"harness_runner": types.SimpleNamespace(invoke=invoke)}),
patch.object(loop, "gate_result", side_effect=gate_with_available_checks)):
result = loop.new_run(self.config)
self.assertEqual(result["status"], "exhausted", result)
self.assertEqual(result["best_score"], "0")
self.assertEqual(result["attempts"][0]["gate"]["checks"]["test"], "pass")
self.assertIn("reviewer", result["attempts"][0]["reason"])
def test_resume_after_interrupted_attempt_does_not_repeat_it(self):
self.write_config(target=1)
git(self.repo, "add", ".dev-workflows.toml")
git(self.repo, "commit", "-qm", "target-one")
def interrupt(_, __):
raise KeyboardInterrupt
with self.runner(interrupt), self.assertRaises(KeyboardInterrupt):
loop.new_run(self.config)
home = loop.state_root(self.repo)
folder = next(p for p in home.iterdir() if p.is_dir())
with self.runner(lambda value, _: 1):
result = loop.resume_run(self.config, folder.name)
self.assertEqual(result["status"], "success", result)
self.assertEqual([a["result"] for a in result["attempts"]], ["interrupted", "accepted"])
self.assertEqual(result["attempts"][-1]["iteration"], 2)
def test_fixed_zen_model_cannot_bypass_account_catalog(self):
self.write_config(target=1, billing="zen")
git(self.repo, "add", ".dev-workflows.toml")
git(self.repo, "commit", "-qm", "zen-config")
with self.runner(lambda value, _: 1), self.assertRaisesRegex(loop.LoopError, "OpenCode ou OMP"):
loop.new_run(self.config)
def test_unknown_paid_usage_blocks_resume_without_reauthorizing(self):
self.write_config(target=1, iterations=1)
self.config.write_text(self.config.read_text().replace("max_paid_usd = 0", "max_paid_usd = 1"))
git(self.repo, "add", ".dev-workflows.toml")
git(self.repo, "commit", "-qm", "paid-budget")
selected = {"model_key": "opencode/test", "billing_mode": "zen",
"balance_confirmed": True, "estimated_native_usd": "0.1"}
calls = 0
def invoke(_tool, _role, _prompt, cwd, _model_key, timeout=900, env=None):
nonlocal calls
calls += 1
(Path(cwd) / "calc.py").write_text("VALUE = 1\n")
return {"returncode": 0, "output": "changed behavior", "usage": None}
with (patch.object(loop, "role_model", return_value=selected),
patch.object(loop, "authorize"),
patch.dict(sys.modules, {"harness_runner": types.SimpleNamespace(invoke=invoke)})):
result = loop.new_run(self.config)
self.assertEqual(result["status"], "paused", result)
self.assertEqual(result["spent_paid_usd"], "0")
state = json.loads((loop.state_root(self.repo) / result["run_id"] / "state.json").read_text())
self.assertTrue(state["unreconciled_paid_call"])
with self.assertRaisesRegex(loop.LoopError, "concilie"):
loop.resume_run(self.config, result["run_id"])
self.assertEqual(calls, 1)
def test_go_requires_all_three_windows_and_disables_balance_fallback(self):
config = {"loop": {"max_paid_usd": 0}}
row = {"billing_mode": "go", "quota_window_remaining": {"5h": "1", "weekly": "1", "monthly": "1"},
"quota_window_debit": {"5h": "0.2", "weekly": "0.2", "monthly": "0.2"},
"use_balance_fallback": True}
with self.assertRaisesRegex(loop.SafetyPause, "fallback"):
loop.authorize(config, row, loop.Decimal(0))
row["use_balance_fallback"] = False
row["quota_window_remaining"]["weekly"] = "0"
with self.assertRaisesRegex(loop.SafetyPause, "três janelas"):
loop.authorize(config, row, loop.Decimal(0))
row["quota_window_remaining"]["weekly"] = "1"
loop.authorize(config, row, loop.Decimal(0))
def test_zen_needs_live_interactive_consent_not_stdin_yes(self):
config = {"loop": {"max_paid_usd": 1}}
row = {"billing_mode": "zen", "model_key": "opencode/test",
"estimated_native_usd": "0.2", "balance_confirmed": True}
with patch("sys.stdin", io.StringIO("SIM\n")), self.assertRaisesRegex(loop.SafetyPause, "interativa"):
loop.authorize(config, row, loop.Decimal(0))
if __name__ == "__main__":
unittest.main(verbosity=2)
+374
View File
@@ -0,0 +1,374 @@
#!/usr/bin/env python3
"""Behavior tests for model catalog imports and reports (stdlib only)."""
import hashlib
import json
import os
import shutil
import subprocess
import sys
import tempfile
import unittest
from decimal import Decimal
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, os.path.join(ROOT, "scripts"))
import model_catalog as catalog
class CatalogImportTests(unittest.TestCase):
def test_openrouter_keeps_per_token_units_and_missing_cache_is_not_free(self):
payload = {"data": [{"id": "z-ai/glm-5.3", "name": "GLM", "pricing": {
"prompt": "0.0000014", "completion": "0.0000044", "input_cache_read": "0.00000026"
}}]}
prices = catalog.parse_openrouter(payload)["z-ai/glm-5.3"]
self.assertEqual(prices["price_unit"], "USD/token")
self.assertEqual(prices["price_per_token_usd"]["input"], "0.0000014")
self.assertEqual(Decimal(prices["display_usd_per_1m"]["input"]), Decimal("1.4"))
self.assertEqual(Decimal(prices["display_usd_per_1m"]["cache_read"]), Decimal("0.26"))
self.assertIsNone(prices["display_usd_per_1m"]["cache_write"])
self.assertIsNone(catalog.reference_cost(prices["price_per_token_usd"], {"cache_write": 1}))
self.assertEqual(catalog.reference_cost(prices["price_per_token_usd"], {"input": 1_000_000, "output": 10_000}), Decimal("1.444"))
def test_negative_public_tariff_keeps_valid_models_and_is_not_costed(self):
payload = {"data": [
{"id": "openrouter/auto-beta", "pricing": {"prompt": "-0.000001", "completion": "0.1"}},
{"id": "openai/valid", "pricing": {"prompt": "0.000002", "completion": "0.000003"}},
]}
parsed = catalog.parse_openrouter(payload)
self.assertEqual(catalog.reference_cost(parsed["openai/valid"]["price_per_token_usd"],
{"input": 1_000_000}), Decimal("2"))
invalid = parsed["openrouter/auto-beta"]
self.assertEqual(invalid["conditions"]["unsupported_negative_prices"]["input"], "-0.000001")
self.assertIsNone(invalid["price_per_token_usd"]["input"])
self.assertIsNone(catalog.reference_cost(invalid["price_per_token_usd"], {"input": 1}))
with self.assertRaises(ValueError):
catalog.parse_openrouter(payload, {"openai/valid": {"price_per_token_usd": {"input": "-1"},
"source_url": "https://example.test/pricing", "captured_at": "2026-09-25T00:00:00Z"}})
def test_openrouter_price_overrides_preserve_conditions_and_unit(self):
payload = {"data": [{"id": "openai/gpt-6-luna", "pricing": {"prompt": "0.1", "completion": "0.5"}, "context_length": 272000}]}
overrides = {"openai/gpt-6-luna": {
"display_usd_per_1m": {"input": "2.25", "output": "7.5"},
"context_length": 272000, "ttl": "1h", "endpoint": "https://example.test/v2",
"source_url": "https://example.test/pricing", "captured_at": "2026-09-25T00:00:00Z"
}}
record = catalog.parse_openrouter(payload, overrides)["openai/gpt-6-luna"]
self.assertEqual(record["price_per_token_usd"]["input"], "0.00000225")
self.assertEqual(Decimal(record["display_usd_per_1m"]["output"]), Decimal("7.5"))
self.assertEqual(record["conditions"]["context_length"], 272000)
self.assertEqual(record["conditions"]["ttl"], "1h")
self.assertEqual(record["conditions"]["endpoint"], "https://example.test/v2")
with self.assertRaises(ValueError):
catalog.parse_openrouter(payload, {"missing/model": {"display_usd_per_1m": {"input": "1"}}})
def test_context_and_cache_ttl_overrides_choose_the_matching_price_tier(self):
payload = {"data": [{"id": "openai/gpt-6-luna", "pricing": {
"prompt": "0.0000001", "completion": "0.0000005",
"input_cache_write": "0.0000009", "input_cache_write_1h": "0.0000005"
}}]}
tier = {"min_context_tokens": 272001, "price_per_token_usd": {"input": "0.0000002", "output": "0.0000008"},
"source_url": "https://openrouter.ai/docs/pricing", "captured_at": "2026-09-25T00:00:00Z"}
record = catalog.parse_openrouter(payload, {"openai/gpt-6-luna": {"context_tiers": [tier]}})["openai/gpt-6-luna"]
below = catalog.openrouter_price_for_profile(record, {"context_length": 272000})
above = catalog.openrouter_price_for_profile(record, {"context_length": 272001})
self.assertEqual(below["price_per_token_usd"]["input"], "0.0000001")
self.assertEqual(above["price_per_token_usd"]["input"], "0.0000002")
self.assertEqual(above["applied_context_tier"], 272001)
self.assertEqual(catalog.reference_cost(record["price_per_token_usd"], {"cache_write": 100, "cache_write_ttl": "1h"}), Decimal("0.00005"))
def test_provider_catalog_preserves_exact_variants_without_guessing(self):
rows = catalog.parse_provider_catalog({"data": [
{"id": "model-x", "name": "X", "variants": ["high", "max"]},
{"id": "model-y"}
]}, "opencode", catalog.ZEN_URL)
self.assertEqual([r["model_key"] for r in rows], ["opencode/model-x#high", "opencode/model-x#max", "opencode/model-y"])
self.assertTrue(all(r["availability"]["authenticated"] is None for r in rows))
with self.assertRaises(ValueError):
catalog.parse_provider_catalog({"data": [{"id": "bad/id"}]}, "opencode", catalog.ZEN_URL)
def test_aa_import_requires_consent_provenance_and_one_consistent_v15_record(self):
snapshot = {
"metric_id": catalog.AA_METRIC, "version": "1.5", "ingestion": "manual_audited",
"terms_accepted": True, "source_url": catalog.AA_URL, "attribution": "Artificial Analysis Coding Agent Index",
"captured_at": "2026-09-25T00:00:00Z", "records": [{
"provider": "opencode", "model_id": "gpt-6-luna", "variant": "max", "score": "41",
"agent": "Codex", "harness": "Codex", "settings": {"effort": "max"},
"match_grade": "proxy", "evidence_url": catalog.AA_URL
}]
}
row = catalog.validate_aa_snapshot(snapshot)[0]
self.assertEqual((row["metric_id"], row["version"], row["score"], row["match_grade"]), (catalog.AA_METRIC, "1.5", "41", "proxy"))
wrong_index = dict(snapshot, metric_id="artificial_analysis_intelligence_index")
with self.assertRaises(ValueError):
catalog.validate_aa_snapshot(wrong_index)
duplicate = dict(snapshot, records=snapshot["records"] * 2)
with self.assertRaisesRegex(ValueError, "inconsistente"):
catalog.validate_aa_snapshot(duplicate)
no_consent = dict(snapshot, terms_accepted=False)
with self.assertRaises(ValueError):
catalog.validate_aa_snapshot(no_consent)
def test_local_discovery_never_returns_diagnostics_or_credential_text(self):
class Result:
returncode = 0
stdout = "opencode/model-a#high\nAPI_KEY=do-not-store\n"
stderr = "secret=do-not-print"
result = catalog.discover_local_models("opencode", runner=lambda *args, **kwargs: Result())
self.assertEqual(result["models"], ["model-a#high"])
self.assertNotIn("do-not-store", json.dumps(result))
self.assertNotIn("do-not-print", json.dumps(result))
def test_omp_json_is_local_listing_only_and_never_proves_entitlement(self):
payload = {"models": [{"provider": "openai", "id": "gpt-6-luna", "thinking": ["high"]}]}
rows = catalog.parse_omp_models(payload, "openai")
self.assertEqual(rows[0]["model_key"], "openai/gpt-6-luna")
self.assertIsNone(rows[0]["availability"]["authenticated"])
self.assertIsNone(rows[0]["availability"]["entitled"])
class Result:
returncode = 0
stdout = json.dumps(payload)
stderr = "account-private-value"
calls = []
result = catalog.discover_omp_models("openai", runner=lambda args, **kwargs: (calls.append(args) or Result()))
self.assertEqual(calls, [["omp", "models", "openai", "--json"]])
self.assertEqual(result["models"], ["openai/gpt-6-luna", "openai/gpt-6-luna#high"])
self.assertNotIn("account-private-value", json.dumps(result))
def test_omp_keeps_slash_ids_and_only_lists_advertised_thinking(self):
payload = {"models": [
{"provider": "openai", "id": "anthropic/claude-x",
"selector": "openai/anthropic/claude-x", "thinking": ["low", "high"]}
]}
rows = catalog.parse_omp_models(payload, "openai")
self.assertEqual([row["model_key"] for row in rows], ["openai/anthropic/claude-x"])
self.assertEqual(rows[0]["model_id"], "anthropic/claude-x")
class Result:
returncode = 0
stdout = json.dumps(payload)
stderr = ""
discovered = catalog.discover_omp_models("openai", runner=lambda *args, **kwargs: Result())
self.assertEqual(discovered["models"], [
"openai/anthropic/claude-x", "openai/anthropic/claude-x#high", "openai/anthropic/claude-x#low"
])
with self.assertRaises(ValueError):
catalog.parse_omp_models({"models": [{"provider": "openai", "id": "anthropic/claude-x",
"selector": "openai/claude-x"}]}, "openai")
def test_openrouter_public_long_context_override_affects_reference_cost(self):
record = catalog.parse_openrouter({"data": [{"id": "anthropic/model-x", "pricing": {
"prompt": "0.000001", "completion": "0.000002",
"overrides": [{"min_prompt_tokens": 272000, "prompt": "0.000003", "completion": "0.000004"}]
}}]})["anthropic/model-x"]
selected = catalog.openrouter_price_for_profile(record, {"input": 272000})
self.assertEqual(selected["price_per_token_usd"]["input"], "0.000003")
self.assertEqual(catalog.reference_cost(selected["price_per_token_usd"],
{"input": 272000, "output": 10}), Decimal("0.81604"))
def test_omp_sync_requires_manual_account_and_balance_evidence(self):
with tempfile.TemporaryDirectory() as cache:
availability_path = os.path.join(cache, "availability.json")
native_path = os.path.join(cache, "overrides.json")
aa_path = os.path.join(cache, "aa.json")
timestamp = catalog.utc_now()
with open(availability_path, "w", encoding="utf-8") as stream:
json.dump({
"tool": "omp", "ingestion": "manual_audited", "user_confirmed": True,
"captured_at": timestamp, "records": [{
"provider": "openai", "model_id": "gpt-6-luna", "variant": "high",
"local_listed": True, "authenticated": True, "entitled": True,
"verified_at": timestamp, "source": "manual audited OMP account",
"balance_confirmed": True, "balance_verified_at": timestamp,
}],
}, stream)
with open(native_path, "w", encoding="utf-8") as stream:
json.dump({"native_tariffs": {"openai/gpt-6-luna#high": {
"billing_mode": "omp_payg", "account_confirmed": True,
"source_url": "https://provider.example/pricing", "captured_at": timestamp,
"price_per_token_usd": {"input": "0.000001"}, "available_balance_usd": "2",
}}}, stream)
with open(aa_path, "w", encoding="utf-8") as stream:
json.dump({
"metric_id": catalog.AA_METRIC, "version": "1.5", "ingestion": "manual_audited",
"terms_accepted": True, "source_url": catalog.AA_URL,
"attribution": "Artificial Analysis Coding Agent Index", "captured_at": timestamp,
"records": [{
"provider": "openai", "model_id": "gpt-6-luna", "variant": "high", "score": "54",
"agent": "Codex", "harness": "OMP", "settings": {"effort": "high"},
"match_grade": "exact", "evidence_url": catalog.AA_URL,
}, {
"provider": "openai", "model_id": "gpt-6-luna", "variant": "xhigh", "score": "60",
"agent": "Codex", "harness": "OMP", "settings": {"effort": "xhigh"},
"match_grade": "exact", "evidence_url": catalog.AA_URL,
}],
}, stream)
rows = catalog.parse_omp_models({"models": [{"provider": "openai", "id": "gpt-6-luna",
"thinking": ["high"]}]}, "openai")
discover = lambda provider: {"ok": True, "models": ["openai/gpt-6-luna", "openai/gpt-6-luna#high"], "rows": rows,
"source_hash": "a" * 64, "verified_at": timestamp, "reason": None}
fetched = []
def fetcher(url):
fetched.append(url)
payload = {"data": []}
return payload, url, catalog.sha256(catalog.canonical_json(payload))
result = catalog.sync("omp", ["openai"], cache, fetcher, aa_snapshot=aa_path,
availability_snapshot=availability_path, price_overrides=native_path,
omp_discoverer=discover)
snapshot = catalog.load_snapshot("omp", cache)
by_key = {row["model_key"]: row for row in snapshot["models"]}
self.assertNotIn("openai/gpt-6-luna#xhigh", by_key)
self.assertEqual(result["model_count"], 2)
self.assertEqual(fetched, [catalog.OPENROUTER_URL])
model = by_key["openai/gpt-6-luna#high"]
self.assertEqual(model["score"]["version"], "1.5")
self.assertEqual(model["billing_mode"], "omp_payg")
self.assertTrue(model["availability"]["local_listed"])
self.assertTrue(model["availability"]["entitled"])
self.assertTrue(model["availability"]["balance_confirmed"])
self.assertEqual(model["native_tariff"]["available_balance_usd"], "2")
with self.assertRaisesRegex(ValueError, "providers explicitamente"):
catalog.sync("omp", cache_dir=cache, fetcher=lambda url: ({}, url, "x"))
with self.assertRaises(ValueError):
catalog.validate_native_tariff_overrides({"openai/model": {
"billing_mode": "omp_payg", "account_confirmed": True,
"source_url": "https://provider.example/pricing", "captured_at": "2026-09-25T12:00:00Z",
"price_per_token_usd": {"input": "0.1"},
}})
def test_manual_availability_and_native_tariff_are_auditable_without_secrets(self):
with tempfile.TemporaryDirectory() as cache:
availability = os.path.join(cache, "availability.json")
with open(availability, "w", encoding="utf-8") as stream:
json.dump({
"tool": "opencode", "ingestion": "manual_audited", "user_confirmed": True,
"captured_at": "2026-09-25T00:00:00Z",
"records": [{"provider": "opencode", "model_id": "model-a", "variant": None,
"local_listed": True, "authenticated": True, "entitled": True,
"verified_at": "2026-09-25T00:00:00Z", "source": "manual confirmation token=NEVER_PERSIST"}]
}, stream)
def fetcher(url):
body = {"data": [{"id": "model-a"}]} if url == catalog.ZEN_URL else {"data": []}
return body, url, catalog.sha256(catalog.canonical_json(body))
catalog.sync("opencode", ("opencode",), cache, fetcher,
lambda provider: {"ok": True, "models": ["model-a"], "reason": None},
availability_snapshot=availability)
snapshot = catalog.load_snapshot(cache_dir=cache)
model = snapshot["models"][0]
self.assertEqual(model["availability"]["authenticated"], True)
self.assertEqual(model["availability"]["entitled"], True)
self.assertEqual(model["availability"]["source"], "manual_audited")
self.assertNotIn("NEVER_PERSIST", json.dumps(snapshot))
self.assertIn("availability", snapshot["source_hashes"])
tariff = catalog.validate_native_tariff_overrides({"opencode/model-a": {
"billing_mode": "zen_balance", "account_confirmed": True, "source_url": "https://opencode.ai/docs/zen",
"captured_at": "2026-09-25T00:00:00Z", "price_per_token_usd": {"input": "0.000001", "output": "0.000002"},
"available_balance_usd": "2",
}})
self.assertEqual(tariff["opencode/model-a"]["price_per_token_usd"]["input"], "0.000001")
self.assertEqual(tariff["opencode/model-a"]["available_balance_usd"], "2")
with self.assertRaisesRegex(ValueError, "saldo disponível"):
catalog.validate_native_tariff_overrides({"opencode/model-a": {
"billing_mode": "zen_balance", "account_confirmed": True, "source_url": "https://opencode.ai/docs/zen",
"captured_at": "2026-09-25T00:00:00Z", "price_per_token_usd": {"input": "0.000001"},
}})
def test_unknown_openrouter_id_override_is_rejected(self):
payload = {"data": [{"id": "known/id", "pricing": {}}]}
with self.assertRaises(ValueError):
catalog.parse_openrouter(payload, {"typo/id": {"context_length": 100}})
class CatalogSnapshotTests(unittest.TestCase):
def test_missing_cache_and_complete_report_keep_unavailable_models(self):
with tempfile.TemporaryDirectory() as cache:
self.assertEqual(catalog.list_models(cache_dir=cache), [])
self.assertEqual(catalog._csv_text([]).splitlines()[0].split(","), list(catalog.LIST_FIELDS))
source_catalogs = {
catalog.ZEN_URL: {"data": [{"id": "glm-5.3", "name": "GLM"}, {"id": "unknown-model", "name": "Unknown"}]},
catalog.GO_URL: {"data": [{"id": "gpt-6-luna", "name": "Luna"}]},
catalog.OPENROUTER_URL: {"data": [{"id": "z-ai/glm-5.3", "pricing": {"prompt": "0.0000014", "completion": "0.0000044"}},
{"id": "openai/gpt-6-luna", "pricing": {"prompt": "0.0000001", "completion": "0.0000005"}}]},
}
def fetcher(url):
body = source_catalogs[url]
return body, url, catalog.sha256(catalog.canonical_json(body))
def local(provider):
ids = ["glm-5.3"] if provider == "opencode" else []
return {"ok": True, "models": ids, "reason": None}
result = catalog.sync("opencode", ("opencode", "opencode-go"), cache, fetcher, local)
rows = catalog.list_models(cache_dir=cache)
self.assertEqual(result["model_count"], 3)
self.assertEqual(len(rows), 3)
by_key = {row["model_key"]: row for row in rows}
self.assertEqual(by_key["opencode/glm-5.3"]["disponivel_na_conta"], "n/d")
self.assertEqual(by_key["opencode/unknown-model"]["openrouter_id"], "n/d")
self.assertEqual(by_key["opencode/unknown-model"]["preco_or_entrada_usd_1m"], "n/d")
self.assertEqual(by_key["opencode-go/gpt-6-luna"]["coding_index_nota"], "n/d")
self.assertFalse(by_key["opencode-go/gpt-6-luna"]["disponivel_na_conta"])
self.assertEqual(len(catalog.list_models(cache_dir=cache, show_missing=False)), 1)
self.assertEqual(Decimal(by_key["opencode/glm-5.3"]["preco_or_entrada_usd_1m"]), Decimal("1.4"))
def test_archived_cli_csv_reproduces_frozen_bytes_at_capture_time(self):
archived_snapshot = os.path.join(ROOT, "docs", "model-catalog-snapshot-2026-09-25", "catalog-opencode.json")
archived_csv = os.path.join(ROOT, "docs", "model-catalog-zen-go-2026-09-25.csv")
with tempfile.TemporaryDirectory() as cache:
shutil.copyfile(archived_snapshot, os.path.join(cache, "catalog-opencode.json"))
result = subprocess.run([
sys.executable, os.path.join(ROOT, "scripts", "model_catalog.py"), "list",
"--tool", "opencode", "--format", "csv", "--cache-dir", cache,
"--as-of-utc", "2026-09-25T07:18:38Z",
], capture_output=True, check=True)
with open(archived_csv, "rb") as stream:
expected = stream.read()
self.assertEqual(hashlib.sha256(expected).hexdigest(),
"80e2930877b20e5c47d4fd18f394c17a4683b257ca715496e91c63520d528230")
self.assertEqual(result.stdout, expected)
self.assertEqual(len(result.stdout.splitlines()) - 1, 122)
def test_archived_openrouter_override_changes_long_context_cost(self):
cache = os.path.join(ROOT, "docs", "model-catalog-snapshot-2026-09-25")
record = catalog.load_snapshot(cache_dir=cache)["openrouter"]["openai/gpt-6-sol"]
below = catalog.openrouter_price_for_profile(record, {"input": 271999})
above = catalog.openrouter_price_for_profile(record, {"input": 300000})
self.assertEqual(catalog.reference_cost(below["price_per_token_usd"], {"input": 271999}),
Decimal("0.543998"))
self.assertEqual(above["applied_context_tier"], 272000)
self.assertEqual(catalog.reference_cost(above["price_per_token_usd"], {"input": 300000}),
Decimal("1.2"))
def test_go_report_shows_all_confirmed_quota_windows_and_fallback_policy(self):
with tempfile.TemporaryDirectory() as cache:
timestamp = catalog.utc_now()
native_path = os.path.join(cache, "quota.json")
with open(native_path, "w", encoding="utf-8") as stream:
json.dump({"native_tariffs": {"opencode-go/model-a": {
"billing_mode": "go_quota", "account_confirmed": True,
"source_url": "https://opencode.ai/docs/go", "captured_at": timestamp,
"quota_window_remaining": {"5h": "2", "weekly": "5", "monthly": "10"},
"quota_window_debit": {"5h": "0.5", "weekly": "0.5", "monthly": "0.5"},
"use_balance_fallback": False,
}}}, stream)
def fetcher(url):
body = {"data": [{"id": "model-a"}]} if url == catalog.GO_URL else {"data": []}
return body, url, catalog.sha256(catalog.canonical_json(body))
catalog.sync("opencode", ("opencode-go",), cache, fetcher,
lambda _: {"ok": True, "models": ["model-a"], "reason": None},
price_overrides=native_path)
report = catalog.list_models(cache_dir=cache)[0]["preco_native_ou_cota"]
self.assertEqual(report["quota_window_remaining"], {"5h": "2", "weekly": "5", "monthly": "10"})
self.assertEqual(report["quota_window_debit"]["monthly"], "0.5")
self.assertFalse(report["use_balance_fallback"])
def test_score_bands_are_fixed_inclusive_only_at_high_upper_bound(self):
cases = {"9.99": None, "10": "leve", "19.99": "leve", "20": "media", "49.99": "media", "50": "alta", "100": "alta", "100.01": None}
for score, expected in cases.items():
self.assertEqual(catalog.band_for_score(score), expected)
if __name__ == "__main__":
unittest.main(verbosity=1)
+260
View File
@@ -0,0 +1,260 @@
#!/usr/bin/env python3
"""Behavior tests for role routing, spending boundaries, and deterministic ties."""
import os
import json
import sys
import tempfile
import unittest
from datetime import datetime, timezone
from decimal import Decimal
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, os.path.join(ROOT, "scripts"))
import model_catalog
import model_router
NOW = datetime(2026, 9, 25, 12, 0, tzinfo=timezone.utc)
NOW_TEXT = "2026-09-25T12:00:00Z"
def candidate(model_key, *, provider="opencode", score="45", native_input="0.0000001", billing="zen_balance", **extra):
result = {
"tool": "opencode", "model_key": model_key, "provider": provider,
"model_id": model_key.split("/", 1)[-1], "variant": None, "billing_mode": billing,
"availability": {"local_listed": True, "authenticated": True, "entitled": True, "verified_at": NOW_TEXT,
"local_verified_at": NOW_TEXT, "account_verified_at": NOW_TEXT,
"balance_confirmed": True, "balance_verified_at": NOW_TEXT},
"score": {"metric_id": model_catalog.AA_METRIC, "version": "1.5", "score": score,
"agent": "Codex", "harness": "OpenCode", "variant": None, "settings": {"effort": "max"},
"match_grade": "exact", "source_url": model_catalog.AA_URL, "observed_at": NOW_TEXT},
"openrouter": {"captured_at": NOW_TEXT, "price_per_token_usd": {"input": "0.0000001", "output": "0.0000005"}},
"native_tariff": {"billing_mode": billing, "account_confirmed": True, "source_url": "https://opencode.ai/docs/zen",
"captured_at": NOW_TEXT, "available_balance_usd": "2",
"price_per_token_usd": {"input": native_input, "output": "0.0000002",
"cache_read": "0.00000001", "cache_write": "0.00000002"}},
}
if billing == "go_quota":
result["quota_verified_at"] = NOW_TEXT
result["quota_source_url"] = "https://opencode.ai/docs/go"
result["use_balance_fallback"] = False
result.update(extra)
return result
class RoutePolicyTests(unittest.TestCase):
def test_missing_cache_is_explicit_and_no_model_is_invented(self):
with tempfile.TemporaryDirectory() as cache:
result = model_router.route_from_catalog("opencode", "implementer", ["opencode"], cache)
self.assertIsNone(result["selected"])
self.assertIn("snapshot_de_catalogo_ausente", result["reason"])
empty = model_router.route([], "explorer", allowed_providers=["opencode"], now=NOW)
self.assertIsNone(empty["selected"])
self.assertEqual(empty["reason"], "no_scored_candidate")
high_only = model_router.route([candidate("opencode/high-only", score="54")], "implementer",
allowed_providers=["opencode"], budget_usd="1", now=NOW)
self.assertIsNone(high_only["selected"])
self.assertEqual(high_only["reason"], "faixa_vazia:media")
def test_benchmark_with_wrong_index_is_never_ranked(self):
row = candidate("opencode/model-a", score="54")
row["score"]["metric_id"] = "artificial_analysis_intelligence_index"
result = model_router.route([row], "planner", allowed_providers=["opencode"], now=NOW)
self.assertIsNone(result["selected"])
self.assertEqual(result["ranking"][0]["eligible"], False)
self.assertIn("indice_incompativel_ou_ausente", result["ranking"][0]["exclusion_reasons"])
def test_role_band_precedes_cost_and_plateau_uses_native_cost_not_openrouter(self):
cheap_high = candidate("opencode/high", score="54", native_input="0.000000001")
media_best = candidate("opencode/media", score="49", native_input="0.0000001")
media_cheaper = candidate("opencode/media-cheap", score="47", native_input="0.00000005")
result = model_router.route([cheap_high, media_best, media_cheaper], "implementer", allowed_providers=["opencode"],
tokens={"input": 1_000_000}, budget_usd="0.08", now=NOW)
self.assertEqual(result["selected"]["model_key"], "opencode/media-cheap")
self.assertEqual(result["selected"]["band"], "media")
self.assertEqual(Decimal(result["selected"]["reference_cost_usd"]), Decimal("0.1"))
self.assertEqual(Decimal(result["selected"]["estimated_native_usd"]), Decimal("0.05"))
self.assertIn("platô", result["reason"])
def test_zen_balance_must_cover_native_estimate_and_be_confirmed(self):
row = candidate("opencode/model-a")
row["native_tariff"]["available_balance_usd"] = "0.05"
result = model_router.route([row], "implementer", allowed_providers=["opencode"],
tokens={"input": 1_000_000}, budget_usd="1", now=NOW)
self.assertIsNone(result["selected"])
self.assertIn("saldo_insuficiente", result["ranking"][0]["exclusion_reasons"])
row["native_tariff"]["available_balance_usd"] = "1"
row["availability"]["balance_confirmed"] = False
result = model_router.route([row], "implementer", allowed_providers=["opencode"],
tokens={"input": 1_000_000}, budget_usd="1", now=NOW)
self.assertIsNone(result["selected"])
self.assertIn("saldo_nao_confirmado_ou_obsoleto", result["ranking"][0]["exclusion_reasons"])
def test_zen_balance_requires_explicit_budget(self):
row = candidate("opencode/model-a")
result = model_router.route([row], "implementer", allowed_providers=["opencode"], now=NOW)
self.assertIsNone(result["selected"])
self.assertIn("orcamento_zen_nao_configurado", result["ranking"][0]["exclusion_reasons"])
def test_exact_benchmark_harness_must_match_tool_but_proxy_requires_approval(self):
row = candidate("opencode/model-a")
row["score"]["harness"] = "Codex"
result = model_router.route([row], "implementer", allowed_providers=["opencode"],
tokens={"input": 100_000}, budget_usd="1", now=NOW)
self.assertIsNone(result["selected"])
self.assertIn("harness_incompativel", result["ranking"][0]["exclusion_reasons"])
row["score"]["match_grade"] = "proxy"
result = model_router.route([row], "implementer", allowed_providers=["opencode"],
tokens={"input": 100_000}, budget_usd="1", now=NOW)
self.assertIsNone(result["selected"])
self.assertIn("match_proxy_nao_autorizado", result["ranking"][0]["exclusion_reasons"])
approved = model_router.route([row], "implementer", allowed_providers=["opencode"],
tokens={"input": 100_000}, budget_usd="1", allow_proxy=True, now=NOW)
self.assertEqual(approved["selected"]["model_key"], "opencode/model-a")
def test_budget_is_applied_before_plateau_and_proxy_requires_explicit_permission(self):
top = candidate("opencode/top", score="49", native_input="0.000001")
lower = candidate("opencode/lower", score="46", native_input="0.00000005")
row = candidate("opencode/proxy", score="45", match="proxy")
row["score"]["match_grade"] = "proxy"
result = model_router.route([top, lower, row], "implementer", allowed_providers=["opencode"],
tokens={"input": 1_000_000}, budget_usd="0.1", now=NOW)
self.assertEqual(result["selected"]["model_key"], "opencode/lower")
exclusions = {entry["model_key"]: entry["exclusion_reasons"] for entry in result["ranking"]}
self.assertIn("match_proxy_nao_autorizado", exclusions["opencode/proxy"])
proxy = model_router.route([row], "implementer", allowed_providers=["opencode"], tokens={"input": 1_000_000},
budget_usd="1", allow_proxy=True, now=NOW)
self.assertEqual(proxy["selected"]["model_key"], "opencode/proxy")
def test_unknown_entitlement_and_provider_are_not_eligible(self):
row = candidate("opencode/model-a", score="54")
row["availability"]["entitled"] = None
result = model_router.route([row], "planner", allowed_providers=["opencode"], now=NOW)
self.assertIsNone(result["selected"])
self.assertIn("entitlement_nao_confirmado", result["ranking"][0]["exclusion_reasons"])
unauthorized = model_router.route([candidate("opencode/model-a", score="54")], "planner", now=NOW)
self.assertIn("provider_nao_autorizado", unauthorized["reason"])
def test_go_quota_checks_every_window_and_never_falls_back_to_zen(self):
for window in model_router.WINDOWS:
row = candidate("opencode-go/model-a", provider="opencode-go", score="54", billing="go_quota")
row["quota_window_remaining"] = {"5h": "1", "weekly": "1", "monthly": "1"}
row["quota_window_debit"] = {"5h": "0.1", "weekly": "0.1", "monthly": "0.1"}
row["quota_window_remaining"][window] = "0.05"
result = model_router.route([row], "planner", allowed_providers=["opencode-go"], tokens={"input": 1_000_000}, now=NOW)
self.assertIsNone(result["selected"], window)
self.assertIn("quota_go_insuficiente", result["reason"])
row = candidate("opencode-go/model-a", provider="opencode-go", score="54", billing="go_quota")
row["quota_window_remaining"] = {"5h": "1", "weekly": "1", "monthly": "1"}
row["quota_window_debit"] = {"5h": "0.1", "weekly": "0.1", "monthly": "0.1"}
row["use_balance_fallback"] = True
result = model_router.route([row], "planner", allowed_providers=["opencode-go"], tokens={"input": 1_000_000}, now=NOW)
self.assertIsNone(result["selected"])
self.assertEqual(result["reason"], "fallback_go_para_saldo_zen_nao_autorizado")
def test_go_success_exposes_quota_and_billing_mode_separately(self):
row = candidate("opencode-go/model-a", provider="opencode-go", score="54", billing="go_quota")
row["quota_window_remaining"] = {"5h": "1", "weekly": "2", "monthly": "3"}
row["quota_window_debit"] = {"5h": "0.1", "weekly": "0.1", "monthly": "0.2"}
result = model_router.route([row], "planner", allowed_providers=["opencode-go"], tokens={"input": 1_000_000}, now=NOW)
selected = result["selected"]
self.assertEqual(selected["billing_mode"], "go")
self.assertEqual(selected["billing_mode_detail"], "go_quota")
self.assertEqual(selected["quota_window_debit"]["monthly"], "0.2")
self.assertIsNone(selected["estimated_native_usd"])
self.assertEqual(selected["native_cost_or_quota_debit_usd"], "0.2")
def test_missing_cache_rate_disables_comparative_cost_not_native_selection(self):
row = candidate("opencode/model-a", score="45")
row["openrouter"]["price_per_token_usd"] = {"input": "0.0000001"}
result = model_router.route([row], "implementer", allowed_providers=["opencode"],
tokens={"input": 1_000_000, "cache_read": 1000}, budget_usd="1", now=NOW)
self.assertEqual(result["selected"]["model_key"], "opencode/model-a")
self.assertIsNone(result["selected"]["reference_cost_usd"])
self.assertEqual(Decimal(result["selected"]["estimated_native_usd"]), Decimal("0.10001"))
def test_expired_paid_metadata_blocks_automatic_selection(self):
row = candidate("opencode/model-a", score="54")
row["openrouter"]["captured_at"] = "2026-09-23T00:00:00Z"
result = model_router.route([row], "planner", allowed_providers=["opencode"], budget_usd="1", now=NOW)
self.assertIsNone(result["selected"])
self.assertIn("preco_referencial_obsoleto_ou_ausente", result["ranking"][0]["exclusion_reasons"])
def test_ties_are_deterministic_independent_of_input_order(self):
a = candidate("opencode/a", score="48", native_input="0.00000005")
b = candidate("opencode/b", score="48", native_input="0.00000005")
first = model_router.route([a, b], "implementer", allowed_providers=["opencode"], tokens={"input": 1_000_000}, budget_usd="1", now=NOW)
second = model_router.route([b, a], "implementer", allowed_providers=["opencode"], tokens={"input": 1_000_000}, budget_usd="1", now=NOW)
self.assertEqual(first, second)
self.assertEqual(first["selected"]["model_key"], "opencode/a")
def test_fixed_bands_metric_and_role_override_contract(self):
self.assertEqual(model_router.validate_bands({"leve": [10, 20], "media": [20, 50], "alta": [50, 100]}),
model_router.FIXED_BANDS)
with self.assertRaises(ValueError):
model_router.validate_bands({"leve": [0, 20], "media": [20, 50], "alta": [50, 100]})
row = candidate("opencode/model-a", score="54")
result = model_router.route([row], "implementer", allowed_providers=["opencode"],
band_override="alta", tokens={"input": 1_000_000}, budget_usd="1", now=NOW)
self.assertEqual(result["selected"]["band"], "alta")
with self.assertRaises(ValueError):
model_router.route([row], "planner", allowed_providers=["opencode"],
benchmark_metric="aa_coding_agent_index_v1.4", now=NOW)
def test_omp_payg_uses_only_native_estimate_and_exact_dispatch_variant(self):
row = candidate("openai/model-a#high", provider="openai", score="54", billing="omp_payg")
row.update({"tool": "omp", "model_id": "model-a", "variant": "high"})
row["score"]["harness"] = "OMP"
row["score"]["variant"] = "high"
row["openrouter"] = None
row["native_tariff"] = {
"billing_mode": "omp_payg", "account_confirmed": True,
"source_url": "https://provider.example/pricing", "captured_at": NOW_TEXT,
"price_per_token_usd": {"input": "0.000001"}, "available_balance_usd": "0.2",
}
result = model_router.route([row], "planner", allowed_providers=["openai"],
tokens={"input": 100_000}, budget_usd="0.2", now=NOW)
selected = result["selected"]
self.assertEqual(selected["model_key"], "openai/model-a#high")
self.assertEqual(selected["dispatch_model_key"], "openai/model-a:high")
self.assertEqual(selected["billing_mode"], "payg")
self.assertEqual(selected["estimated_native_usd"], "0.100000")
self.assertEqual(selected["available_balance_usd"], "0.2")
self.assertIsNone(selected["reference_cost_usd"])
row["availability"]["balance_confirmed"] = False
blocked = model_router.route([row], "planner", allowed_providers=["openai"],
tokens={"input": 100_000}, budget_usd="0.2", now=NOW)
self.assertIsNone(blocked["selected"])
self.assertIn("saldo_nao_confirmado_ou_obsoleto", blocked["ranking"][0]["exclusion_reasons"])
def test_omp_catalog_route_revalidates_local_list_and_keeps_manual_entitlement(self):
row = candidate("openai/model-a#high", provider="openai", score="54", billing="omp_payg")
row.update({"tool": "omp", "model_id": "model-a", "variant": "high"})
row["score"]["harness"] = "OMP"
row["score"]["variant"] = "high"
row["native_tariff"] = {
"billing_mode": "omp_payg", "account_confirmed": True,
"source_url": "https://provider.example/pricing", "captured_at": NOW_TEXT,
"price_per_token_usd": {"input": "0.000001"}, "available_balance_usd": "0.2",
}
with tempfile.TemporaryDirectory() as cache:
with open(os.path.join(cache, "catalog-omp.json"), "w", encoding="utf-8") as stream:
json.dump({"tool": "omp", "models": [row]}, stream)
result = model_router.route_from_catalog(
"omp", "planner", ["openai"], cache, tokens={"input": 100_000}, budget_usd="0.2",
omp_discoverer=lambda provider: {"ok": True, "models": ["openai/model-a#high"], "verified_at": NOW_TEXT},
now=NOW,
)
unsupported = model_router.route_from_catalog(
"omp", "planner", ["openai"], cache, tokens={"input": 100_000}, budget_usd="0.2",
omp_discoverer=lambda provider: {"ok": True, "models": ["openai/model-a"], "verified_at": NOW_TEXT},
now=NOW,
)
self.assertIsNone(unsupported["selected"])
self.assertIn("nao_listado_localmente", unsupported["ranking"][0]["exclusion_reasons"])
self.assertEqual(result["selected"]["dispatch_model_key"], "openai/model-a:high")
if __name__ == "__main__":
unittest.main(verbosity=1)
+45
View File
@@ -0,0 +1,45 @@
"""Ownership and safety behavior for native OMP package builds."""
import importlib.util
import tempfile
import unittest
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
SPEC = importlib.util.spec_from_file_location("omp_build", ROOT / "adapters" / "omp" / "build.py")
BUILD = importlib.util.module_from_spec(SPEC)
SPEC.loader.exec_module(BUILD)
class OmpAdapterTests(unittest.TestCase):
def setUp(self):
self.tmp = tempfile.TemporaryDirectory()
self.addCleanup(self.tmp.cleanup)
self.package = Path(self.tmp.name) / "dev-workflows"
BUILD.build_package(ROOT, self.package)
def test_refuses_to_replace_unowned_destination(self):
with tempfile.TemporaryDirectory() as tmp:
dest = Path(tmp) / "third-party"
dest.mkdir()
sentinel = dest / "keep"
sentinel.write_text("untouched")
with self.assertRaises(FileExistsError):
BUILD.build_package(ROOT, dest)
self.assertEqual(sentinel.read_text(), "untouched")
def test_preserves_manual_edits_in_managed_package(self):
prompt = self.package / "agents" / "planner.md"
prompt.write_text(prompt.read_text() + "\nMudança do usuário.\n")
with self.assertRaisesRegex(FileExistsError, "alterações manuais"):
BUILD.build_package(ROOT, self.package)
self.assertIn("Mudança do usuário.", prompt.read_text())
def test_rejects_invalid_model_selectors(self):
with tempfile.TemporaryDirectory() as tmp:
with self.assertRaises(ValueError):
BUILD.build_package(ROOT, Path(tmp) / "package", {"planner": "gpt-6-luna"})
if __name__ == "__main__":
unittest.main()
+825
View File
@@ -0,0 +1,825 @@
#!/usr/bin/env python3
"""Opt-in, evaluator-driven experiments in detached git worktrees.
The user's branch is never reset, staged, merged, or published. Agent output is
untrusted; only the external evaluator and current quality-gate report decide.
"""
import argparse
import contextlib
from decimal import Decimal, InvalidOperation
import fcntl
import hashlib
import json
import os
from pathlib import Path
import re
import subprocess
import sys
import time
import tomllib
import uuid
ROOT = Path(__file__).resolve().parent.parent
GATE = ROOT / "scripts" / "quality-gate"
MODEL_CATALOG = ROOT / "scripts" / "model_catalog.py"
class LoopError(Exception):
pass
class SafetyPause(LoopError):
"""The next model invocation is not authorized or cannot be budgeted."""
def command(argv, cwd, timeout=60, env=None):
try:
return subprocess.run(argv, cwd=cwd, env=env, text=True, capture_output=True, timeout=timeout)
except (OSError, subprocess.TimeoutExpired) as exc:
raise LoopError(f"falha ao executar {argv[0]}: {exc}") from exc
def sandbox_binary():
bwrap = next((path for path in ("/usr/bin/bwrap", "/bin/bwrap") if Path(path).is_file()), None)
if not bwrap:
raise LoopError("bubblewrap indisponível: não executar código do projeto sem isolamento")
return bwrap
def preflight_isolation(project):
"""Prove namespace support without modifying the project or invoking a model."""
result = command([sandbox_binary(), "--die-with-parent", "--new-session", "--unshare-net",
"--unshare-pid", "--ro-bind", "/", "/", "--dev-bind", "/dev", "/dev",
"--proc", "/proc", "--", "/usr/bin/true"], project, timeout=15)
if result.returncode:
raise LoopError(f"isolamento bubblewrap indisponível: {result.stderr.strip()[:300]}")
def isolated_command(argv, cwd, timeout=60, env=None, writable=()):
"""Run untrusted project checks with no network or write access outside mounts."""
bwrap = sandbox_binary()
repo = Path(cwd).resolve(strict=True)
home = repo / ".dev-workflows" / "sandbox-home"
home.mkdir(mode=0o700, parents=True, exist_ok=True)
child_env = dict(os.environ if env is None else env)
child_env.update(HOME=str(home), XDG_CACHE_HOME=str(home), TMPDIR=str(home),
PYTHONDONTWRITEBYTECODE="1")
marker = repo / ".git"
if marker.is_symlink() or not marker.is_file():
raise LoopError("sandbox exige ponteiro .git de worktree regular")
args = [bwrap, "--die-with-parent", "--new-session", "--unshare-net", "--unshare-pid",
"--ro-bind", "/", "/", "--dev-bind", "/dev", "/dev", "--proc", "/proc",
"--bind", str(repo), str(repo), "--ro-bind", str(marker), str(marker)]
for directory in writable:
resolved = Path(directory).resolve(strict=True)
if not resolved.is_dir():
raise LoopError(f"diretório de relatório inválido: {directory}")
args.extend(("--bind", str(resolved), str(resolved)))
args.extend(("--", *argv))
return command(args, repo, timeout, child_env)
def git(root, *args):
result = command(["git", *args], root)
if result.returncode:
raise LoopError(f"git {args[0]} falhou: {result.stderr.strip()[:300]}")
return result.stdout.strip()
def digest(path):
h = hashlib.sha256()
with open(path, "rb") as source:
for block in iter(lambda: source.read(1024 * 1024), b""):
h.update(block)
return h.hexdigest()
def number(value, name):
if isinstance(value, bool):
raise LoopError(f"{name}: número inválido")
try:
d = Decimal(str(value))
except (InvalidOperation, ValueError) as exc:
raise LoopError(f"{name}: número inválido") from exc
if not d.is_finite():
raise LoopError(f"{name}: número não finito")
return d
def bounded_timeout(limit, deadline=None):
if deadline is None:
return limit
remaining = deadline - time.time()
if remaining <= 0:
raise LoopError("limite global de tempo esgotado")
return min(limit, remaining)
def within(path, directory):
return path == directory or directory in path.parents
def config_at(config_path):
path = Path(config_path).resolve(strict=True)
with path.open("rb") as source:
config = tomllib.load(source)
top = Path(git(path.parent, "rev-parse", "--show-toplevel")).resolve()
if not within(path, top):
raise LoopError("configuração deve estar no repositório avaliado")
loop = config.get("loop", {})
goal = loop.get("goal", {})
evaluator = loop.get("evaluator", {})
if not goal.get("name") or not goal.get("unit") or goal.get("direction") not in ("maximize", "minimize"):
raise LoopError("[loop.goal] requer name, unit e direction maximize|minimize")
target = number(goal.get("target"), "target")
argv = evaluator.get("argv")
if not isinstance(argv, list) or not argv or any(not isinstance(x, str) or not x for x in argv):
raise LoopError("[loop.evaluator].argv deve ser uma lista de argumentos")
# An interpreter may precede the evaluator. The executable script must not
# come from the editable checkout; a bare command in PATH is not auditable.
candidate = argv[1] if Path(argv[0]).name in ("python", "python3", "node", "bun") and len(argv) > 1 else argv[0]
script = Path(candidate)
if not script.is_absolute() or not script.is_file():
raise LoopError("avaliador precisa ser arquivo absoluto existente fora do worktree")
script = script.resolve(strict=True)
if within(script, top):
raise LoopError("avaliador não pode residir no checkout editável")
expected = evaluator.get("trusted_sha256", "")
if not re.fullmatch(r"[0-9a-fA-F]{64}", expected) or digest(script) != expected.lower():
raise LoopError("hash aprovado do avaliador não corresponde ao arquivo")
required = evaluator.get("required_checks", [])
if not isinstance(required, list) or not required or any(not isinstance(x, str) or not x for x in required):
raise LoopError("required_checks deve listar os checks obrigatórios do gate")
if evaluator.get("require_gate_verdict", "pass") != "pass":
raise LoopError("loop exige veredito pass no quality gate")
tier = loop.get("tier", 2)
if type(tier) is not int or tier not in range(4):
raise LoopError("[loop].tier deve estar entre 0 e 3")
loop["tier"] = tier
for key in ("max_iterations", "max_minutes", "max_stagnant"):
if type(loop.get(key)) is not int or loop[key] < 1:
raise LoopError(f"[loop].{key} deve ser inteiro positivo")
if number(loop.get("min_improvement"), "min_improvement") <= 0:
raise LoopError("min_improvement deve ser positivo")
if number(loop.get("max_paid_usd", 0), "max_paid_usd") < 0:
raise LoopError("max_paid_usd não pode ser negativo")
if loop.get("harness") not in ("claude", "opencode", "omp"):
raise LoopError("[loop].harness deve ser claude, opencode ou omp")
if not git(top, "status", "--porcelain", "--untracked-files=all") == "":
raise LoopError("working tree do usuário tem alterações; salve/snapshot antes de iniciar")
return path, top, config, script, target
def state_root(project):
default = Path(os.environ.get("XDG_STATE_HOME", Path.home() / ".local" / "state")) / "dev-workflows"
root = Path(os.environ.get("DW_STATE_HOME", default)).expanduser().resolve()
if within(root, project) or within(project, root):
raise LoopError("estado do controlador deve ficar fora do checkout do projeto")
return root / hashlib.sha256(os.fsencode(project)).hexdigest()[:20]
def prepare_home(root):
root.mkdir(mode=0o700, parents=True, exist_ok=True)
os.chmod(root, 0o700)
@contextlib.contextmanager
def locked(home):
prepare_home(home)
with (home / "lock").open("a+") as f:
try:
fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
except BlockingIOError as exc:
raise LoopError("já existe uma execução ativa neste projeto") from exc
try:
yield
finally:
fcntl.flock(f, fcntl.LOCK_UN)
def save(folder, state):
folder.mkdir(mode=0o700, parents=True, exist_ok=True)
path = folder / "state.json"
tmp = folder / f".{uuid.uuid4().hex}.json"
with tmp.open("x") as out:
os.chmod(tmp, 0o600)
json.dump(state, out, ensure_ascii=False, indent=2)
out.flush()
os.fsync(out.fileno())
os.replace(tmp, path)
def load(home, run_id):
if not re.fullmatch(r"[0-9a-f]{32}", run_id):
raise LoopError("ID de execução inválido")
path = home / run_id / "state.json"
if not path.is_file():
raise LoopError("execução não encontrada")
with path.open() as f:
state = json.load(f)
return path.parent, state
def evaluator_result(cfg, script, repo, folder, deadline=None):
if digest(script) != cfg["loop"]["evaluator"]["trusted_sha256"].lower():
raise LoopError("avaliador protegido foi alterado")
folder.mkdir(mode=0o700, parents=True, exist_ok=True)
env = os.environ.copy()
env["DW_REPORT_DIR"] = str(folder)
argv = cfg["loop"]["evaluator"]["argv"]
result = isolated_command(argv, repo, bounded_timeout(
int(cfg["loop"]["evaluator"].get("timeout_seconds", 600)), deadline), env, writable=[folder])
if result.returncode:
raise LoopError(f"avaliador retornou {result.returncode}: {result.stderr.strip()[:300]}")
if digest(script) != cfg["loop"]["evaluator"]["trusted_sha256"].lower():
raise LoopError("avaliador protegido foi alterado durante a avaliação")
try:
data = json.loads(result.stdout, parse_constant=lambda _: (_ for _ in ()).throw(ValueError("NaN")))
score = number(data["value"], "score")
except (ValueError, KeyError, TypeError, json.JSONDecodeError) as exc:
raise LoopError("avaliador não produziu JSON com score válido") from exc
goal = cfg["loop"]["goal"]
if (data.get("schema_version") != 1 or data.get("metric") != goal["name"]
or data.get("unit") != goal["unit"] or data.get("direction") != goal["direction"]):
raise LoopError("métrica/unidade/direção divergente da meta")
checks = data.get("checks")
if not isinstance(checks, dict) or not checks or any(x != "pass" for x in checks.values()):
raise LoopError("avaliador não aprovou todos os seus checks")
paths = data.get("evidence")
if not isinstance(paths, list) or not paths:
raise LoopError("avaliador não forneceu evidência verificável")
evidence = []
for raw in paths:
if not isinstance(raw, str):
raise LoopError("caminho inválido de evidência")
p = Path(raw).resolve(strict=False)
if not p.is_file() or not within(p, folder.resolve()):
raise LoopError("evidência deve existir fora do worktree no diretório de relatórios")
evidence.append({"file": str(p), "sha256": digest(p)})
return score, evidence, checks
def attained(score, target, direction):
return score >= target if direction == "maximize" else score <= target
def improved(score, best, minimum, direction):
return score - best >= minimum if direction == "maximize" else best - score >= minimum
def worktree(project, folder, ref):
if folder.exists():
raise LoopError(f"worktree já existe: {folder}")
folder.parent.mkdir(mode=0o700, parents=True, exist_ok=True)
git(project, "-c", "core.hooksPath=/dev/null", "worktree", "add", "--detach", str(folder), ref)
return folder
def assert_worktree(project, repo, expected_head, marker_sha256=None):
"""Reject redirected Git pointers or a branch before controller Git writes."""
marker = repo / ".git"
if marker.is_symlink() or not marker.is_file():
raise LoopError("ponteiro .git do worktree foi removido ou substituído")
try:
text = marker.read_text(encoding="utf-8")
except (OSError, UnicodeError) as exc:
raise LoopError("ponteiro .git do worktree ilegível") from exc
match = re.fullmatch(r"gitdir: ([^\r\n]+)\r?\n?", text)
if not match:
raise LoopError("ponteiro .git do worktree inválido")
marker_hash = digest(marker)
if marker_sha256 is not None and marker_hash != marker_sha256:
raise LoopError("ponteiro .git do worktree mudou durante a tentativa")
admin = Path(match.group(1))
admin = (repo / admin).resolve() if not admin.is_absolute() else admin.resolve()
common = Path(git(project, "rev-parse", "--git-common-dir"))
common = (project / common).resolve() if not common.is_absolute() else common.resolve()
if not admin.is_dir() or admin.parent != common / "worktrees":
raise LoopError("gitdir do worktree não pertence ao repositório original")
actual = command(["git", "rev-parse", "--absolute-git-dir"], repo)
if actual.returncode or Path(actual.stdout.strip()).resolve() != admin:
raise LoopError("ponteiro .git redireciona o worktree")
detached = command(["git", "symbolic-ref", "-q", "HEAD"], repo)
if detached.returncode != 1 or git(repo, "rev-parse", "HEAD") != expected_head:
raise LoopError("worktree não está no commit detached esperado")
return marker_hash
def changed_paths(repo, base):
changed = set(git(repo, "diff", "--name-only", base).splitlines())
changed.update(git(repo, "ls-files", "--others", "--exclude-standard").splitlines())
return sorted(p for p in changed if p and not p.startswith(".dev-workflows/"))
def fingerprint(repo, names):
h = hashlib.sha256()
for name in names:
p = repo / name
h.update(os.fsencode(name))
h.update(b"\0")
if p.is_symlink():
h.update(os.fsencode(os.readlink(p)))
elif p.is_file():
h.update(digest(p).encode())
h.update(str(p.stat().st_mode & 0o777).encode())
else:
h.update(b"deleted")
return h.hexdigest()
def gate_result(repo, base, tier, required, changes, deadline=None):
t = time.time_ns()
result = isolated_command([sys.executable, str(GATE), "--dir", str(repo), "--base", base,
"--tier", str(tier)], repo, bounded_timeout(3600, deadline))
report_path = repo / ".dev-workflows" / "gate.json"
if not report_path.is_file() or report_path.stat().st_mtime_ns < t:
raise LoopError("quality gate não gerou relatório atual")
report = json.loads(report_path.read_text())
if result.returncode or report.get("verdict") != "pass" or report.get("base") != base or report.get("tier") != tier:
raise LoopError(f"quality gate não aprovou o diff: {report.get('verdict', 'sem relatório')}")
checks = {c.get("name"): c.get("status") for c in report.get("checks", [])}
if any(checks.get(name) != "pass" for name in required):
raise LoopError("checks obrigatórios ausentes, não verificados ou falhos")
deleted = set(git(repo, "diff", "--name-only", "--diff-filter=D", base).splitlines())
if not set(changes).difference(deleted).issubset(set(report.get("changed_files", []))):
raise LoopError("quality gate não cobriu todos os arquivos alterados")
return {"verdict": report["verdict"], "tier": tier, "checks": checks,
"base": base, "changed_files": report["changed_files"], "sha256": digest(report_path)}
def role_model(config, tool, role, cwd):
models = config.get("models", {})
role_cfg = models.get("roles", {}).get(role, {})
if role_cfg.get("model_key"):
if not role_cfg.get("manual_unranked_approval", False):
raise LoopError(f"{role}: modelo fixado sem aprovação explícita unranked")
if tool != "claude" or role_cfg.get("billing_mode") != "claude_subscription":
raise LoopError("modelo fixo não substitui descoberta de disponibilidade/conta em OpenCode ou OMP")
model_key = role_cfg["model_key"]
if model_key not in ("haiku", "sonnet", "opus", "inherit"):
raise LoopError("Claude por assinatura aceita apenas aliases de modelo suportados")
return {"model_key": model_key, "billing_mode": "claude_subscription",
"score": None, "reason": "unranked: fixado explicitamente pelo usuário"}
providers = models.get("allowed_providers")
if not isinstance(providers, list) or not providers or any(not isinstance(x, str) for x in providers):
raise LoopError("[models].allowed_providers deve listar os providers autorizados da conta")
argv = [sys.executable, str(MODEL_CATALOG), "route", "--tool", tool, "--role", role,
"--providers", ",".join(providers), "--format", "json",
"--budget-usd", str(number(config["loop"].get("max_paid_usd", 0), "max_paid_usd"))]
if models.get("benchmark_metric"):
argv.extend(["--benchmark-metric", models["benchmark_metric"]])
if models.get("bands"):
argv.extend(["--bands-json", json.dumps(models["bands"])])
for key, flag in (("max_price_age_hours", "--max-price-age-hours"),
("max_score_age_days", "--max-score-age-days")):
if key in models:
argv.extend([flag, str(models[key])])
if role_cfg.get("band"):
argv.extend(["--band", role_cfg["band"]])
if "max_loss_points" in role_cfg:
argv.extend(["--max-loss-points", str(role_cfg["max_loss_points"])])
if "tokens" in role_cfg:
argv.extend(["--tokens", json.dumps(role_cfg["tokens"])])
if (models.get("allow_proxy_score") and role_cfg.get("allow_proxy_score", True)
and config["loop"]["tier"] < 3):
argv.append("--allow-proxy-score")
if models.get("cache_dir"):
argv.extend(["--cache-dir", models["cache_dir"]])
p = command(argv, cwd)
if p.returncode:
raise LoopError(f"roteamento {role}: {p.stderr.strip()[:300]}")
try:
result = json.loads(p.stdout)
selected = result.get("selected")
if not selected or not selected.get("model_key"):
raise LoopError(f"{role}: sem modelo elegível: {result.get('reason', 'sem nota')}")
except (ValueError, AttributeError) as exc:
raise LoopError("roteador não devolveu JSON válido") from exc
return selected
def authorize(config, model, remaining):
billing = model.get("billing_mode")
if billing in ("free", "subscription", "claude_subscription"):
return
if billing == "go":
quota = model.get("quota_window_remaining")
debit = model.get("quota_window_debit")
if (not isinstance(quota, dict) or not isinstance(debit, dict) or
any(k not in quota or k not in debit or number(quota[k], k) < number(debit[k], k)
for k in ("5h", "weekly", "monthly"))):
raise SafetyPause("Go: cota não confirmada nas três janelas; sem fallback para saldo Zen")
if model.get("use_balance_fallback") is not False:
raise SafetyPause("Go: fallback para saldo Zen desconhecido ou cobrado; não autorizado")
return
if billing not in ("zen", "payg"):
raise SafetyPause("modalidade de cobrança desconhecida; despacho não autorizado")
label = "Zen" if billing == "zen" else "API paga"
if model.get("balance_confirmed") is not True:
raise SafetyPause(f"{label}: saldo ou permissão de cobrança da conta não confirmado")
cap = number(config["loop"].get("max_paid_usd", 0), "max_paid_usd")
estimate = model.get("estimated_native_usd")
if cap == 0 or estimate is None or number(estimate, "estimated_native_usd") > cap - remaining:
raise SafetyPause(f"{label}: orçamento explícito e estimativa nativa atual são obrigatórios")
if not sys.stdin.isatty():
raise SafetyPause(f"{label}: autorização interativa exigida imediatamente antes do gasto")
question = (f"Autorizar {model['model_key']} via {label}, estimativa USD {estimate}, "
f"limite restante USD {cap - remaining}? Digite SIM: ")
if input(question) != "SIM":
raise SafetyPause(f"gasto {label} não autorizado")
def mark_call_pending(state, folder, model):
if model.get("billing_mode") in ("zen", "payg", "go"):
state["unreconciled_paid_call"] = True
save(folder, state)
def selected_roles(config, cwd):
tier = config["loop"]["tier"]
roles = ["implementer"]
if tier >= 2:
roles = ["planner", "implementer", "reviewer"]
if tier >= 3:
roles.append("security-auditor")
return {role: role_model(config, config["loop"]["harness"], role, cwd) for role in roles}
def same_route(previous, current):
return all(previous.get(key) == current.get(key) for key in
("model_key", "billing_mode", "provider", "variant", "estimated_native_usd", "native_tariff"))
def verified_model(config, state, role):
previous = state["route_plan"][role]
if previous.get("billing_mode") == "claude_subscription":
return previous # CLI authentication is checked immediately before dispatch.
try:
current = role_model(config, config["loop"]["harness"], role, Path(state["project"]))
except LoopError as exc:
raise SafetyPause(f"{role}: disponibilidade, preço ou quota não revalidada: {exc}") from exc
if not same_route(previous, current):
raise SafetyPause(f"{role}: rota ou tarifa mudou; novo plan e aprovação necessários")
if current.get("billing_mode") == "go":
for key in ("5h", "weekly", "monthly"):
current["quota_window_remaining"][key] = str(min(
number(previous["quota_window_remaining"][key], key),
number(current["quota_window_remaining"][key], key)))
state["route_plan"][role] = current
return current
def report_run(state):
return {k: state.get(k) for k in
("run_id", "status", "baseline_score", "best_score", "target", "iteration",
"best_commit", "best_worktree", "spent_paid_usd", "elapsed_seconds",
"baseline_evidence", "baseline_checks", "baseline_gate", "attempts",
"route_plan", "gate_sha256", "evaluator_sha256", "error")}
def plan(config_path):
path, project, cfg, script, target = config_at(config_path)
preflight_isolation(project)
routes = {}
roles = (["planner", "implementer", "reviewer", "security-auditor"] if cfg["loop"]["tier"] >= 3
else ["planner", "implementer", "reviewer"] if cfg["loop"]["tier"] >= 2 else ["implementer"])
preflight = command([sys.executable, str(GATE), "--dir", str(project),
"--base", git(project, "rev-parse", "HEAD"),
"--tier", str(cfg["loop"]["tier"]), "--list"], project)
if preflight.returncode:
raise LoopError(f"quality gate indisponível: {preflight.stderr.strip()[:300]}")
planned = {fields[1]: " ".join(fields[3:]) for line in preflight.stdout.splitlines()
if len(fields := line.split()) >= 4 and fields[0].startswith("T")}
gate = {name: planned.get(name, "ausente") for name in cfg["loop"]["evaluator"]["required_checks"]}
for role in roles:
try:
routes[role] = role_model(cfg, cfg["loop"]["harness"], role, project)
except LoopError as exc:
routes[role] = {"status": "unavailable", "reason": str(exc)}
return {"config": str(path), "enabled": cfg["loop"].get("enabled", False), "root": str(project),
"evaluator_sha256": digest(script), "gate_sha256": digest(GATE),
"baseline": "not_run", "target": str(target),
"tier": cfg["loop"]["tier"], "routes": routes, "gate_preflight": gate,
"risks": ["modelos e permissões devem ser revalidados antes de cada chamada",
"worktree não substitui isolamento de processo e acesso a rede",
"preço OpenRouter não equivale à cobrança da ferramenta"],
"max_paid_usd": str(number(cfg["loop"].get("max_paid_usd", 0), "max_paid_usd"))}
def new_run(config_path):
path, project, cfg, script, target = config_at(config_path)
if cfg["loop"].get("enabled") is not True:
raise LoopError("loop desativado: habilite [loop].enabled explicitamente")
home = state_root(project)
with locked(home):
routes = selected_roles(cfg, project)
for model in routes.values():
if (model.get("billing_mode") in ("zen", "payg")
and number(cfg["loop"].get("max_paid_usd", 0), "max_paid_usd") == 0):
raise LoopError("modelo pago: gasto não autorizado; max_paid_usd=0")
base = git(project, "rev-parse", "HEAD")
run_id = uuid.uuid4().hex
folder = home / run_id
folder.mkdir(mode=0o700)
work = worktree(project, folder / "worktrees" / "baseline", base)
state = {"version": 1, "run_id": run_id, "project": str(project), "config": str(path),
"config_sha256": digest(path), "evaluator_sha256": digest(script),
"gate_sha256": digest(GATE), "base": base,
"best_commit": base, "best_worktree": str(work), "best_score": None,
"baseline_score": None,
"target": str(target), "iteration": 0, "spent_paid_usd": "0", "stagnant": 0,
"started_at": time.time(), "elapsed_seconds": 0, "status": "planned", "attempts": [],
"route_plan": routes}
save(folder, state)
try:
deadline = state["started_at"] + cfg["loop"]["max_minutes"] * 60
score, evidence, checks = evaluator_result(
cfg, script, work, folder / "evidence" / "baseline", deadline)
if changed_paths(work, base):
raise LoopError("avaliador modificou baseline; medição inicial inválida")
state.update(best_score=str(score), baseline_score=str(score), baseline_evidence=evidence,
baseline_checks=checks, status="baselined")
save(folder, state)
if attained(score, target, cfg["loop"]["goal"]["direction"]):
state["baseline_gate"] = gate_result(work, base, cfg["loop"]["tier"],
cfg["loop"]["evaluator"]["required_checks"], [], deadline)
state["status"] = "success"
save(folder, state)
else:
iterate(folder, state, cfg, script)
except (LoopError, OSError, ValueError) as exc:
state.update(status="error", error=str(exc))
save(folder, state)
return report_run(state)
def check_resumption(state, cfg, project, script, path):
if state["project"] != str(project) or state["config_sha256"] != digest(path):
raise LoopError("configuração/checkout mudou desde o início; não retomar automaticamente")
if (state["evaluator_sha256"] != digest(script) or state["gate_sha256"] != digest(GATE)
or git(project, "rev-parse", "HEAD") != state["base"]):
raise LoopError("avaliador, gate ou base Git mudaram; retomar exige nova avaliação")
if state["status"] not in ("exhausted", "paused", "running", "baselined"):
raise LoopError(f"execução com estado {state['status']} não pode ser retomada")
if state.get("unreconciled_paid_call"):
raise LoopError("tentativa paga com consumo/quota indeterminados; concilie antes de novo run")
routes = selected_roles(cfg, project)
if set(routes) != set(state["route_plan"]) or any(
not same_route(state["route_plan"][role], fresh) for role, fresh in routes.items()):
raise LoopError("catálogo, preço, conta ou modelos mudaram; não retomar sem novo plan")
if not Path(state["best_worktree"]).is_dir():
raise LoopError("worktree vencedor foi removido; não retomar")
def resume_run(config_path, run_id):
path, project, cfg, script, target = config_at(config_path)
home = state_root(project)
with locked(home):
folder, state = load(home, run_id)
check_resumption(state, cfg, project, script, path)
if (state["status"] == "running" and len(state["attempts"]) < state["iteration"]
and any(row.get("billing_mode") in ("zen", "payg", "go") for row in state["route_plan"].values())):
raise LoopError("tentativa paga interrompida: consumo/quota indeterminados; concilie antes de novo run")
if cfg["loop"].get("enabled") is not True:
raise LoopError("loop desativado")
if state["status"] == "running" and len(state["attempts"]) < state["iteration"]:
state["attempts"].append({"iteration": state["iteration"], "result": "interrupted", "reason": "tentativa interrompida, não reutilizada"})
state["status"] = "baselined"
save(folder, state)
try:
iterate(folder, state, cfg, script)
except (LoopError, OSError, ValueError) as exc:
state.update(status="error", error=str(exc))
save(folder, state)
return report_run(state)
def iterate(folder, state, cfg, script):
from harness_runner import invoke
minimum = number(cfg["loop"]["min_improvement"], "min_improvement")
target = number(state["target"], "target")
project = Path(state["project"])
path = Path(state["config"])
direction = cfg["loop"]["goal"]["direction"]
deadline = state["started_at"] + cfg["loop"]["max_minutes"] * 60
while state["iteration"] < cfg["loop"]["max_iterations"]:
if (folder / "stop.requested").exists():
state["status"] = "cancelled"
break
if time.time() >= deadline:
state["status"] = "exhausted"
break
if state["stagnant"] >= cfg["loop"]["max_stagnant"]:
state["status"] = "exhausted"
break
if (digest(path) != state["config_sha256"] or digest(script) != state["evaluator_sha256"]
or digest(GATE) != state["gate_sha256"]):
state["status"] = "paused"
state["error"] = "configuração, avaliador ou gate alterado durante a execução"
break
if git(project, "rev-parse", "HEAD") != state["base"] or git(project, "status", "--porcelain", "--untracked-files=all"):
state["status"] = "paused"
state["error"] = "checkout original alterado durante a execução; preservar mudanças do usuário"
break
step = state["iteration"] + 1
base = state["best_commit"]
work = worktree(project, folder / "worktrees" / f"iteration-{step:03}", base)
marker_hash = assert_worktree(project, work, base)
state.update(status="running", iteration=step)
save(folder, state)
attempt = {"iteration": step, "worktree": str(work), "from": base}
paid = number(state["spent_paid_usd"], "spent_paid_usd")
try:
tool = cfg["loop"]["harness"]
routes = state["route_plan"]
timeout = int(cfg["loop"].get("agent_timeout_seconds", 900))
prompt = (f"Use dev-router com tier mínimo {cfg['loop']['tier']}. Meta do aplicativo: "
f"{cfg['loop']['goal']['name']} {direction} {target} {cfg['loop']['goal']['unit']}. "
f"Score atual {state['best_score']}. Faça UMA hipótese pequena por iteração; "
"preserve testes e quality gate. Não modifique o avaliador, config, catálogos ou testes protegidos. "
"Não publique, instale dependências ou produza efeitos externos sem autorização. "
f"Feedback anterior: {state['attempts'][-1]['reason'] if state['attempts'] else 'nenhum'}. ")
if "planner" in routes:
model = verified_model(cfg, state, "planner")
authorize(cfg, model, paid)
mark_call_pending(state, folder, model)
planned = invoke(tool, "planner", prompt + "Planeje uma única hipótese; só leitura.", str(work),
model["model_key"], timeout=bounded_timeout(timeout, deadline),
env={"DEV_WORKFLOWS_AUTONOMOUS": "1"})
assert_worktree(project, work, base, marker_hash)
paid = charged(planned, model, cfg, state, folder)
if planned["returncode"]:
raise SafetyPause("planejamento falhou; nenhuma outra chamada autorizada")
prompt += "Plano (não é autorização): " + planned["output"][:3000] + ". "
model = verified_model(cfg, state, "implementer")
authorize(cfg, model, paid)
mark_call_pending(state, folder, model)
done = invoke(tool, "implementer", prompt + "Implemente e relate nível declarado e evidências.", str(work),
model["model_key"], timeout=bounded_timeout(timeout, deadline),
env={"DEV_WORKFLOWS_AUTONOMOUS": "1"})
paid = charged(done, model, cfg, state, folder)
if done["returncode"]:
raise SafetyPause("agente de implementação falhou; nenhuma outra chamada autorizada")
assert_worktree(project, work, base, marker_hash)
changes = changed_paths(work, base)
if not changes:
raise LoopError("agente não modificou código verificável")
if path.relative_to(project).as_posix() in changes or any(c.startswith(".dev-workflows/") for c in changes):
raise LoopError("tentativa alterou configuração ou estado protegido")
if (git(project, "rev-parse", "HEAD") != state["base"]
or git(project, "status", "--porcelain", "--untracked-files=all")):
raise LoopError("checkout original alterado durante a tentativa; preservar mudanças do usuário")
assert_worktree(project, work, base, marker_hash)
# This commit is only a candidate in a detached worktree, never a promotion.
git(work, "add", "-A", "--", ".", ":(exclude).dev-workflows/**")
git(work, "-c", "core.hooksPath=/dev/null", "-c", "commit.gpgSign=false",
"-c", "user.name=Dev Workflows", "-c", "user.email=dev-workflows@localhost",
"commit", "-m", f"dev-workflows: candidate iteration {step}")
candidate_commit = git(work, "rev-parse", "HEAD")
assert_worktree(project, work, candidate_commit, marker_hash)
if git(project, "rev-parse", "HEAD") != state["base"]:
raise LoopError("checkout original alterado durante o snapshot")
# Gate/review the exact commit, not agent-created ignored files.
verified = worktree(project, folder / "verification" / "worktrees" / f"iteration-{step:03}", candidate_commit)
verified_marker = assert_worktree(project, verified, candidate_commit)
if changed_paths(verified, base) != changes:
raise LoopError("snapshot da tentativa diverge dos arquivos alterados")
before = fingerprint(verified, changes)
gate = gate_result(verified, base, cfg["loop"]["tier"],
cfg["loop"]["evaluator"]["required_checks"], changes, deadline)
assert_worktree(project, verified, candidate_commit, verified_marker)
if changed_paths(verified, base) != changes or before != fingerprint(verified, changes):
raise LoopError("código mudou durante o quality gate")
attempt["gate"] = gate
for role in ("reviewer", "security-auditor"):
if role in routes:
model = verified_model(cfg, state, role)
authorize(cfg, model, paid)
mark_call_pending(state, folder, model)
review = invoke(tool, role, "Revise exclusivamente o diff da tentativa. Responda JSON: "
'{"verdict":"pass|fail","findings":[]}.', str(verified), model["model_key"],
timeout=bounded_timeout(timeout, deadline),
env={"DEV_WORKFLOWS_AUTONOMOUS": "1"})
paid = charged(review, model, cfg, state, folder)
if review["returncode"]:
raise SafetyPause(f"{role} falhou; nenhuma outra chamada autorizada")
if review_verdict(review["output"]) != "pass":
raise LoopError(f"{role} rejeitou ou não concluiu a revisão")
assert_worktree(project, verified, candidate_commit, verified_marker)
if changed_paths(verified, base) != changes or fingerprint(verified, changes) != before:
raise LoopError("código mudou depois do gate/revisão")
# Score a second clean checkout: gate artifacts cannot bias the metric.
scored = worktree(project, folder / "scoring" / "worktrees" / f"iteration-{step:03}", candidate_commit)
scored_marker = assert_worktree(project, scored, candidate_commit)
try:
score, evidence, checks = evaluator_result(
cfg, script, scored, folder / "evidence" / f"iteration-{step:03}", deadline)
except LoopError as exc:
raise SafetyPause(f"avaliador inválido: {exc}") from exc
assert_worktree(project, scored, candidate_commit, scored_marker)
if (changed_paths(scored, candidate_commit) or digest(path) != state["config_sha256"]
or git(project, "rev-parse", "HEAD") != state["base"]):
raise LoopError("código/configuração/base mudou durante a avaliação")
attempt.update(score=str(score), evidence=evidence, evaluator_checks=checks)
best = number(state["best_score"], "best_score")
if not improved(score, best, minimum, direction):
raise LoopError(f"sem melhoria mínima sobre {best}: score {score}")
bounded_timeout(1, deadline)
state.update(best_commit=candidate_commit, best_worktree=str(scored), best_score=str(score), stagnant=0)
attempt.update(result="accepted", reason="melhoria medida em snapshot limpo e gate aprovado",
commit=candidate_commit)
if attained(score, target, direction):
state["status"] = "success"
except SafetyPause as exc:
attempt.update(result="paused", reason=str(exc))
state["status"] = "paused"
except RuntimeError as exc:
attempt.update(result="paused", reason=f"runtime recusou ou falhou: {exc}")
state["status"] = "paused"
except (LoopError, OSError, ValueError) as exc:
attempt.update(result="rejected", reason=str(exc))
state["stagnant"] += 1
state["attempts"].append(attempt)
state["elapsed_seconds"] = round(time.time() - state["started_at"], 2)
save(folder, state)
if state["status"] in ("success", "paused"):
break
else:
state["status"] = "exhausted"
if state["status"] == "running":
state["status"] = "exhausted"
save(folder, state)
def usage_cost(result, model):
value = (result.get("usage") or {}).get("cost_usd")
if model.get("billing_mode") in ("zen", "payg") and value is None:
raise SafetyPause("modelo pago: custo real da chamada não foi informado; pausa obrigatória")
cost = number(value, "cost_usd") if value is not None else Decimal(0)
if cost < 0:
raise SafetyPause("custo negativo informado pelo provedor; pausa obrigatória")
if model.get("billing_mode") == "go":
quota = model["quota_window_remaining"]
debit = model["quota_window_debit"]
for window in ("5h", "weekly", "monthly"):
quota[window] = str(number(quota[window], window) - number(debit[window], window))
return cost if model.get("billing_mode") in ("zen", "payg") else Decimal(0)
def charged(result, model, config, state, folder):
total = number(state["spent_paid_usd"], "spent_paid_usd") + usage_cost(result, model)
state["spent_paid_usd"] = str(total)
if model.get("billing_mode") in ("zen", "payg", "go"):
state["unreconciled_paid_call"] = False
save(folder, state)
if (model.get("billing_mode") in ("zen", "payg")
and total > number(config["loop"]["max_paid_usd"], "max_paid_usd")):
raise SafetyPause(f"modelo pago: custo real USD {total} excedeu limite aprovado; nenhuma outra chamada autorizada")
return total
def review_verdict(output):
try:
report = json.loads(output)
except ValueError:
return "invalid"
return report.get("verdict") if report.get("verdict") in ("pass", "fail") and isinstance(report.get("findings"), list) else "invalid"
def main(argv=None):
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
parser.add_argument("action", choices=("plan", "run", "status", "resume", "stop"))
parser.add_argument("--config", default=".dev-workflows.toml")
parser.add_argument("--run", dest="run_id")
args = parser.parse_args(argv)
try:
if args.action == "plan":
result = plan(args.config)
elif args.action == "run":
result = new_run(args.config)
else:
if not args.run_id:
raise LoopError("--run <id> obrigatório")
path = Path(args.config).resolve(strict=True)
project = Path(git(path.parent, "rev-parse", "--show-toplevel")).resolve()
home = state_root(project)
if args.action == "resume":
result = resume_run(args.config, args.run_id)
else:
folder, state = load(home, args.run_id)
if args.action == "stop":
(folder / "stop.requested").touch(exist_ok=True)
result = report_run(state)
print(json.dumps(result, indent=2, ensure_ascii=False))
return 0 if args.action in ("plan", "status", "stop") or result.get("status") == "success" else 1
except (LoopError, FileNotFoundError, tomllib.TOMLDecodeError) as exc:
print(json.dumps({"status": "error", "reason": str(exc)}, ensure_ascii=False), file=sys.stderr)
return 2
if __name__ == "__main__":
sys.exit(main())
+496
View File
@@ -0,0 +1,496 @@
#!/usr/bin/env python3
"""Execução headless e conservadora para Claude Code, OpenCode e OMP."""
from __future__ import annotations
import importlib.util
import json
import os
import re
import shutil
import secrets
import subprocess
import tempfile
from pathlib import Path
from typing import Any, Mapping
ROOT = Path(__file__).resolve().parent.parent
AGENTS = ROOT / "agents"
OMP_TOOLS = {
"Read": "read", "Edit": "edit", "Write": "write", "Bash": "bash",
"Grep": "grep", "Glob": "glob", "WebFetch": "web_search",
"WebSearch": "web_search", "NotebookEdit": "notebook",
}
OMP_THINKING_LEVELS = {"off", "minimal", "low", "medium", "high", "xhigh", "max", "auto"}
class HarnessError(RuntimeError):
"""Harness request cannot be safely or exactly dispatched."""
def _load_catalog_module():
path = ROOT / "scripts" / "model_catalog.py"
spec = importlib.util.spec_from_file_location("dev_workflows_model_catalog", path)
if spec is None or spec.loader is None:
raise HarnessError("catálogo local indisponível")
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
def _agent(role: str) -> tuple[dict[str, str], str]:
if not re.fullmatch(r"[a-z][a-z0-9-]*", role):
raise HarnessError(f"papel inválido: {role!r}")
path = AGENTS / f"{role}.md"
try:
text = path.read_text(encoding="utf-8")
except OSError as exc:
raise HarnessError(f"papel desconhecido: {role}") from exc
match = re.match(r"\A---\n(.*?)\n---\n(.*)\Z", text, re.S)
if not match:
raise HarnessError(f"frontmatter inválido para papel {role}")
meta = dict(re.findall(r"^(\w+):\s*(.*)$", match.group(1), re.M))
if meta.get("name") != role:
raise HarnessError(f"identidade inválida para papel {role}")
return meta, match.group(2).replace("${CLAUDE_PLUGIN_ROOT}", str(ROOT))
def _model_for_cli(tool: str, model_key: str, meta: dict[str, str]) -> tuple[str | None, str]:
"""Return CLI selector and exact catalog key; never strip an unsupported variant."""
if not isinstance(model_key, str) or not model_key:
raise HarnessError("model_key obrigatório")
if tool == "claude":
if model_key == "inherit":
inherited = meta.get("model", "")
if inherited == "inherit":
raise HarnessError("Claude `inherit` não identifica um modelo verificável para este papel")
selector = inherited
catalog_key = inherited
else:
selector = model_key
catalog_key = model_key
if selector not in {"haiku", "sonnet", "opus"} and not re.fullmatch(r"claude-[A-Za-z0-9.-]+", selector):
raise HarnessError("Claude CLI aceita aliases haiku/sonnet/opus ou IDs Claude; model_key não é exato para esta ferramenta")
return (None if model_key == "inherit" else selector), catalog_key
if model_key == "inherit":
raise HarnessError("inherit não identifica provider/model para esta ferramenta")
if not re.fullmatch(r"[A-Za-z0-9_.-]+/[A-Za-z0-9_.:+/-]+(?:#[A-Za-z0-9_.+-]+)?", model_key):
raise HarnessError(f"model_key inválido ou não exato para {tool}: {model_key!r}")
return model_key, model_key
def _require_catalog_entry(tool: str, model_key: str, cache_dir: str | None) -> dict[str, Any]:
catalog = _load_catalog_module()
snapshot = catalog.load_snapshot(tool, cache_dir)
if not isinstance(snapshot, dict) or snapshot.get("tool") != tool:
raise HarnessError(f"snapshot local de {tool} indisponível; despacho bloqueado")
matches = [row for row in snapshot.get("models", [])
if isinstance(row, dict) and row.get("tool") == tool and row.get("model_key") == model_key]
if len(matches) != 1:
raise HarnessError(f"model_key {model_key!r} não é um ID exato e único no catálogo local de {tool}")
availability = matches[0].get("availability")
if not isinstance(availability, dict) or any(availability.get(field) is not True
for field in ("local_listed", "authenticated", "entitled")):
raise HarnessError(f"disponibilidade/autorização local não verificada para {model_key!r}; despacho bloqueado")
return matches[0]
def _role_tools(meta: dict[str, str]) -> list[str]:
declared = {item.strip() for item in meta.get("tools", "").split(",") if item.strip()}
return [name for name in ("Read", "Grep", "Glob", "Edit", "Write") if name in declared]
def _opencode_loop_agent(meta: dict[str, str], role_prompt: str) -> str:
tools = set(_role_tools(meta))
allowed = {
"read": "Read" in tools,
"edit": bool(tools & {"Edit", "Write"}),
"glob": "Glob" in tools,
"grep": "Grep" in tools,
"list": False,
"bash": False,
"task": False,
"external_directory": False,
"todowrite": False,
"webfetch": False,
"websearch": False,
"lsp": False,
"skill": False,
"question": False,
"doom_loop": False,
}
lines = ["---", f"description: {json.dumps(meta['description'], ensure_ascii=False)}",
"mode: primary", "permission:", ' "*": deny']
lines.extend(f" {name}: {'allow' if enabled else 'deny'}" for name, enabled in allowed.items())
return "\n".join(lines + ["---", "", role_prompt])
def _memfd(contents: bytes) -> int:
if not hasattr(os, "memfd_create"):
raise HarnessError("sandbox requer suporte a memfd para config efêmera")
fd = os.memfd_create("dev-workflows-harness")
os.write(fd, contents)
os.lseek(fd, 0, os.SEEK_SET)
return fd
def _within(path: Path, root: Path) -> bool:
return path == root or root in path.parents
def _validate_autonomous_worktree(cwd: str) -> None:
worktree = Path(cwd).resolve()
if worktree.parent.name != "worktrees" or not (
worktree.name == "baseline" or re.fullmatch(r"iteration-[0-9]+", worktree.name)
):
raise HarnessError("modo autônomo exige worktree isolado baseline/iteration-*")
checkout = ROOT.resolve()
if _within(worktree, checkout) or _within(checkout, worktree):
raise HarnessError("modo autônomo não pode gravar no checkout de origem")
marker = worktree / ".git"
if marker.is_symlink() or not marker.is_file():
raise HarnessError("cwd autônomo não é um git worktree")
match = re.fullmatch(r"gitdir:\s*(.+)\s*", marker.read_text(encoding="utf-8"))
if not match:
raise HarnessError("ponteiro .git inválido no worktree autônomo")
gitdir = Path(match.group(1))
if not gitdir.is_absolute():
gitdir = worktree / gitdir
gitdir = gitdir.resolve()
if not gitdir.is_dir() or _within(gitdir, worktree):
raise HarnessError("gitdir do worktree autônomo ausente ou inseguro")
def _sandbox_path(cwd: str, env: dict[str, str]) -> str:
worktree = Path(cwd).resolve()
entries: list[str] = []
seen: set[Path] = set()
for entry in env.get("PATH", "").split(os.pathsep):
path = Path(entry or cwd).expanduser()
if not path.is_absolute():
path = worktree / path
try:
path = path.resolve()
except OSError:
continue
if not path.is_dir() or _within(path, worktree) or path in seen:
continue
seen.add(path)
entries.append(str(path))
return os.pathsep.join(entries)
def _sandbox_command(tool: str, command: list[str], cwd: str, env: dict[str, str],
opencode_agent: str | None = None, temp_root: str | None = None
) -> tuple[list[str], tuple[int, ...]]:
if env.get("DEV_WORKFLOWS_AUTONOMOUS") != "1":
return command, ()
bwrap = shutil.which("bwrap", path="/usr/bin:/bin")
if not bwrap:
raise HarnessError("modo autônomo requer bwrap; despacho bloqueado")
if not temp_root:
raise HarnessError("sandbox sem diretório temporário privado")
temp_data = f"{temp_root}/data"
temp_config = f"{temp_root}/config"
args = [
bwrap, "--unshare-all", "--share-net", "--die-with-parent",
"--ro-bind", "/", "/", "--proc", "/proc", "--dev", "/dev",
"--bind", temp_root, temp_root,
"--dir", f"{temp_root}/tmp", "--dir", f"{temp_root}/cache",
"--dir", f"{temp_root}/state", "--dir", temp_data,
]
args.extend(("--setenv", "PATH", _sandbox_path(cwd, env)))
pass_fds: list[int] = []
if tool == "opencode":
for directory in (temp_config, f"{temp_config}/opencode", f"{temp_config}/opencode/agents",
f"{temp_data}/opencode"):
args.extend(("--dir", directory))
args.extend(("--setenv", "XDG_CONFIG_HOME", temp_config,
"--setenv", "XDG_DATA_HOME", temp_data,
"--setenv", "TMPDIR", f"{temp_root}/tmp"))
config_home = Path(env.get("XDG_CONFIG_HOME", str(Path.home() / ".config")))
configured = env.get("OPENCODE_CONFIG")
if not configured:
for filename in ("opencode.json", "opencode.jsonc"):
candidate = config_home / "opencode" / filename
if candidate.is_file():
configured = str(candidate)
break
if configured:
args.extend(("--setenv", "OPENCODE_CONFIG", configured))
auth_home = Path(env.get("XDG_DATA_HOME", str(Path.home() / ".local" / "share")))
auth_file = auth_home / "opencode" / "auth.json"
if auth_file.is_file():
auth_target = f"{temp_data}/opencode/auth.json"
fd = _memfd(b"")
pass_fds.append(fd)
args.extend(("--file", str(fd), auth_target, "--ro-bind", str(auth_file), auth_target))
if opencode_agent is not None:
role_name = command[command.index("--agent") + 1]
agent_target = f"{temp_config}/opencode/agents/{role_name}.md"
fd = _memfd(opencode_agent.encode("utf-8"))
pass_fds.append(fd)
args.extend(("--file", str(fd), agent_target))
args.extend(("--setenv", "XDG_CACHE_HOME", f"{temp_root}/cache",
"--setenv", "XDG_STATE_HOME", f"{temp_root}/state"))
else:
args.extend(("--setenv", "TMPDIR", f"{temp_root}/tmp",
"--setenv", "XDG_CACHE_HOME", f"{temp_root}/cache",
"--setenv", "XDG_STATE_HOME", f"{temp_root}/state"))
if tool == "omp":
args.extend(("--dir", f"{temp_root}/omp-agent",
"--setenv", "PI_CODING_AGENT_DIR", f"{temp_root}/omp-agent"))
elif tool == "claude":
args.extend(("--setenv", "CLAUDE_CODE_SKIP_PROMPT_HISTORY", "1"))
marker = str(Path(cwd) / ".git")
args.extend(("--bind", cwd, cwd, "--ro-bind", marker, marker, "--chdir", cwd, "--", *command))
# The network namespace is shared for provider APIs; it is not an API-only egress filter.
return args, tuple(pass_fds)
def _run_process(command: list[str], cwd: str, env: dict[str, str], timeout: float, tool: str,
opencode_agent: str | None = None) -> subprocess.CompletedProcess:
autonomous = env.get("DEV_WORKFLOWS_AUTONOMOUS") == "1"
temp_dir = None
pass_fds: tuple[int, ...] = ()
try:
if autonomous:
safe_path = _sandbox_path(cwd, env)
if not safe_path:
raise HarnessError("PATH seguro vazio; despacho bloqueado")
executable = shutil.which(command[0], path=safe_path)
if not executable:
raise HarnessError(f"CLI {command[0]!r} não encontrado em PATH seguro")
if _within(Path(executable).resolve(), Path(cwd).resolve()):
raise HarnessError(f"CLI {command[0]!r} está dentro do worktree; despacho bloqueado")
command = [executable, *command[1:]]
temp_dir = tempfile.TemporaryDirectory(prefix="dev-workflows-harness-", dir="/tmp")
wrapped, pass_fds = _sandbox_command(
tool, command, cwd, env, opencode_agent, temp_dir.name if temp_dir else None
)
return subprocess.run(wrapped, cwd=cwd, env=env, capture_output=True, text=True,
errors="replace", timeout=timeout, check=False, pass_fds=pass_fds)
finally:
for fd in pass_fds:
os.close(fd)
if temp_dir is not None:
temp_dir.cleanup()
def _claude_auth_status(cwd: str, env: dict[str, str], timeout: float) -> bool:
try:
result = _run_process(["claude", "auth", "status", "--json"], cwd, env, timeout, "claude")
except (OSError, subprocess.TimeoutExpired):
return False
if result.returncode != 0:
return False
try:
status = json.loads(result.stdout)
except json.JSONDecodeError:
return False
return isinstance(status, dict) and status.get("loggedIn") is True
def _omp_cli_model(row: dict[str, Any], model_key: str) -> tuple[str, str | None]:
variant = row.get("variant")
if variant is None:
if "#" in model_key:
raise HarnessError(f"model_key OMP variante sem metadado variant: {model_key!r}")
return model_key, None
if variant not in OMP_THINKING_LEVELS:
raise HarnessError(f"OMP CLI não oferece seleção exata da variante {variant!r}")
base_key, separator, key_variant = model_key.rpartition("#")
if not separator or key_variant != variant:
raise HarnessError(f"variante OMP não corresponde ao model_key canônico {model_key!r}")
provider, model_id = row.get("provider"), row.get("model_id")
if not isinstance(provider, str) or not isinstance(model_id, str) or base_key != f"{provider}/{model_id}":
raise HarnessError(f"provider/model_id do catálogo não confirma {model_key!r}")
return base_key, variant
def _local_models_command(tool: str, model_key: str, cwd: str, env: dict[str, str],
timeout: float, thinking: str | None = None) -> bool:
provider, model = model_key.split("/", 1)
base_model = model.split("#", 1)[0]
autonomous = env.get("DEV_WORKFLOWS_AUTONOMOUS") == "1"
if tool == "opencode":
command = ["opencode"] + (["--pure"] if autonomous else []) + ["models", provider]
else:
command = ["omp"] + (["--no-extensions"] if autonomous else []) + ["models", provider, "--json"]
try:
result = _run_process(command, cwd, env, timeout, tool)
except (OSError, subprocess.TimeoutExpired):
return False
if result.returncode != 0:
return False
if tool == "omp":
try:
payload = json.loads(result.stdout)
except json.JSONDecodeError:
return False
return _json_catalog_has_model(payload, provider, base_model, thinking)
for line in result.stdout.splitlines():
candidate = line.strip().strip("`'\" ")
if candidate.startswith(provider + "/"):
candidate = candidate[len(provider) + 1:]
if candidate in {model, base_model}:
return True
return False
def _json_catalog_has_model(value: Any, provider: str, model_id: str, thinking: str | None = None) -> bool:
if isinstance(value, list):
return any(_json_catalog_has_model(item, provider, model_id, thinking) for item in value)
if not isinstance(value, dict):
return False
row_provider = value.get("provider") or value.get("providerID") or value.get("provider_id")
row_id = value.get("id") or value.get("modelID") or value.get("model_id")
full_id = value.get("selector") or value.get("model_key") or value.get("model")
matches = ((row_provider == provider and row_id == model_id)
or (isinstance(full_id, str) and full_id == f"{provider}/{model_id}"))
if matches and (thinking is None or
(isinstance(value.get("thinking"), list) and thinking in value["thinking"])):
return True
return any(_json_catalog_has_model(item, provider, model_id, thinking) for item in value.values()
if isinstance(item, (dict, list)))
def _omp_tools(meta: dict[str, str], autonomous: bool = False) -> list[str]:
if autonomous:
return [OMP_TOOLS[name] for name in _role_tools(meta)]
declared = {item.strip() for item in meta.get("tools", "").split(",") if item.strip()}
read_only = not bool(declared & {"Edit", "Write"})
tool_order = ("Read", "Edit", "Write", "Bash", "Grep", "Glob", "WebFetch", "WebSearch", "NotebookEdit")
return list(dict.fromkeys(
OMP_TOOLS[name] for name in tool_order
if name in declared and not (read_only and name in {"Edit", "Write", "Bash"})
))
def _omp_skills(meta: dict[str, str]) -> list[str]:
match = re.search(r"\[(.*?)\]", meta.get("skills", ""))
return re.findall(r"[\w-]+", match.group(1)) if match else []
def _stderr_summary(stderr: str) -> str:
if not stderr:
return ""
lines = len(stderr.splitlines())
return f"[stderr omitido por segurança: {lines} linha(s), {len(stderr)} caracteres]"
def _text(value: str | bytes | None) -> str:
if value is None:
return ""
if isinstance(value, bytes):
return value.decode("utf-8", errors="replace")
return value
def invoke(tool: str, role: str, prompt: str, cwd: str, model_key: str,
timeout: float = 600, env: Mapping[str, str] | None = None) -> dict[str, Any]:
"""Invoke one role; only bounded autonomous OMP dispatch uses auto-approval.
The local catalog must attest local listing, authentication and entitlement.
OpenCode/OMP local models are rechecked immediately before dispatch. Autonomous
calls require bwrap and a tool allowlist; no fallback or config rewrite occurs.
"""
if tool not in {"claude", "opencode", "omp"}:
raise HarnessError(f"ferramenta não suportada: {tool!r}")
if not isinstance(prompt, str) or not prompt:
raise HarnessError("prompt vazio")
if isinstance(timeout, bool) or not isinstance(timeout, (int, float)) or timeout <= 0:
raise HarnessError("timeout deve ser positivo")
workdir = str(Path(cwd).resolve())
if not Path(workdir).is_dir():
raise HarnessError(f"cwd não existe ou não é diretório: {cwd!r}")
child_env = os.environ.copy()
if env is not None:
if any(not isinstance(key, str) or not isinstance(value, str) for key, value in env.items()):
raise HarnessError("env deve conter somente pares string/string")
child_env.update(env)
autonomous = child_env.get("DEV_WORKFLOWS_AUTONOMOUS") == "1"
if autonomous:
_validate_autonomous_worktree(workdir)
meta, role_prompt = _agent(role)
cli_model, catalog_key = _model_for_cli(tool, model_key, meta)
cache_dir = child_env.get("DEV_WORKFLOWS_MODEL_CACHE")
if tool == "claude":
if not _claude_auth_status(workdir, child_env, float(timeout)):
raise HarnessError("claude auth status não confirmou uma sessão autenticada; despacho bloqueado")
row = None if model_key in {"haiku", "sonnet", "opus", "inherit"} else _require_catalog_entry(tool, catalog_key, cache_dir)
else:
row = _require_catalog_entry(tool, catalog_key, cache_dir)
omp_thinking = None
local_model_key = catalog_key
if tool == "omp":
cli_model, omp_thinking = _omp_cli_model(row, catalog_key)
local_model_key = cli_model
if tool in {"opencode", "omp"} and not _local_models_command(
tool, local_model_key, workdir, child_env, float(timeout), omp_thinking):
raise HarnessError(f"provider/model indisponível na CLI local de {tool}: {catalog_key!r}; despacho bloqueado")
opencode_agent = None
if tool == "claude":
if autonomous:
safe_tools = _role_tools(meta)
agent_config = json.dumps({
role: {"description": meta["description"], "prompt": role_prompt, "tools": safe_tools}
}, ensure_ascii=False)
command = [
"claude", "--bare", "--no-session-persistence", "-p", "--agent", role,
"--agents", agent_config, "--tools", ",".join(safe_tools),
"--permission-mode", "dontAsk",
]
if cli_model is not None:
command.extend(("--model", cli_model))
if safe_tools:
command.extend(("--allowedTools", *safe_tools))
else:
command = ["claude", "-p", "--agent", role, "--permission-mode", "dontAsk"]
if cli_model is not None:
command.extend(("--model", cli_model))
command.append(prompt)
elif tool == "opencode":
agent_name = f"dev-workflows-loop-{role}-{secrets.token_hex(8)}" if autonomous else role
command = ["opencode"] + (["--pure"] if autonomous else []) + ["run", "--agent", agent_name]
if cli_model is not None:
command.extend(("--model", cli_model))
command.append(prompt)
if autonomous:
opencode_agent = _opencode_loop_agent(meta, role_prompt)
else:
command = ["omp", "-p", "--cwd", workdir]
if autonomous:
command.extend(("--no-extensions", "--no-lsp", "--no-session", "--auto-approve"))
else:
command.extend(("--approval-mode", "always-ask"))
if cli_model is not None:
command.extend(("--model", cli_model))
if omp_thinking is not None:
command.extend(("--thinking", omp_thinking))
command.extend(("--append-system-prompt", role_prompt))
skills = _omp_skills(meta)
if skills:
command.extend(("--skills", ",".join(skills)))
tools = _omp_tools(meta, autonomous=autonomous)
if tools:
command.extend(("--tools", ",".join(tools)))
else:
command.append("--no-tools")
command.append(prompt)
try:
result = _run_process(command, workdir, child_env, float(timeout), tool, opencode_agent)
returncode = result.returncode
stdout, stderr = result.stdout, result.stderr
except subprocess.TimeoutExpired as exc:
returncode = 124
stdout, stderr = _text(exc.stdout), _text(exc.stderr)
except OSError:
return {"returncode": 127, "output": f"CLI {tool} indisponível", "usage": None}
output = _text(stdout).rstrip()
summary = _stderr_summary(_text(stderr))
if summary:
output = f"{output}\n{summary}" if output else summary
return {"returncode": returncode, "output": output, "usage": None}
+66 -12
View File
@@ -1,14 +1,15 @@
#!/usr/bin/env python3
"""Install dev-workflows into Claude Code, opencode or Hermes Agent.
"""Install dev-workflows into Claude Code, OpenCode, OMP or Hermes Agent.
python3 scripts/install.py claude # plugin via local marketplace (skills, agents, hooks)
python3 scripts/install.py opencode # skills + agents + plugin under ~/.config/opencode
python3 scripts/install.py omp # native skills + agents under ~/.omp/plugins/dev-workflows
python3 scripts/install.py hermes # skills under ~/.hermes/skills (no agents/hooks there)
opencode and Hermes do not substitute ${CLAUDE_PLUGIN_ROOT}, so the copies point at this checkout:
OpenCode and Hermes do not substitute ${CLAUDE_PLUGIN_ROOT}, so their copies point at this checkout:
keep it where it is, or re-run the install after moving it.
"""
import argparse, os, re, shutil, subprocess, sys
import argparse, importlib.util, os, re, shutil, subprocess, sys
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
MARKER = ".dev-workflows-install"
@@ -40,23 +41,74 @@ def install_skills(target_dir, force):
def opencode_agent(path):
"""Claude Code agent frontmatter -> opencode subagent frontmatter."""
text = open(path, encoding="utf-8").read()
"""Claude Code agent frontmatter -> OpenCode subagent with explicit permissions."""
with open(path, encoding="utf-8") as source:
text = source.read()
m = re.match(r"---\n(.*?)\n---\n(.*)", text, re.S)
if not m:
raise ValueError(f"frontmatter inválido em {path}")
meta = dict(re.findall(r"^(\w+):\s*(.*)$", m.group(1), re.M))
tools = {t.strip() for t in meta.get("tools", "").split(",")}
skills = re.findall(r"[\w-]+", meta.get("skills", ""))
perm = {"edit": "allow" if tools & {"Edit", "Write"} else "deny",
"bash": "allow" if "Bash" in tools else "deny",
"webfetch": "allow" if "WebFetch" in tools else "deny"}
read_only = not bool(tools & {"Edit", "Write"})
allowed = {
"read": "Read" in tools,
"edit": not read_only and bool(tools & {"Edit", "Write"}),
"bash": not read_only and "Bash" in tools,
"glob": "Glob" in tools,
"grep": "Grep" in tools,
"list": False,
"task": False,
"external_directory": False,
"todowrite": False,
"webfetch": "WebFetch" in tools,
"websearch": "WebSearch" in tools,
"lsp": False,
"skill": "Skill" in tools,
"question": False,
"doom_loop": False,
}
body = m.group(2).replace("${CLAUDE_PLUGIN_ROOT}", ROOT)
if skills:
body = f"Antes de começar, carregue a(s) skill(s): {', '.join(skills)}.\n\n" + body
head = ["# dev-workflows", f"description: {meta['description']}", "mode: subagent", "permission:"]
head += [f" {k}: {v}" for k, v in perm.items()]
head = ["# dev-workflows", f"description: {meta['description']}", "mode: subagent", "permission:", ' "*": deny']
head += [f" {key}: {'allow' if value else 'deny'}" for key, value in allowed.items()]
return "---\n" + "\n".join(head) + "\n---\n\n" + body
def _omp_builder(path=None):
path = path or os.path.join(ROOT, "adapters", "omp", "build.py")
spec = importlib.util.spec_from_file_location("dev_workflows_omp_build", path)
if spec is None or spec.loader is None:
raise ImportError(f"não foi possível carregar o adapter OMP: {path}")
module = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = module
spec.loader.exec_module(module)
return module.build_package
def install_omp(base=None, runner=None, build_package=None):
"""Build and link the OMP package without replacing a foreign installation."""
omp_root = os.path.realpath(base or os.path.expanduser("~/.omp"))
dest = os.path.join(omp_root, "plugins", "dev-workflows")
if os.path.lexists(dest) and (os.path.islink(dest) or not os.path.isdir(dest)):
sys.exit(f"{dest} existe e não é um pacote OMP deste checkout.")
build = build_package or _omp_builder()
try:
build(ROOT, dest)
except FileExistsError as exc:
sys.exit(str(exc))
run = runner or subprocess.run
command = ["omp", "plugin", "link", dest]
try:
result = run(command, check=False)
except OSError:
sys.exit("OMP não encontrado; pacote gerado, mas `omp plugin link` não foi executado.")
if result.returncode != 0:
sys.exit(f"`omp plugin link {dest}` falhou com código {result.returncode}.")
print(f"plugin OMP instalado em {dest}")
def install_opencode(force):
base = os.path.expanduser("~/.config/opencode")
install_skills(os.path.join(base, "skills"), force)
@@ -83,13 +135,15 @@ def install_claude():
def main():
ap = argparse.ArgumentParser(description=__doc__.splitlines()[0])
ap.add_argument("target", choices=["claude", "opencode", "hermes"])
ap.add_argument("--force", action="store_true", help="sobrescreve pastas com o mesmo nome que não vieram deste script")
ap.add_argument("target", choices=["claude", "opencode", "hermes", "omp"])
ap.add_argument("--force", action="store_true", help="sobrescreve skills/agentes externos; OMP nunca sobrescreve pacote não pertencente")
a = ap.parse_args()
if a.target == "claude":
install_claude()
elif a.target == "opencode":
install_opencode(a.force)
elif a.target == "omp":
install_omp()
else:
install_skills(os.path.expanduser("~/.hermes/skills"), a.force)
print("Hermes: agentes e hooks não se aplicam; rode o gate manualmente.")
+1013
View File
File diff suppressed because it is too large. Load diff
+399
View File
@@ -0,0 +1,399 @@
#!/usr/bin/env python3
"""Seleção conservadora por papel; custos OpenRouter nunca são tarifa de cobrança."""
from __future__ import annotations
import datetime as dt
import json
from decimal import Decimal, InvalidOperation
from pathlib import Path
from typing import Any, Iterable
from model_catalog import (AA_METRIC, AA_VERSION, CACHE_DIR, decimal_text, decimal_value, discover_local_models,
load_snapshot, openrouter_price_for_profile, reference_cost)
ROLE_BANDS = {
"explorer": "leve", "verifier": "leve", "summarizer": "leve",
"implementer": "media", "ui-critic": "media",
"planner": "alta", "reviewer": "alta", "security-auditor": "alta",
}
DEFAULT_DELTA = {"leve": Decimal(3), "media": Decimal(3), "alta": Decimal(2)}
EXPECTED_HARNESSES = {"opencode": "OpenCode", "omp": "OMP", "claude": "Claude Code"}
WINDOWS = ("5h", "weekly", "monthly")
FIXED_BANDS = {
"leve": (Decimal(10), Decimal(20)),
"media": (Decimal(20), Decimal(50)),
"alta": (Decimal(50), Decimal(100)),
}
def validate_bands(bands: dict[str, Any] | None) -> dict[str, tuple[Decimal, Decimal]]:
"""Aceita a configuração declarativa apenas se preservar as faixas normativas."""
if bands is None:
return FIXED_BANDS.copy()
if not isinstance(bands, dict) or set(bands) != set(FIXED_BANDS):
raise ValueError("bands deve conter exatamente leve/media/alta")
normalized = {}
for name, limits in bands.items():
if not isinstance(limits, (list, tuple)) or len(limits) != 2:
raise ValueError(f"faixa {name} deve declarar dois limites")
low, high = (_decimal(value) for value in limits)
if low is None or high is None:
raise ValueError(f"limites da faixa {name} devem ser decimais")
normalized[name] = (low, high)
if normalized != FIXED_BANDS:
raise ValueError("bands customizadas são recusadas; use 10..20, 20..50 e 50..100")
return normalized
def _score_band(score: Decimal | None, bands: dict[str, tuple[Decimal, Decimal]]) -> str | None:
if score is None:
return None
for name in ("leve", "media"):
low, high = bands[name]
if low <= score < high:
return name
low, high = bands["alta"]
return "alta" if low <= score <= high else None
def _time(value: Any) -> dt.datetime | None:
if not isinstance(value, str) or not value:
return None
try:
result = dt.datetime.fromisoformat(value.replace("Z", "+00:00"))
except ValueError:
return None
if result.tzinfo is None:
return None
return result.astimezone(dt.timezone.utc)
def _decimal(value: Any) -> Decimal | None:
try:
return decimal_value(value)
except ValueError:
return None
def _has_token_profile(tokens: dict[str, Any]) -> bool:
return any((_decimal(tokens.get(key)) or Decimal(0)) > 0 for key in ("input", "output", "cache_read", "cache_write"))
def _staleness(row: dict[str, Any], now: dt.datetime, max_price_age_hours: Decimal, max_score_age_days: Decimal,
tokens: dict[str, Any]) -> list[str]:
reasons: list[str] = []
mode = row.get("billing_mode")
paid = mode in ("zen_balance", "go_quota", "omp_payg", "claude_subscription")
price_record = row.get("openrouter") or {"price_per_token_usd": row.get("or_price_per_token") or {}}
price = openrouter_price_for_profile(price_record, tokens)
native = row.get("native_tariff") or {}
has_reference_price = any(price.get("price_per_token_usd", {}).get(k) is not None
for k in ("input", "output", "cache_read", "cache_write"))
if paid:
if has_reference_price:
price_time = _time(price.get("captured_at"))
if price_time is None or price_time > now or (now - price_time).total_seconds() > float(max_price_age_hours * Decimal(3600)):
reasons.append("preco_referencial_obsoleto_ou_ausente")
score = row.get("score") or {}
score_time = _time(score.get("observed_at"))
if score_time is None or score_time > now or (now - score_time).total_seconds() > float(max_score_age_days * Decimal(86400)):
reasons.append("benchmark_obsoleto_ou_ausente")
if mode in ("zen_balance", "omp_payg"):
native_time = _time(native.get("captured_at"))
if native.get("account_confirmed") is not True or not str(native.get("source_url", "")).startswith("https://") or native_time is None or native_time > now or now - native_time > dt.timedelta(hours=float(max_price_age_hours)):
reasons.append("tarifa_nativa_obsoleta_ou_nao_confirmada")
if mode == "go_quota":
quota_time = _time(row.get("quota_verified_at"))
if quota_time is None or quota_time > now or now - quota_time > dt.timedelta(seconds=60) or not str(row.get("quota_source_url", "")).startswith("https://"):
reasons.append("quota_go_obsoleta_ou_nao_confirmada")
availability = row.get("availability") or {}
local_time = _time(availability.get("local_verified_at") or availability.get("verified_at"))
if local_time is None or local_time > now or now - local_time > dt.timedelta(hours=24):
reasons.append("disponibilidade_local_precisa_revalidacao")
account_time = _time(availability.get("account_verified_at"))
if availability.get("authenticated") is True and availability.get("entitled") is True:
if account_time is None or account_time > now or now - account_time > dt.timedelta(hours=24):
reasons.append("entitlement_precisa_revalidacao")
if mode in ("zen_balance", "omp_payg"):
balance_time = _time(availability.get("balance_verified_at"))
if availability.get("balance_confirmed") is not True or balance_time is None or balance_time > now or now - balance_time > dt.timedelta(seconds=60):
reasons.append("saldo_nao_confirmado_ou_obsoleto")
return reasons
def _profile_cost(row: dict[str, Any], tokens: dict[str, Any]) -> Decimal | None:
record = row.get("openrouter") or {"price_per_token_usd": row.get("or_price_per_token") or {}}
profile = openrouter_price_for_profile(record, tokens)
return reference_cost(profile.get("price_per_token_usd") or {}, tokens)
def _native_cost_and_headroom(row: dict[str, Any], tokens: dict[str, Any]) -> tuple[Decimal | None, Decimal | None, str | None]:
mode = row.get("billing_mode")
native = row.get("native_tariff")
if mode in ("zen_balance", "omp_payg"):
if not _has_token_profile(tokens):
return None, None, "perfil_tokens_native_nao_configurado"
if not isinstance(native, dict) or not isinstance(native.get("price_per_token_usd"), dict) or native.get("account_confirmed") is not True:
return None, None, "tarifa_native_nao_confirmada"
amount = reference_cost(native["price_per_token_usd"], tokens)
if amount is None:
return None, None, "tarifa_native_incompleta_para_perfil"
balance = _decimal(native.get("available_balance_usd"))
availability = row.get("availability") or {}
if availability.get("balance_confirmed") is not True:
return None, None, "saldo_nao_confirmado"
if balance is None or balance < 0:
return None, None, "saldo_desconhecido"
if balance < amount:
return None, balance, "saldo_insuficiente"
return amount, balance - amount, None
if mode == "go_quota":
if not _has_token_profile(tokens):
return None, None, "perfil_tokens_go_nao_configurado"
remaining = row.get("quota_window_remaining")
debit = row.get("quota_window_debit")
if row.get("use_balance_fallback"):
return None, None, "fallback_go_para_saldo_zen_nao_autorizado"
if not isinstance(remaining, dict) or debit is None:
return None, None, "quota_go_nao_confirmada"
debit_map = debit if isinstance(debit, dict) else {window: debit for window in WINDOWS}
headrooms: list[Decimal] = []
for window in WINDOWS:
available = _decimal(remaining.get(window))
used = _decimal(debit_map.get(window))
if available is None or used is None or available < 0 or used < 0:
return None, None, f"janela_go_{window}_desconhecida"
if used > available:
return None, None, f"quota_go_{window}_insuficiente"
headrooms.append(available - used)
representative = _decimal(debit_map.get("monthly"))
if representative is None:
return None, min(headrooms), "debito_go_nao_confirmado"
return representative, min(headrooms), None
if mode == "claude_subscription":
amount = _decimal(row.get("subscription_consumption_usd"))
if amount is None:
return None, None, "consumo_assinatura_nao_mensuravel"
return amount, None, None
return None, None, "modo_de_cobranca_desconhecido"
def route(candidates: Iterable[dict[str, Any]], role: str, *, allowed_providers: Iterable[str] = (),
tokens: dict[str, Any] | None = None, budget_usd: Any = None, allow_proxy: bool = False,
delta_points: Any = None, max_price_age_hours: Any = 24, max_score_age_days: Any = 30,
now: dt.datetime | None = None, band_override: str | None = None,
bands: dict[str, Any] | None = None,
benchmark_metric: str = "aa_coding_agent_index_v1.5") -> dict[str, Any]:
"""Returns the stable API: selected, ranking, reason. Never dispatches a model."""
default_band = ROLE_BANDS.get(role)
if default_band is None:
return {"selected": None, "ranking": [], "reason": f"papel_desconhecido:{role}"}
normalized_bands = validate_bands(bands)
band = band_override or default_band
if band not in normalized_bands:
raise ValueError("band deve ser uma faixa fixa: leve, media ou alta")
if benchmark_metric != "aa_coding_agent_index_v1.5":
raise ValueError("benchmark_metric incompatível; somente aa_coding_agent_index_v1.5 é aceito")
if now is None:
now = dt.datetime.now(dt.timezone.utc)
if now.tzinfo is None:
raise ValueError("now precisa de timezone")
now = now.astimezone(dt.timezone.utc)
tokens = tokens or {}
providers = set(allowed_providers)
if not providers:
return {"selected": None, "ranking": [], "reason": "provider_nao_autorizado; informe --providers explicitamente"}
if budget_usd is None:
budget = None
else:
budget = _decimal(budget_usd)
if budget is None or budget < 0:
raise ValueError("budget_usd precisa ser decimal não negativo")
max_price_age = _decimal(max_price_age_hours)
max_score_age = _decimal(max_score_age_days)
if max_price_age is None or max_score_age is None:
raise ValueError("TTL precisa ser decimal não negativo")
delta = _decimal(delta_points) if delta_points is not None else DEFAULT_DELTA[band]
if delta is None or delta < 0 or max_price_age < 0 or max_score_age < 0:
raise ValueError("delta e TTL devem ser decimais não negativos")
ranking = []
eligible = []
reasons_seen: list[str] = []
for row in candidates:
if not isinstance(row, dict):
continue
provider = row.get("provider")
score = row.get("score") or {}
parsed_score = _decimal(score.get("score"))
row_band = _score_band(parsed_score, normalized_bands)
reference = _profile_cost(row, tokens)
native_cost, headroom, native_error = _native_cost_and_headroom(row, tokens)
excluded: list[str] = []
availability = row.get("availability") or {}
if provider not in providers:
excluded.append("provider_nao_autorizado")
if availability.get("local_listed") is not True:
excluded.append("nao_listado_localmente")
if availability.get("authenticated") is not True:
excluded.append("autenticacao_nao_confirmada")
if availability.get("entitled") is not True:
excluded.append("entitlement_nao_confirmado")
required_provenance = all(score.get(field) not in (None, "", {}) for field in ("agent", "harness", "settings", "source_url", "observed_at"))
if not required_provenance or not str(score.get("source_url", "")).startswith("https://artificialanalysis.ai/"):
excluded.append("proveniencia_do_benchmark_incompleta")
if score.get("variant") != row.get("variant"):
excluded.append("mapeamento_de_variante_incompativel")
expected_harness = EXPECTED_HARNESSES.get(row.get("tool"))
if score.get("match_grade") == "exact" and score.get("harness") != expected_harness:
excluded.append("harness_incompativel")
if score.get("metric_id") != AA_METRIC or str(score.get("version")) != AA_VERSION:
excluded.append("indice_incompativel_ou_ausente")
if parsed_score is None:
excluded.append("no_scored_candidate")
if score.get("match_grade") not in (("exact", "proxy") if allow_proxy else ("exact",)):
excluded.append("match_proxy_nao_autorizado" if score.get("match_grade") == "proxy" else "mapeamento_de_variante_incompativel")
if row_band != band:
excluded.append("fora_da_faixa" if row_band else "sem_faixa_de_nota")
excluded.extend(_staleness(row, now, max_price_age, max_score_age, tokens))
if native_error:
excluded.append(native_error)
if row.get("billing_mode") in ("zen_balance", "omp_payg") and budget is None:
excluded.append("orcamento_zen_nao_configurado" if row.get("billing_mode") == "zen_balance" else "orcamento_payg_omp_nao_configurado")
if native_cost is not None and budget is not None and native_cost > budget:
excluded.append("orcamento_excedido")
if row.get("billing_mode") == "claude_subscription" and native_cost is None:
excluded.append("consumo_assinatura_nao_mensuravel")
if row.get("billing_mode") == "go_quota" and headroom is None and native_error is None:
excluded.append("cota_go_nao_confirmada")
key = row.get("model_key") or f"{provider}/{row.get('model_id', '')}"
entry = {
"model_key": key, "provider": provider, "billing_mode": row.get("billing_mode"),
"score": decimal_text(parsed_score), "band": row_band, "match_grade": score.get("match_grade"),
"eligible": not excluded, "exclusion_reasons": excluded,
"reference_cost_usd": decimal_text(reference), "native_cost_or_quota_debit_usd": decimal_text(native_cost),
"quota_headroom_usd": decimal_text(headroom),
}
ranking.append(entry)
if not excluded:
eligible.append((row, entry, parsed_score, native_cost, headroom))
else:
reasons_seen.extend(excluded)
ranking.sort(key=lambda entry: (
not entry["eligible"],
_decimal(entry.get("native_cost_or_quota_debit_usd")) if _decimal(entry.get("native_cost_or_quota_debit_usd")) is not None else Decimal("Infinity"),
-(_decimal(entry.get("score")) or Decimal(0)),
-(_decimal(entry.get("quota_headroom_usd")) or Decimal(0)),
entry["model_key"],
))
if not ranking:
return {"selected": None, "ranking": [], "reason": "no_scored_candidate"}
if not eligible:
if "no_scored_candidate" in reasons_seen or "indice_incompativel_ou_ausente" in reasons_seen:
reason = "no_scored_candidate_or_compatible_index"
elif "fora_da_faixa" in reasons_seen or "sem_faixa_de_nota" in reasons_seen:
reason = f"faixa_vazia:{band}"
elif "quota_go_5h_insuficiente" in reasons_seen or "quota_go_weekly_insuficiente" in reasons_seen or "quota_go_monthly_insuficiente" in reasons_seen:
reason = "quota_go_insuficiente; execução pausada antes da chamada"
elif "fallback_go_para_saldo_zen_nao_autorizado" in reasons_seen:
reason = "fallback_go_para_saldo_zen_nao_autorizado"
else:
reason = "nenhum_candidato_elegivel:" + ",".join(sorted(set(reasons_seen)))
return {"selected": None, "ranking": ranking, "reason": reason}
top_score = max(item[2] for item in eligible)
plateau = [item for item in eligible if item[2] >= top_score - delta]
# custo real da ferramenta; desempate: score, folga de quota, ID lexical.
plateau.sort(key=lambda item: (item[3], -item[2], -(item[4] if item[4] is not None else Decimal(0)), item[1]["model_key"]))
chosen = plateau[0]
row, entry, score_value, native_cost, headroom = chosen
selected = {
"model_key": entry["model_key"],
"billing_mode": {"zen_balance": "zen", "go_quota": "go", "omp_payg": "payg", "claude_subscription": "subscription"}.get(row.get("billing_mode"), row.get("billing_mode")),
"billing_mode_detail": row.get("billing_mode"), "score": entry["score"],
"band": band, "match_grade": entry["match_grade"],
"reference_cost_usd": entry["reference_cost_usd"],
"native_cost_or_quota_debit_usd": decimal_text(native_cost),
"estimated_native_usd": decimal_text(native_cost) if row.get("billing_mode") in ("zen_balance", "omp_payg") else None,
"native_tariff": row.get("native_tariff"),
"available_balance_usd": (row.get("native_tariff") or {}).get("available_balance_usd"),
"balance_confirmed": (row.get("availability") or {}).get("balance_confirmed") is True,
"balance_verified_at": (row.get("availability") or {}).get("balance_verified_at"),
"quota_window_remaining": row.get("quota_window_remaining"),
"quota_window_debit": row.get("quota_window_debit"),
"use_balance_fallback": row.get("use_balance_fallback") if row.get("billing_mode") == "go_quota" else False,
"quota_headroom_usd": decimal_text(headroom),
"score_top": decimal_text(top_score), "plateau_delta_points": decimal_text(delta),
}
if row.get("tool") == "omp":
variant = row.get("variant")
selected["dispatch_model_key"] = f"{row['provider']}/{row['model_id']}" + (f":{variant}" if variant else "")
reason = f"menor consumo relevante dentro do platô {band} (score >= {decimal_text(top_score - delta)}); custo OpenRouter é apenas referência"
if len(plateau) > 1:
reason += "; desempate determinístico por consumo, score, folga de cota e model_key"
return {"selected": selected, "ranking": ranking, "reason": reason}
def route_from_catalog(tool: str, role: str, allowed_providers: Iterable[str], cache_dir: str | Path | None = None,
*, explain: bool = False, tokens: dict[str, Any] | None = None, budget_usd: Any = None,
allow_proxy: bool = False, delta_points: Any = None, max_price_age_hours: Any = 24,
max_score_age_days: Any = 30, band_override: str | None = None,
bands: dict[str, Any] | None = None,
benchmark_metric: str = "aa_coding_agent_index_v1.5",
now: dt.datetime | None = None,
local_discoverer=discover_local_models, omp_discoverer=None) -> dict[str, Any]:
from model_catalog import discover_omp_models
clock = now or dt.datetime.now(dt.timezone.utc)
snapshot = load_snapshot(tool, cache_dir)
if snapshot is None:
return {"selected": None, "ranking": [], "reason": "snapshot_de_catalogo_ausente; execute models sync"}
if tool not in ("opencode", "omp"):
return {"selected": None, "ranking": [], "reason": f"catalogo_local_nao_disponivel_para_{tool}"}
providers = tuple(allowed_providers)
if not providers:
return route(snapshot.get("models", []), role, allowed_providers=providers, tokens=tokens, budget_usd=budget_usd,
allow_proxy=allow_proxy, delta_points=delta_points, max_price_age_hours=max_price_age_hours,
max_score_age_days=max_score_age_days, band_override=band_override, bands=bands,
benchmark_metric=benchmark_metric, now=clock)
discoverer = local_discoverer if tool == "opencode" else (omp_discoverer or discover_omp_models)
discoveries = {provider: discoverer(provider) for provider in sorted(set(providers))}
verified_at = clock.astimezone(dt.timezone.utc).isoformat().replace("+00:00", "Z")
candidates = []
for original in snapshot.get("models", []):
row = dict(original)
availability = dict(row.get("availability") or {})
provider = row.get("provider")
result = discoveries.get(provider)
if result is not None and result.get("ok"):
local_ids = set(result.get("models", []))
local_model_key = row["model_key"] if tool == "omp" else row["model_id"] + (f"#{row['variant']}" if row.get("variant") else "")
availability["local_listed"] = local_model_key in local_ids
availability["local_verified_at"] = result.get("verified_at", verified_at)
elif provider in discoveries:
availability["local_listed"] = None
availability["local_verified_at"] = None
row["availability"] = availability
candidates.append(row)
return route(candidates, role, allowed_providers=providers, tokens=tokens, budget_usd=budget_usd,
allow_proxy=allow_proxy, delta_points=delta_points, max_price_age_hours=max_price_age_hours,
max_score_age_days=max_score_age_days, band_override=band_override, bands=bands,
benchmark_metric=benchmark_metric, now=clock)
def main(argv: list[str] | None = None) -> int:
import argparse
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
parser.add_argument("--tool", choices=("opencode", "omp", "claude"), default="opencode")
parser.add_argument("--role", required=True)
parser.add_argument("--providers", default="")
parser.add_argument("--format", choices=("json",), default="json")
parser.add_argument("--cache-dir")
args = parser.parse_args(argv)
result = route_from_catalog(args.tool, args.role, [p for p in args.providers.split(",") if p], args.cache_dir, explain=True)
print(json.dumps(result, ensure_ascii=False))
return 0 if result["selected"] is not None else 2
if __name__ == "__main__":
raise SystemExit(main())