Files
Panama/docs/superpowers/specs/2026-08-25-escalation-ladder-and-usage.md
T

174 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.