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-338GitHub issuePublicDecided· Out of scope

Agents panel reports SIGN-IN EXPIRED when only the 8-hour access token lapsed

Reported by echelonzero · filed Sep 18, 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

Agents panel reports SIGN-IN EXPIRED when only the 8-hour access token lapsedrevision 1 · captured 2026-09-28 21:23 UTC via poll

System details

Intel i7-1185G7 / Iris Xe, Omarchy 4.0.3-1, Claude Code 2.1.265. bin/omarchy-agent-usage-claude on this machine is byte-identical to quattro HEAD, so the line numbers below are current.

What's wrong?

Leave the machine alone for ~8 hours and the agents panel reports SIGN-IN EXPIRED over stale limits. The sign-in has not expired. Launching claude clears it immediately.

Repro

  1. Sign in to Claude Code, open the agents panel, confirm the limits are live.
  2. Don't run claude for 8+ hours (overnight is enough).
  3. Open the panel: SIGN-IN EXPIRED, "showing the last known limits", bars frozen where they last read.
  4. Run claude in a terminal, then reopen the panel — green again.

Why

collect_limits branches on one field, bin/omarchy-agent-usage-claude:813:

if expires_at_ms > 0 and expires_at_ms <= time.time() * 1000:
    result["limits"] = fallback
    result["usageStatusText"] = "Sign-in expired"

expires_at_ms comes from claudeAiOauth.expiresAt in ~/.claude/.credentials.json (oauth_login, line 584). That is the access token, and it lives about 8 hours. The same file carries claudeAiOauth.refreshTokenExpiresAt — the actual sign-in — which is good for about 30 days. On this machine the access token lapses ~8h after the last claude run while the refresh token still has three weeks on it, and the panel calls that an expired sign-in.

The comment above the branch shows the 8-hour lapse is known and the message is deliberate. The lapse isn't the complaint; the wording is. SIGN-IN EXPIRED in the panel header, plus "Start Claude Code, or run claude auth login, to refresh it", tells a user their session died and invites a re-auth that isn't needed — for a cache that expired on schedule. Users will re-login, which is a browser round trip to fix nothing.

Two ways out, either is fine

  1. Refresh instead of reporting. The refresh token is right there in the file. A collector that mints its own access token keeps the panel live without the CLI, and the "lapsed token" state stops existing.
  2. Say what was measured. Keep the passive behaviour, but distinguish the two. Check refreshTokenExpiresAt first: if that has passed, Sign-in expired is the truth and claude auth login is the fix. If it hasn't, the state is a stale access token — something like Limits paused — run claude to refresh — and the help text should not mention re-authenticating.

Option 2 is the smaller change and removes the misleading half. Worth noting that option 1 has a sharp edge: a rejected refresh makes the CLI drop the stored tokens, so a collector doing its own refresh needs to handle rotation and write-back carefully, and races with a running CLI over the same file.

Which commands actually refresh — measured against a throwaway CLAUDE_CONFIG_DIR copy, so the real credential file was never touched. Useful if anyone documents a workaround:

  • claude auth status does not refresh. Handed an expired token it reports loggedIn:true and leaves the file byte-identical.
  • claude doctor does. Handed an expired token and a deliberately bogus refresh token, it came back with the stored tokens cleared — the server rejected the refresh — while the same run with the network blackholed (HTTPS_PROXY at a dead port) left the file untouched. Only a real round trip to the token endpoint explains the difference.

Locally I've worked around it with a user timer running claude doctor every 6 hours, which keeps the access token inside its window and the panel green. That's a patch on my side, not a fix — the panel is still reporting the wrong thing when it fires late.

View raw text
### System details

Intel i7-1185G7 / Iris Xe, Omarchy 4.0.3-1, Claude Code 2.1.265. `bin/omarchy-agent-usage-claude` on this machine is byte-identical to `quattro` HEAD, so the line numbers below are current.

### What's wrong?

Leave the machine alone for ~8 hours and the agents panel reports `SIGN-IN EXPIRED` over stale limits. The sign-in has not expired. Launching `claude` clears it immediately.

**Repro**

1. Sign in to Claude Code, open the agents panel, confirm the limits are live.
2. Don't run `claude` for 8+ hours (overnight is enough).
3. Open the panel: `SIGN-IN EXPIRED`, "showing the last known limits", bars frozen where they last read.
4. Run `claude` in a terminal, then reopen the panel — green again.

**Why**

`collect_limits` branches on one field, `bin/omarchy-agent-usage-claude:813`:

```python
if expires_at_ms > 0 and expires_at_ms <= time.time() * 1000:
    result["limits"] = fallback
    result["usageStatusText"] = "Sign-in expired"
```

`expires_at_ms` comes from `claudeAiOauth.expiresAt` in `~/.claude/.credentials.json` (`oauth_login`, line 584). That is the **access** token, and it lives about 8 hours. The same file carries `claudeAiOauth.refreshTokenExpiresAt` — the actual sign-in — which is good for about 30 days. On this machine the access token lapses ~8h after the last `claude` run while the refresh token still has three weeks on it, and the panel calls that an expired sign-in.

The comment above the branch shows the 8-hour lapse is known and the message is deliberate. The lapse isn't the complaint; the wording is. `SIGN-IN EXPIRED` in the panel header, plus "Start Claude Code, or run `claude auth login`, to refresh it", tells a user their session died and invites a re-auth that isn't needed — for a cache that expired on schedule. Users will re-login, which is a browser round trip to fix nothing.

**Two ways out, either is fine**

1. **Refresh instead of reporting.** The refresh token is right there in the file. A collector that mints its own access token keeps the panel live without the CLI, and the "lapsed token" state stops existing.
2. **Say what was measured.** Keep the passive behaviour, but distinguish the two. Check `refreshTokenExpiresAt` first: if *that* has passed, `Sign-in expired` is the truth and `claude auth login` is the fix. If it hasn't, the state is a stale access token — something like `Limits paused — run claude to refresh` — and the help text should not mention re-authenticating.

Option 2 is the smaller change and removes the misleading half. Worth noting that option 1 has a sharp edge: a rejected refresh makes the CLI drop the stored tokens, so a collector doing its own refresh needs to handle rotation and write-back carefully, and races with a running CLI over the same file.

**Which commands actually refresh** — measured against a throwaway `CLAUDE_CONFIG_DIR` copy, so the real credential file was never touched. Useful if anyone documents a workaround:

- `claude auth status` does **not** refresh. Handed an expired token it reports `loggedIn:true` and leaves the file byte-identical.
- `claude doctor` **does**. Handed an expired token and a deliberately bogus refresh token, it came back with the stored tokens cleared — the server rejected the refresh — while the same run with the network blackholed (`HTTPS_PROXY` at a dead port) left the file untouched. Only a real round trip to the token endpoint explains the difference.

Locally I've worked around it with a user timer running `claude doctor` every 6 hours, which keeps the access token inside its window and the panel green. That's a patch on my side, not a fix — the panel is still reporting the wrong thing when it fires late.

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 15:46 UTC