Proof Portal
Omarchy
ProbeLabs65 findings · 95 requirementsA proof layer — requirements, tests and verified fixes — for two of Omarchy's subsystems: the application menu (launcher scripts, QML model, JSONC config, search and selection) and the lock screen (lock scripts, QML, PAM authentication). Scope is deliberately limited to those components of omacom/omarchy; the rest of the distribution is not covered.
Add OpenCode collector to the Agents panel
Reported by acf1210 · filed Sep 1, 2026 · open at source
At a glance
- 1 · What is claimed?
- Only the report text below — no validator has restated it as checkable claims yet.
- 2 · What does it affect?
- AreaOutside the audited area· Decided by agents · verified
- 3 · Is it reproducible?
- No validation has been run yet.
- 4 · What remains unclear?
- Not validated yet: no claims, no reproducer.
- 5 · What happens next?
- Decided by agents and verified by a second, independent agent — see the decision.
Original report
Context
OpenCode is a supported default agent in Omarchy (omarchy-default-agent opencode) but has no usage collector, so daily OpenCode usage never appears in the omarchy.agents bar panel, unlike Claude Code and Codex.
Current State
Verified live (2026-09-01):
- OpenCode 1.18.25 installed and actively used:
~/.local/share/opencode/opencode.dbis a 7.5MB SQLite DB with 202 rows inmessagealone. auth.jsonhas exactly one provider key,"opencode"— this account routes through OpenCode's own hosted "Zen" gateway, not raw Anthropic/OpenAI keys.- An assistant message row's
dataJSON has this verified shape (no secrets):
{
"role": "assistant",
"providerID": "opencode",
"modelID": "big-pickle",
"tokens": {"input": 6929, "output": 182, "reasoning": 0, "cache": {"write": 0, "read": 1792}, "total": 8903},
"cost": 0,
"time": {"created": "<epoch-ms>", "completed": "<epoch-ms>"}
} (time.created/time.completed are millisecond Unix epoch integers in the real record; shown as placeholders here.)
- The existing bin/omarchy-agent-usage-claude collector already queries this exact DB/table (its scan_opencode_usage() function) — but only to merge Anthropic-provider rows into the Claude tab. It filters providerID == "anthropic" and never surfaces OpenCode's own aggregate.
- No public balance/credit API exists for OpenCode Zen: anomalyco/opencode#10448 is an open feature request for exactly GET /zen/v1/balance, confirming it doesn't exist yet. Balance is dashboard-only today.
- opencode stats (the CLI's own usage command) has no --json flag — it prints an ASCII table only, so it is not a viable machine-readable source; the collector must query the SQLite DB directly, exactly like the existing Claude-side code already does.
Proposed Change
Add bin/omarchy-agent-usage-opencode, a new collector mirroring omarchy-agent-usage-claude's existing scan_opencode_usage() logic, minus the providerID == "anthropic" filter (aggregate every provider OpenCode routed through), and register it as a new provider tab.
Implementation Details
New file: `bin/omarchy-agent-usage-opencode` (Python, matching the other collectors' shape and omarchy:hidden=true convention)
- Read-only SQLite connection:
sqlite3.connect(db.resolve().as_uri() + "?mode=ro", uri=True, timeout=2),PRAGMA query_only = ON— same safety pattern as the existing Claude-side reader (OpenCode may be writing concurrently). SELECT session_id, data FROM message; parse each row'sdataJSON; skip non-"assistant"rows.- Per row:
input_tokens = tokens.input,output_tokens = tokens.output + tokens.reasoning,cache_read = tokens.cache.read,cache_write = tokens.cache.write,model = modelID,dayderived fromtime.created(ms epoch). - Build the same generic stats bucket every other collector returns:
todayPrompts,todaySessions,todayTotalTokens,todayTokensByModel,recentDays(last 7 days,{date, messageCount}),modelUsage({model: {inputTokens, outputTokens, cacheReadInputTokens, cacheCreationInputTokens}}),totalPrompts,totalSessions,activeDays,activeDates. - No
limitsand nobalancein v1 — no confirmed live API for Zen balance; ship stats-only rather than block (durable scope decision logged this session, idcb82f332). - Top-level record:
{"schemaVersion": 1, "id": "opencode", "name": "OpenCode", "updatedAt": <iso>, "ready": totalPrompts>0, "hasLocalStats": true, "tierLabel": "", "usageStatusText": "", "authHelpText": "", "limits": []}merged with the stats bucket — same wrapper shapeomarchy-agent-usage-claudealready emits. --force/--limits-onlyflags accepted (no-ops beyond cache freshness) for CLI contract parity with every other collector.- Cache the scan result under
cache_root()/opencode-scan-<hash>.jsonwith the same freshness/lock pattern ascached_scan()in the Claude collector, so repeated panel opens don't re-scan a growing DB every time.
`shell/plugins/agents/manifest.json`: add "opencode": {"enabled": true} to defaults.providers.
`shell/plugins/agents/assets/opencode.svg` (+ -light variant if OpenCode's mark needs one for light bar surfaces): OpenCode's brand mark; the bar glyph fallback is acceptable if no mark is added (optional per the plugin's own README).
`shell/plugins/agents/README.md`: add a row to the collector table documenting the new collector: no balance source (Zen has no public API yet), local source is opencode.db message table across every provider.
Acceptance Criteria
- On a machine with
~/.local/share/opencode/opencode.dbcontaining at least one assistant message,omarchy-agent-usage-opencodeprints a valid JSON record withschemaVersion: 1,id: "opencode", and non-zerototalPrompts. - On a machine with no OpenCode DB, the collector exits cleanly with
ready: false/totalPrompts: 0(not an error) — the panel's existing self-hide behavior keeps the tab off the bar. omarchy agent usage-update opencoderegenerates~/.local/state/omarchy/agents/usage/opencode.jsonwithout touchingclaude.json,codex.json, orfireworks.json.- The "OpenCode" tab appears in the live panel with correct today/7-day/all-time token counts, verified against a manual SQL count on the same DB.
- Existing Claude tab behavior (its own
scan_opencode_usage()Anthropic-only merge) is unchanged — no regression. - No
balancekey appears in the record.
Testing Plan
| Layer | What | Count |
|---|---|---|
| Unit | Token/day/model aggregation from a fixture opencode.db (multi-provider, multi-day) | +4 |
| Unit | Empty/missing DB → ready:false, no crash | +1 |
| Integration | omarchy-agent-usage-update opencode writes opencode.json, leaves siblings untouched | +1 |
| Manual | Live panel shows an OpenCode tab against a machine with real data | +1 |
Rollback Plan
Delete bin/omarchy-agent-usage-opencode, remove the opencode entry from manifest.json:defaults.providers, delete the stale ~/.local/state/omarchy/agents/usage/opencode.json if present. No data migration, no schema change to any other file.
Effort Estimate
~4h — 2h collector script (mirrors an existing, proven query), 1h manifest/assets/README, 1h tests + manual verification.
Files Reference
| File | Change |
|---|---|
bin/omarchy-agent-usage-opencode | New collector |
shell/plugins/agents/manifest.json | Add opencode to defaults.providers |
shell/plugins/agents/assets/opencode.svg | New mark (optional) |
shell/plugins/agents/README.md | Document the new collector row |
bin/omarchy-agent-usage-claude (reference only, unchanged) | Existing scan_opencode_usage() is the proven query pattern to mirror |
Out of Scope
- Balance/credit display (no public Zen API).
- Cost-per-model display (data exists in
message.data.costbut showing it needs aPanel.qmlchange — separate issue). - Filtering by project/workspace (v1 aggregates everything machine-wide, matching Claude/Codex's own scope).
Related
- Parent epic: #9685 — Add Gemini and OpenCode monitoring to the Agents panel
- Sibling: #9684 — Add Gemini collector to the Agents panel
View raw text
## Context
OpenCode is a supported default agent in Omarchy (`omarchy-default-agent opencode`) but has no usage collector, so daily OpenCode usage never appears in the `omarchy.agents` bar panel, unlike Claude Code and Codex.
## Current State
Verified live (2026-09-01):
- OpenCode 1.18.25 installed and actively used: `~/.local/share/opencode/opencode.db` is a 7.5MB SQLite DB with 202 rows in `message` alone.
- `auth.json` has exactly one provider key, `"opencode"` — this account routes through OpenCode's own hosted "Zen" gateway, not raw Anthropic/OpenAI keys.
- An assistant message row's `data` JSON has this verified shape (no secrets):
```json
{
"role": "assistant",
"providerID": "opencode",
"modelID": "big-pickle",
"tokens": {"input": 6929, "output": 182, "reasoning": 0, "cache": {"write": 0, "read": 1792}, "total": 8903},
"cost": 0,
"time": {"created": "<epoch-ms>", "completed": "<epoch-ms>"}
}
```
(`time.created`/`time.completed` are millisecond Unix epoch integers in the real record; shown as placeholders here.)
- The existing `bin/omarchy-agent-usage-claude` collector already queries this exact DB/table (its `scan_opencode_usage()` function) — but only to merge Anthropic-provider rows into the Claude tab. It filters `providerID == "anthropic"` and never surfaces OpenCode's own aggregate.
- No public balance/credit API exists for OpenCode Zen: anomalyco/opencode#10448 is an open feature request for exactly `GET /zen/v1/balance`, confirming it doesn't exist yet. Balance is dashboard-only today.
- `opencode stats` (the CLI's own usage command) has no `--json` flag — it prints an ASCII table only, so it is not a viable machine-readable source; the collector must query the SQLite DB directly, exactly like the existing Claude-side code already does.
## Proposed Change
Add `bin/omarchy-agent-usage-opencode`, a new collector mirroring `omarchy-agent-usage-claude`'s existing `scan_opencode_usage()` logic, minus the `providerID == "anthropic"` filter (aggregate every provider OpenCode routed through), and register it as a new provider tab.
### Implementation Details
**New file: `bin/omarchy-agent-usage-opencode`** (Python, matching the other collectors' shape and `omarchy:hidden=true` convention)
- Read-only SQLite connection: `sqlite3.connect(db.resolve().as_uri() + "?mode=ro", uri=True, timeout=2)`, `PRAGMA query_only = ON` — same safety pattern as the existing Claude-side reader (OpenCode may be writing concurrently).
- `SELECT session_id, data FROM message`; parse each row's `data` JSON; skip non-`"assistant"` rows.
- Per row: `input_tokens = tokens.input`, `output_tokens = tokens.output + tokens.reasoning`, `cache_read = tokens.cache.read`, `cache_write = tokens.cache.write`, `model = modelID`, `day` derived from `time.created` (ms epoch).
- Build the same generic stats bucket every other collector returns: `todayPrompts`, `todaySessions`, `todayTotalTokens`, `todayTokensByModel`, `recentDays` (last 7 days, `{date, messageCount}`), `modelUsage` (`{model: {inputTokens, outputTokens, cacheReadInputTokens, cacheCreationInputTokens}}`), `totalPrompts`, `totalSessions`, `activeDays`, `activeDates`.
- No `limits` and no `balance` in v1 — no confirmed live API for Zen balance; ship stats-only rather than block (durable scope decision logged this session, id `cb82f332`).
- Top-level record: `{"schemaVersion": 1, "id": "opencode", "name": "OpenCode", "updatedAt": <iso>, "ready": totalPrompts>0, "hasLocalStats": true, "tierLabel": "", "usageStatusText": "", "authHelpText": "", "limits": []}` merged with the stats bucket — same wrapper shape `omarchy-agent-usage-claude` already emits.
- `--force` / `--limits-only` flags accepted (no-ops beyond cache freshness) for CLI contract parity with every other collector.
- Cache the scan result under `cache_root()/opencode-scan-<hash>.json` with the same freshness/lock pattern as `cached_scan()` in the Claude collector, so repeated panel opens don't re-scan a growing DB every time.
**`shell/plugins/agents/manifest.json`**: add `"opencode": {"enabled": true}` to `defaults.providers`.
**`shell/plugins/agents/assets/opencode.svg`** (+ `-light` variant if OpenCode's mark needs one for light bar surfaces): OpenCode's brand mark; the bar glyph fallback is acceptable if no mark is added (optional per the plugin's own README).
**`shell/plugins/agents/README.md`**: add a row to the collector table documenting the new collector: no balance source (Zen has no public API yet), local source is `opencode.db` message table across every provider.
## Acceptance Criteria
1. On a machine with `~/.local/share/opencode/opencode.db` containing at least one assistant message, `omarchy-agent-usage-opencode` prints a valid JSON record with `schemaVersion: 1`, `id: "opencode"`, and non-zero `totalPrompts`.
2. On a machine with no OpenCode DB, the collector exits cleanly with `ready: false` / `totalPrompts: 0` (not an error) — the panel's existing self-hide behavior keeps the tab off the bar.
3. `omarchy agent usage-update opencode` regenerates `~/.local/state/omarchy/agents/usage/opencode.json` without touching `claude.json`, `codex.json`, or `fireworks.json`.
4. The "OpenCode" tab appears in the live panel with correct today/7-day/all-time token counts, verified against a manual SQL count on the same DB.
5. Existing Claude tab behavior (its own `scan_opencode_usage()` Anthropic-only merge) is unchanged — no regression.
6. No `balance` key appears in the record.
## Testing Plan
| Layer | What | Count |
|-------|------|-------|
| Unit | Token/day/model aggregation from a fixture `opencode.db` (multi-provider, multi-day) | +4 |
| Unit | Empty/missing DB → `ready:false`, no crash | +1 |
| Integration | `omarchy-agent-usage-update opencode` writes `opencode.json`, leaves siblings untouched | +1 |
| Manual | Live panel shows an OpenCode tab against a machine with real data | +1 |
## Rollback Plan
Delete `bin/omarchy-agent-usage-opencode`, remove the `opencode` entry from `manifest.json:defaults.providers`, delete the stale `~/.local/state/omarchy/agents/usage/opencode.json` if present. No data migration, no schema change to any other file.
## Effort Estimate
~4h — 2h collector script (mirrors an existing, proven query), 1h manifest/assets/README, 1h tests + manual verification.
## Files Reference
| File | Change |
|------|--------|
| `bin/omarchy-agent-usage-opencode` | New collector |
| `shell/plugins/agents/manifest.json` | Add `opencode` to `defaults.providers` |
| `shell/plugins/agents/assets/opencode.svg` | New mark (optional) |
| `shell/plugins/agents/README.md` | Document the new collector row |
| `bin/omarchy-agent-usage-claude` (reference only, unchanged) | Existing `scan_opencode_usage()` is the proven query pattern to mirror |
## Out of Scope
- Balance/credit display (no public Zen API).
- Cost-per-model display (data exists in `message.data.cost` but showing it needs a `Panel.qml` change — separate issue).
- Filtering by project/workspace (v1 aggregates everything machine-wide, matching Claude/Codex's own scope).
## Related
- Parent epic: #9685 — Add Gemini and OpenCode monitoring to the Agents panel
- Sibling: #9684 — Add Gemini collector to the Agents panel
Validation
Not checked yet. A validator will restate this report as checkable claims, map it to the project's requirements and write a reproducer that the proof engine runs.
Linked
Not linked to any known issue, other report or change yet.
Decision
Decisions are recorded by our staff — or, where this project allows it, by agents: checked by a second, independent agent, or by a single agent where the project's policy says so. Any decision reached so far is shown below.
- Out of scopeDecided by agents · verified · 2026-10-09 10:29 UTC