No error is a dead end: crash, click, and your agent is already looking

Claude-Session: https://claude.ai/code/session_01Ms2FbjQy31TVf3CEvQhGM8
This commit is contained in:
Gabriel Brown
2026-08-25 12:50:09 -04:00
parent ada0faf1d1
commit cc7d91d09c
43 changed files with 4648 additions and 327 deletions
+15
View File
@@ -92,6 +92,21 @@ surfacing agent usage in the bar, and a plugin registry with a lockfile. The
first shipped, as a bar widget with a switch of its own on Shell Bar; the
second remains deferred, see below.
**Omarchy** ([repo](https://github.com/basecamp/omarchy), MIT — DHH): the
crash-to-agent escalation ladder and the multi-agent usage collectors, both
taken as code, not just ideas, with attribution headers on every derived file.
Specifically: the command-as-notification-data hint (the shell runs the click,
so it survives shell restarts and never blocks the sender), the per-agent argv
launch table with the skill-path-as-fallback trick for harnesses without a
skill mechanism, the coredump PID+signal payload, and the Claude collector's
hard-won honesty — model-scoped limits, cached numbers that expire on window
rollover rather than age, waiting-vs-expired auth as distinct states, and
retry-on-transport-but-not-HTTP-error. The diagnose-crash skill's structure
("rule out OOM first", "never invent function names", "diagnosis reads; it
does not fix") was adapted rather than rewritten, because it was already
right. Their usage panel and menu system were not taken — Panama renders its
own surfaces in its own design language.
### Declined, and why
- **Wallpaper-derived dynamic color** (HyDE wallbash, matugen). The headline
+17 -2
View File
@@ -4,7 +4,7 @@
Do not edit this file. Run `quickshell/scripts/panama-settings-docs`
after changing the schema; a contract fails when this copy is stale.
175 settings across 36 groups. 77 of them are applied to the compositor and confirmed by reading the value back.
183 settings across 37 groups. 77 of them are applied to the compositor and confirmed by reading the value back.
## accessibility
@@ -22,6 +22,21 @@ Found on **Accessibility**.
| **Pointer size**<br>`cursorSize` | 24 px | Applies to the compositor and to applications. Range 1664. |
| **Text size**<br>`textScale` | 1.0 | Scales interface text everywhere; 1.00 is the design size. Range 0.752.0. |
## agents
Found on **System Agents**.
| Setting | Default | What it does |
|---|---|---|
| **Preferred agent**<br>`preferredAgent` | none | Who answers when the desktop offers to investigate something Choices: None, Claude Code, Codex. |
| **Offer to diagnose crashes**<br>`crashDiagnoseOffer` | true | When a program dumps core, the notification carries a click that opens the preferred agent mid-investigation with the crash details in hand |
| **Offer help when the shell fails to reload**<br>`reloadFailureOffer` | true | A broken change to the shell's own configuration offers the failing log to the agent |
| **System Health hands off unrepairable checks**<br>`healthAgentHandoff` | true | A red check with no repair, or whose repair failed, grows an Ask-the-agent button carrying the check's snapshot |
| **Launched agents approve their own tools**<br>`agentAutoApprove` | true | Investigations run without permission prompts. The diagnose skill still holds agents to reading rather than fixing, and root still goes through panama-sudo, reason and all |
| **Collect Claude Code usage**<br>`agentUsageClaude` | true | Limits from Anthropic's usage endpoint, tokens from the local transcripts |
| **Collect Codex usage**<br>`agentUsageCodex` | true | Limits over the Codex app-server, sessions from its local files |
| **Refresh interval**<br>`agentUsageRefreshMinutes` | 15 min | How often the usage collectors ask for fresh numbers, in minutes. Range 560. |
## appearance
Found on **Appearance**.
@@ -380,7 +395,7 @@ Found on **Shell Bar**.
| **Graphics**<br>`showGpu` | true | Show graphics usage beside the workspace indicator |
| **Battery**<br>`showBattery` | true | Show the charge level in the bar, on machines that have a battery |
| **Battery percentage**<br>`showBatteryPercent` | false | Show the exact number beside the battery icon |
| **Claude usage**<br>`showAgentUsage` | false | Show how much of the Claude subscription has been used, beside the other vitals |
| **Agent usage**<br>`showAgentUsage` | false | Show how much of the busiest agent subscription has been used, beside the other vitals |
| **Vitals refresh**<br>`vitalsIntervalMs` | 2000 ms | How often processor, memory, and graphics usage update. Range 50010000. |
## wallpaper
@@ -0,0 +1,173 @@
# The escalation ladder, and usage worth trusting
Approved from mock `agents.html` (2026-08-25). Two builds in one cycle: no failure surface is a
dead end (crash → one click → your agent mid-investigation), and the bar's usage number becomes a
multi-agent panel backed by Omarchy's battle-tested collectors. Borrowed code is MIT — carry
`Copyright (c) David Heinemeier Hansson` + the MIT permission notice in a header comment on every
derived file, and add an Omarchy entry to `docs/UPSTREAM-INSPIRATION.md`.
## Decisions log
| Decision | Choice |
|---|---|
| Scope | Ladder + usage panel, one cycle |
| Ladder surfaces v1 | App crashes, shell reload failures, Health red checks, update/migration failures, plus `panama diagnose` by hand |
| Agent | Configurable via `preferredAgent`; **Claude and Codex both fully supported on the ladder** (per-agent argv table); default `none` — quiet until chosen, like Omarchy |
| Permission posture | Auto-approve (user's explicit choice), behind a toggle; the diagnose skill still teaches reads-not-fixes; root still via `panama-sudo` |
| Usage | Collectors ported near-verbatim (Claude + Codex), Panama-native popover panel, no cross-machine sync |
| Settings home | New `agents` leaf under System |
| Notification click mechanism | Omarchy's command-as-data hint (`panama-exec`), executed by the shell — survives restarts, never blocks the watcher |
## Schema (orchestrator adds first — do not re-add)
| key | type | def | group | notes |
|---|---|---|---|---|
| `preferredAgent` | enum `none/claude/codex` | `none` | agents | `none` = crash toasts carry no action |
| `crashDiagnoseOffer` | bool | true | agents | gates the crash rung (still requires an agent chosen) |
| `reloadFailureOffer` | bool | true | agents | shell-reload rung |
| `healthAgentHandoff` | bool | true | agents | Health-page rung |
| `agentAutoApprove` | bool | true | agents | off → agents launch in their default prompting mode |
| `agentUsageClaude` / `agentUsageCodex` | bool | true | agents | per-collector enables |
| `agentUsageRefreshMinutes` | int 560 | 15 | agents | collector fan-out interval |
`showAgentUsage` stays where it is (vitals) and keeps its meaning; the Bar page row remains, the
Agents page gets the full set (declared mirror in `settings-ownership-contract` if both surface
the same key). New group `agents` needs a `groupPages` route to the new leaf
(`search-routing-contract`).
## The launcher: `bin/panama-agent`
Ported from `omarchy-agent`, trimmed to Panama's needs, attribution header included.
- Reads `preferredAgent` and `agentAutoApprove` from `~/.config/panama/settings.json` with jq at
press time (the power-button precedent) — `none` exits 0 silently.
- `cd "$PANAMA_PATH"` before spawning: the checkout is where the skills, the repo trust, and the
pre-approved diagnostic permissions live.
- Per-agent argv table — **verify every flag against the installed binaries' `--help`, do not
trust the Omarchy source or this spec**: Claude ≈ `claude [auto-approve flag] -- "$prompt"`,
Codex ≈ `codex [auto-approve flag] -- "$prompt"` (Omarchy used `--permission-mode auto` and
`--approve-for-me`; use whatever the real flags are, and the prompting-mode variants when
`agentAutoApprove` is off).
- Spawn: `setsid kitty --directory "$PANAMA_PATH" -e <argv…>` (kitty is the house terminal, its
own health check exists; `--app-id`-style fixed class `panama-agent` so window rules can target
it later).
- `--prompt "text"` input; no `--pick` menu in v1 (the Agents page is the picker).
- Repo `.claude/settings.json` gains a pre-approved allowlist for the read-only diagnostic
commands (`coredumpctl`, `journalctl`, `rpm -q`, `panama doctor`) so even non-auto-approve
launches investigate smoothly.
## The rungs
**1. Crashes.** `bin/panama-crash-watch` gains `COREDUMP_PID` + `COREDUMP_SIGNAL_NAME`
extraction. When `preferredAgent != none` and `crashDiagnoseOffer`, the notification carries the
command as data: `notify-send … --hint=string:panama-exec:"$(printf 'panama-agent-crash %q %q %q %q' pid comm exe signal)"`
with body "Click to diagnose with <Agent>". Otherwise today's actionless notification, verbatim.
Existing session-dedupe and portal-crash rationale untouched. New `bin/panama-agent-crash` ports
`omarchy-agent-crash`: coredump facts + `coredumpctl list` timestamp into a heredoc prompt naming
the `diagnose-crash` skill **with its absolute path as fallback** (the harness-agnostic trick —
this is what makes the ladder work for Codex too), then `exec panama-agent --prompt "$prompt"`.
**2. The `panama-exec` hint.** `services/Notifs.qml`: read hint `panama-exec` into the
notification model (one field, carried through popup persistence like any other).
`modules/notifications/NotificationCard.qml`: on body click, if the entry carries an exec, run it
via `Quickshell.execDetached(["sh", "-c", command])` and dismiss — the branch sits beside the
existing `defaultAction` handling and defers to it when both exist. Security note in-file: the
session bus is local; any sender could carry the hint, which grants nothing an local process
lacks.
**3. Shell reload failure.** `shell.qml`'s `onReloadFailed` (old shell keeps running — it can
still notify): when `reloadFailureOffer` and an agent is chosen, send a notification through the
shell's own Notifs with the exec hint → new `bin/panama-agent-reload` builds the prompt from the
failure string plus the last ~40 matching journal lines.
**4. Health page.** Red check with no repair, or whose repair just failed → an "Ask the agent"
SettingsButton beside it (visible only when `healthAgentHandoff` and an agent chosen), running
`panama-agent --prompt` with the check's JSON snapshot (`panama doctor check <id>`) embedded.
**5. Update/migration failures.** The failure summary in `install` gains one line:
`Hand it to an agent: panama diagnose`. `bin/panama-migrate-notify`'s failure path likewise.
**6. `panama diagnose` (cmd_diagnose).** By-hand rung: bundles `panama doctor --summary`, the
last journal errors, and "what feels wrong" free text (`panama diagnose [words…]`) into a prompt
and hands it to `panama-agent`. House three-touchpoint rule + README list (readme-contract).
## The skill: `skills/diagnose-crash/`
Written by the orchestrator, shipped un-gated like the other two, structure adapted from
Omarchy's: triggers name the notification and `panama-agent-crash`; `coredumpctl info <pid>`
first and read the command line; rule out OOM before blaming the program; correlate the crash
time against recent package updates and journal context; Fedora debuginfod for symbols; the
security rule (a core holds secrets — scratch files via mktemp, deleted after); "never invent
function names"; "diagnosis reads; it does not fix"; report structure. Claims auto-pinned by
`skills-contract` (it already scans every skill in `skills/`).
## Usage collectors and panel
- `config/dot/quickshell/scripts/panama-agent-usage-claude` — port of Omarchy's Python collector
(attribution header): OAuth usage endpoint + model-scoped `limits[]`, transcript scan with
message-id dedupe and scan cache, cached-limits-expire-on-window-rollover, waiting-vs-expired
auth states, `retryAdvised` transport/HTTP distinction, percent-scale voting. Keep Panama's
secrets discipline: the token stays out of argv and out of the record (their in-process Python
read already satisfies it; the contract proves it).
- `…/panama-agent-usage-codex` — port: app-server JSON-RPC limits, session-file token stats with
the last_token_usage rule.
- `…/panama-agent-usage-update` — fan-out: runs enabled collectors in parallel, `jq -e` validity
gate, atomic writes to `$XDG_STATE_HOME/panama/agents/usage/<agent>.json`.
- `services/AgentUsage.qml` → directory model: one FileView per record file, discovered by
listing the dir; aggregate `headline` = fullest window across enabled agents; timer from
`agentUsageRefreshMinutes`, running only while `showAgentUsage`.
- `modules/bar/AgentUsageWidget.qml`: keeps the two-tier amber-75/red-90 coloring and the
hide-when-nothing rule; click now opens the panel popover (right-click keeps Settings).
- New `modules/bar/AgentUsagePanel.qml` (or popover home matching how other bar popovers are
built — follow the house pattern found in the code): per the mock — agent tabs, tier chip,
updated-ago line, limit meters with reset countdowns (model-scoped rows included), tokens by
day (today bolded), by-model bars, honest auth states. No keyboard-nav requirement in v1;
Escape closes like every popover.
- Old `scripts/panama-agent-usage` retires (delete; its consumers migrate). The five pins of
`tests/quickshell/agent-usage-contract` survive against the new collectors: token never in
argv, never in any record, credentials never written, expired token → no request + honest
state, widget hidden unless asked-for AND real numbers. Extend for: per-agent enables honored,
record validity gate, atomic write.
## New settings leaf
`agents` under the System category: 4-file ceremony (SettingsRoutes categories entry,
SettingsShell case + Component, qmldir, `AgentsPage.qml`), search entries, regen docs+commands
(orchestrator). Page per the mock: preferred-agent picker (install-state aware: show "not
installed" detail for an absent binary), the four escalation toggles (auto-approve copy states
the trade in plain words), usage card (master switch mirroring `showAgentUsage`, per-agent
enables, refresh interval).
## Contracts
- `crash-watch-contract`: extend for PID/signal fields and hint gating (none-agent → no hint;
chosen → hint present; never both mechanisms).
- `agent-usage-contract`: as above.
- New `tests/quickshell/panama-agent-contract`: hermetic — stubbed `settings.json` +
stub `kitty`/`claude`/`codex` on PATH; `none` → silent exit; claude/codex → correct argv shape
including the auto-approve/prompting variants; prompt passed as one argv element; cwd is the
repo. panama-agent-crash: prompt contains pid/comm/exe/signal + the skill path; never runs a
real agent (stub PATH). NOT in the desktop-hijacking ledger — it must run stubbed.
- `skills-contract` covers `diagnose-crash` automatically once the skill lands.
- `settings-nav`/`search-routing`/`settings-docs`/`readme-contract` obligations as usual.
## Ownership (disjoint)
- **Orchestrator**: this spec; schema keys first; the `diagnose-crash` skill;
`UPSTREAM-INSPIRATION.md` + license attribution file check; docs/commands regen; README count;
seam audit.
- **Agent A — usage**: the three collector scripts, `AgentUsage.qml`, `AgentUsageWidget.qml`,
`AgentUsagePanel.qml` (+ its qmldir if bar modules use one), `agent-usage-contract`, deletion
of the old collector.
- **Agent B — ladder scripts**: `bin/panama-agent`, `bin/panama-agent-crash`,
`bin/panama-agent-reload`, `bin/panama-crash-watch`, `bin/panama` (`cmd_diagnose`), `install`
failure line, `bin/panama-migrate-notify` failure line, `.claude/settings.json` allowlist,
`crash-watch-contract`, `panama-agent-contract`, README subcommand row.
- **Agent C — shell & settings UI**: `services/Notifs.qml` (hint field), `NotificationCard.qml`
(exec branch), `shell.qml` (`onReloadFailed` rung), `modules/settings/HealthPage.qml` ("Ask
the agent"), `AgentsPage.qml` + routes/shell-case/qmldir, search entries in
`SettingsSearch.qml`.
Standing rules apply: live desktop (valid QML every save, journal checks), no real agent
launches or notifications left uncleaned during builds, contracts as you go, never the
desktop-hijacking set unannounced.