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.
Agents panel renders an arbitrarily stale usage record identically to a live one (per-record `updatedAt` is never read)
Reported by millsaj · filed Sep 21, 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
What happens
Every packaged collector stamps its record with updatedAt — omarchy-agent-usage-claude, -codex and -fireworks all write it, and it is in the record on disk:
$ jq -r '.updatedAt, .schemaVersion' ~/.local/state/omarchy/agents/usage/claude-work.json
2026-09-21T22:30:27.840596+00:00
1The panel never reads it. A record whose writer has stopped keeps being drawn as current, indefinitely, with no visual difference from one written a minute ago.
Where it goes
updatedAt appears five times in the plugin, and all five belong to cross-device sync:
Main.qml:654/655andMain.qml:696— writing the sync aggregate and this device's snapshot.Main.qml:274—syncUpdatedAt: aggregateData && aggregateData.updatedAt ? ... : "", read offaggregateData.Main.qml:300—aggregateUpdatedAtMs, same source.
The per-record timestamp is skipped at exactly the point it is in scope. Main.qml:274 sits in the block that builds the display model straight off record, two lines under record.modelUsage and record.hasLocalStats — record.updatedAt is simply never taken.
The two sync properties are then dead ends too: grep -rn "UpdatedAt" . across Main.qml, Panel.qml, Agent.qml and manifest.json returns those five lines and nothing else. Neither syncUpdatedAt nor aggregateUpdatedAtMs is consumed by Panel.qml. So the panel has no freshness indicator on any path, local or synced — the plumbing exists on both and terminates.
How I hit it
A second Claude account via an out-of-tree collector (the pattern in #9383 and discussion #10684). Because omarchy-agent-usage-update only globs $OMARCHY_PATH/bin/, that collector is driven by its own systemd timer. The timer silently disarmed itself and the record froze at Sat 19 Sep 12:22:
$ ls -l ~/.local/state/omarchy/agents/usage/
-rw------- 1 user user 1496 Sep 21 13:57 claude.json
-rw------- 1 user user 2147 Sep 19 12:22 claude-work.json <- two days stale
-rw------- 1 user user 680 Sep 21 13:57 codex.json
-rw------- 1 user user 539 Sep 21 13:57 fireworks.jsonFor two days the panel showed that frozen session and weekly percentage beside the live personal account's, with nothing to tell them apart. I only noticed because the numbers looked implausibly low.
Why it isn't just a third-party-collector problem
The stale writer is what made it obvious, but nothing about the display gap is specific to out-of-tree collectors:
- A packaged collector that starts failing leaves its last good record in place. In
collect(), a failed or non-JSON run logsomarchy-agent-usage-update: <agent> collector failedto stderr and returns1before themktemp/mv, so the existing file is untouched — the panel keeps drawing the last successful run with no indication anything has broken since. - With
syncModeon, a machine that goes offline keeps contributing its last snapshot to the aggregate.
Usage percentages and reset countdowns are exactly the kind of number where "old" and "current" need to be distinguishable. A stale limits reading is not merely out of date — after a window rolls over it is a different window's number.
Suggestion
The data is already there and already plumbed; it just terminates. Past a threshold — a couple of refresh cycles, or the record's own cadence — dim the tab or add a "last updated 2d ago" line. The existing mechanism where an auth or endpoint problem replaces the plan line and repeats in a card looks like the natural home for it.
Happy to send a PR if a shape is preferred.
Environment
- omarchy 4.0.4-1, omarchy-settings 4.0.4-1
- Plugin files as shipped, dated Sep 15 (
/usr/share/omarchy/shell/plugins/agents/) - systemd 261.2-1-arch, Linux 7.2.5-3-omarchy
View raw text
## What happens Every packaged collector stamps its record with `updatedAt` — `omarchy-agent-usage-claude`, `-codex` and `-fireworks` all write it, and it is in the record on disk: ``` $ jq -r '.updatedAt, .schemaVersion' ~/.local/state/omarchy/agents/usage/claude-work.json 2026-09-21T22:30:27.840596+00:00 1 ``` The panel never reads it. A record whose writer has stopped keeps being drawn as current, indefinitely, with no visual difference from one written a minute ago. ## Where it goes `updatedAt` appears five times in the plugin, and all five belong to cross-device sync: - `Main.qml:654`/`655` and `Main.qml:696` — *writing* the sync aggregate and this device's snapshot. - `Main.qml:274` — `syncUpdatedAt: aggregateData && aggregateData.updatedAt ? ... : ""`, read off `aggregateData`. - `Main.qml:300` — `aggregateUpdatedAtMs`, same source. The per-record timestamp is skipped at exactly the point it is in scope. `Main.qml:274` sits in the block that builds the display model straight off `record`, two lines under `record.modelUsage` and `record.hasLocalStats` — `record.updatedAt` is simply never taken. The two sync properties are then dead ends too: `grep -rn "UpdatedAt" .` across `Main.qml`, `Panel.qml`, `Agent.qml` and `manifest.json` returns those five lines and nothing else. Neither `syncUpdatedAt` nor `aggregateUpdatedAtMs` is consumed by `Panel.qml`. So the panel has no freshness indicator on any path, local or synced — the plumbing exists on both and terminates. ## How I hit it A second Claude account via an out-of-tree collector (the pattern in #9383 and discussion #10684). Because `omarchy-agent-usage-update` only globs `$OMARCHY_PATH/bin/`, that collector is driven by its own systemd timer. The timer silently disarmed itself and the record froze at Sat 19 Sep 12:22: ``` $ ls -l ~/.local/state/omarchy/agents/usage/ -rw------- 1 user user 1496 Sep 21 13:57 claude.json -rw------- 1 user user 2147 Sep 19 12:22 claude-work.json <- two days stale -rw------- 1 user user 680 Sep 21 13:57 codex.json -rw------- 1 user user 539 Sep 21 13:57 fireworks.json ``` For two days the panel showed that frozen session and weekly percentage beside the live personal account's, with nothing to tell them apart. I only noticed because the numbers looked implausibly low. ## Why it isn't just a third-party-collector problem The stale writer is what made it obvious, but nothing about the display gap is specific to out-of-tree collectors: - A packaged collector that starts failing leaves its last good record in place. In `collect()`, a failed or non-JSON run logs `omarchy-agent-usage-update: <agent> collector failed` to stderr and returns `1` *before* the `mktemp`/`mv`, so the existing file is untouched — the panel keeps drawing the last successful run with no indication anything has broken since. - With `syncMode` on, a machine that goes offline keeps contributing its last snapshot to the aggregate. Usage percentages and reset countdowns are exactly the kind of number where "old" and "current" need to be distinguishable. A stale limits reading is not merely out of date — after a window rolls over it is a different window's number. ## Suggestion The data is already there and already plumbed; it just terminates. Past a threshold — a couple of refresh cycles, or the record's own cadence — dim the tab or add a "last updated 2d ago" line. The existing mechanism where an auth or endpoint problem replaces the plan line and repeats in a card looks like the natural home for it. Happy to send a PR if a shape is preferred. ## Environment - omarchy 4.0.4-1, omarchy-settings 4.0.4-1 - Plugin files as shipped, dated Sep 15 (`/usr/share/omarchy/shell/plugins/agents/`) - systemd 261.2-1-arch, Linux 7.2.5-3-omarchy
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 19:24 UTC