Proof Portal

Project overview

Omarchy

ProbeLabs65 findings · 95 requirements

A 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.

Inbox
ReportR-1084GitHub issuePublicDecided· Out of scope

Add OpenCode collector to the Agents panel

Reported by acf1210 · filed Sep 1, 2026 · open at source

Decided: Out of scope — decided by agents · verified 3 days ago.

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

Add OpenCode collector to the Agents panelrevision 1 · captured 2026-09-28 21:24 UTC via poll

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):
  {
    "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

LayerWhatCount
UnitToken/day/model aggregation from a fixture opencode.db (multi-provider, multi-day)+4
UnitEmpty/missing DB → ready:false, no crash+1
Integrationomarchy-agent-usage-update opencode writes opencode.json, leaves siblings untouched+1
ManualLive 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

FileChange
bin/omarchy-agent-usage-opencodeNew collector
shell/plugins/agents/manifest.jsonAdd opencode to defaults.providers
shell/plugins/agents/assets/opencode.svgNew mark (optional)
shell/plugins/agents/README.mdDocument 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
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