# Applications, Storage & Snapshots redesign Approved mock: `home-mocks/applications.html` (scratchpad, :8642). Spec wins over mock on conflict. Scope: the Applications *tab* (Gaming and Screen Intelligence untouched) plus the System category's Storage and Snapshots tabs, folded into this phase by decision. ## Goals 1. **Applications becomes an app manager**: searchable installed list (DesktopEntries + flatpak metadata), flatpak uninstall, honest system-package rows, permission summaries, autostart toggle per app, jump chips to the app's rules elsewhere. 2. **The panama apps catalog goes native**: category chips → entries with installed state, installing through the same dnf/flatpak paths (polkit prompts). Same files as the CLI. 3. **Defaults modernized**: role dropdowns replace the hand-rolled accordion; a single-file-type override ("One file type") for when a role's family is too broad. 4. **Storage**: proportional breakdown bar with honest captions; folder bars share ONE scale; "Clean up, honestly" — itemized, sized, click-each, nothing pre-selected, nothing nags (the anti-racket rules are contract-pinned); the duplicate container affordances merge. 5. **Snapshots**: retention becomes editable (wire the caller-less `Snapshots.setRetention`); the file browser becomes its own card that opens regardless of source-card state (fixes the collapsed-card bug); rollback stays absent (contract). Non-goals: dnf package removal from Settings (honest refusal row instead), full flatpak permission *editing* (summary + Open Flatseal when installed), per-app storage classification beyond the flatpak sizes, portal-grant editing, snapshot space measurement (quotas honesty stays). ## New helper: `scripts/panama-applications` (pinned verbs) House discipline (validated inputs, JSON out, mutations return fresh state, bounded timeouts): - `flatpaks` → `[{ id, name, size, origin }]` (from `flatpak list` machine-readable columns). - `permissions ` → `{ summary: [human strings], raw: {...} }` from `flatpak info --show-permissions` — curated buckets: Camera, Microphone, Full file system access, Home folder, Network, Devices; unknown keys summarized honestly, never dropped silently. - `uninstall ` → `flatpak uninstall --noninteractive` (app only; a second verb `unused-runtimes` lists what `--unused` would remove, and `clean-unused` removes them — the Storage cleanup row uses these). - `catalog` → categories + entries from `setup/packages/extras/*` (same parser rules as `setup/lib/extras-catalog`: `flatpak: | Label`, bare dnf names, indented continuations), each entry `{ id, label, kind: flatpak|dnf, installed }` (installed via flatpak info / rpm -q). - `install ` → flatpak: `flatpak install --noninteractive flathub `; dnf: `pkexec dnf install -y `. Refuses ids not present in the catalog files (no arbitrary package installation through this surface — contract-pinned). ## Extended helpers - `scripts/panama-default-apps`: `search-types ` → matching MIME types with their current handler + candidate apps; `set-type ` → `xdg-mime default` (validated against installed desktop entries). Role behavior untouched. - `scripts/panama-disks`: `breakdown` → segments `{ home, applications, caches, system, free }` in bytes — home = the scan targets under ~ minus caches, applications = flatpak app+runtime sizes (user-readable sums), caches = ~/.cache, system = used − the others ("System & everything else" caption — honest arithmetic remainder), free from the fs. `cleanables` → `[{ id, label, detail, bytes, privileged }]` for: cache (~/.cache), trash, flatpak-unused, dnf-cache (privileged). `clean ` executes exactly one, refusing unknown ids; trash via `gio trash --empty`; cache via a guarded rm of ~/.cache/* (never follows symlinks out). - `scripts/panama-snapshots`: retention already supported (`set-retention`); add `set-retention` argument validation for the three horizons if not already split (hourly/daily/weekly numbers 0-50). ## Services (A) - **`services/AppLibrary.qml`** (new): merges `DesktopEntries.applications` with the flatpak metadata (id-matched via the entry's flatpak export), exposes `apps: [{ entryId, name, icon, kind: flatpak|system, flatpakId, size }]`, `permissionsFor(id)` (cached), `uninstall(flatpakId)`, catalog state (`categories`, `entriesFor(cat)`, `install(...)`), `busy/lastError`, seam `PANAMA_APPLICATIONS_HELPER`. - **`services/DefaultApps.qml`**: `searchTypes(query)`, `setType(mime, desktopId)` wrappers. - **`services/Disks.qml`**: `breakdown`, `cleanables`, `clean(id)` wrappers; cleanables refresh after any clean. - **`services/Snapshots.qml`**: nothing new needed beyond confirming `setRetention`'s shape matches three-horizon editing; adjust if it takes a single string. ## UI (B) **ApplicationsPage.qml** rebuilt: Installed applications card (search field filters name + id; rows: letter/icon tile, name + source badge, subtitle id·size or "Installed by the system package manager"; expanded: Permissions row (+ Open Flatseal when installed), Start with the session (autostart toggle — creates/toggles the autostart entry for that app), "Elsewhere in Settings" jump chips (shown only where a rule exists: Notifs.appRule customized/present → notifications; app in AudioDevices applications → sound; PrivacyPage relevance is static — link when the app id appears in its rules if cheaply knowable, else omit), Uninstall (flatpak, two-stage danger) or the honest dnf refusal row with the exact command). Browse-the-catalog card (category chips, entry rows, Install with polkit caption for dnf entries, INSTALLED badge). Default applications card: role dropdowns via OptionPickerRow-style (candidates from the existing role matching; keep all 10 roles + family-count details), then the "One file type" row expanding to a search field over `searchTypes` with per-type app pickers. Autostart card: existing rows restyled with the standardized confirm; compositor autostart row kept read-only. The Search card stays but the hardcoded "Super+Space" is replaced by a live `Keybinds` lookup (launcher description match, literal fallback). **StoragePage.qml**: breakdown stack bar + legend at top (honest captions; "System & everything else" for the remainder); Folders card bars share one scale (the disk, or the largest — pick the DISK so it's comparable to the free-space bar, with a note); "Clean up, honestly" card from `cleanables` (row per item: label, honest cost detail, size, Clear… with two-stage confirm; privileged rows carry the password caption; zero-byte rows render inert with "nothing to do"); the "Unused container images" kitty-terminal row is REMOVED (the Containers card below already routes properly — one affordance, not two). Drive/Filesystems/ Removable/Swap cards kept. **SnapshotsPage.qml**: per-config Keep row becomes three dropdowns (hourly/daily/weekly → setRetention); the browser moves OUT of the volume card into its own card rendered whenever browsing state is set (opening from a collapsed card now works — this is the bug fix); timeline/preview/expander kept; Space card kept with its honesty. ## Search & docs (C) New entries: Installed applications, Uninstall an application, Application permissions, Install applications (catalog), Autostart, File associations → applications; Clean up storage, Application caches → storage; Snapshot retention → snapshots. Docs regen only if schema changes (none expected — verify). ## Contracts (C — write, never run) - `applications-settings-contract`: reconcile with the rebuilt page (role labels, card titles, AutostartAppPicker, the bun matcher extraction). - NEW `app-library-contract`: fixture-driven (stub flatpak/rpm): catalog parser agreement with `setup/lib/extras-catalog` rules, install refuses off-catalog ids, uninstall argv shape, permissions summary buckets, dnf never invoked for removal anywhere in the helper. - `disks-contract`: extend — breakdown arithmetic honesty (segments sum ≤ used, remainder labeled), cleanup rules: every cleanable itemized with bytes, nothing auto-selected, no cleanable executes without its id being explicitly passed, cache rm is guarded, trash via gio. Pin the anti-racket copy stance (no urgency language). - `snapshots-contract`: extend — setRetention wired from the page, browser renders independent of the volume card's open state, rollback still absent. - `default-apps-contract` family rules untouched; new needles for set-type validation. - Backlog: Phase 10. README count line if count changes. ## Agent ownership (parallel) - **A**: `scripts/panama-applications` (new), `scripts/panama-default-apps`, `scripts/panama-disks`, `scripts/panama-snapshots` (only if retention args need splitting), `services/AppLibrary.qml` (new), `services/DefaultApps.qml`, `services/Disks.qml`, `services/Snapshots.qml`. - **B**: `modules/settings/ApplicationsPage.qml`, `StoragePage.qml`, `SnapshotsPage.qml`, new components + qmldir. - **C**: `services/SettingsSearch.qml`, contracts above, backlog, README count line. Hard rules for everyone: no live mutations (no flatpak install/uninstall, no dnf, no rm, no gio trash, no snapper writes, no xdg-mime writes) — read-only probes and stub fixtures only; no test runs; valid QML/Python at every save. B programs against the pinned APIs.