Watch
1
0
Fork
You've already forked SouveraineOS
0
SouveraineOS/docs/SETTINGS-APP-PLAN.md

180 lines
9.4 KiB
Markdown

# Souveraine shell — plan (2026-07-13)
## What this is now
`qs -c souveraine` — our own quickshell config, composed by `deploy.sh`:
our files (shell.qml, SouveraineFamily, services/, modules/settings/) are
symlinked from this repo; untouched ii directories are borrowed as whole-dir
symlinks; directories where we override any file are composed file-by-file.
ii's tree stays pristine — no overlay symlinks, no `.upstream` backups. We
step on end-4's toes nowhere; we borrow deliberately and vendor per-directory
only when a reason forces it.
`SouveraineFamily.qml` is the convergence scoreboard: one family, both modes
(desktop + phone). Panels that differ by form factor get an
`extraCondition: Config.options.souveraine.phone` gate; a panel is
"homogenized" when its gate is deleted. No `panelFamily` switching — the
config loads SouveraineFamily, period.
Live on laptop + phone as of 2026-07-13. Hyprland flipped: laptop via the
`qsConfig` var, phone via sed across its 4 hardcoded `qs -c ii` sites
(backup: `hyprland.lua.bak-souveraine-config`).
### The Settings app
`souveraine/settings-phone.qml` — purpose-built mobile shell (list → push →
back, 68px finger rows, fullscreen, no titlebar), launched by
`settings-launch.sh` (imports compositor env from the user manager) via
`souveraine-settings.desktop` in the phone's app grid. Page registry shape
`[{name, icon, component}]` is identical to desktop settings.qml, so pages
are interchangeable. Pages edit `Config.options` (JsonAdapter → config.json,
hot-apply + persist).
Current pages: Device (souveraine.phone flag + future per-device overrides),
Lock screen, Dock, Pill, Keyboard, About (ii's stock page verbatim).
## Doctrine — "tie back down"
Two tiers, nothing app-private:
1. **Shell settings**`Config.options.*` → config.json. Idempotent,
survives redeploy, diffable. Zero new persistence.
2. **System settings** → the owning daemon, live: NetworkManager, ModemManager
(mmcli -J), bluez, UPower, brightnessctl. The app is a *view* over system
state — kill it and the system is still the truth. No shadow copies, no
sync jobs. Privileged writes via polkit (`pkexec` — setuid fixed
2026-07-13, Pixel3Arch gap #7), zero sudo.
## Upstream drift — the decision (2026-07-13)
Our overrides were forked against the **phone's vintage** of ii. The laptop
runs a **newer** ii. Drift is large and one-directional. The question is not
"rebase everything" — it's "which upstream additions do we actually want,
and which are desktop features we're deliberately not running on a
phone-first shell."
**Laptop-upstream additions we do NOT have:**
- `background.widgets.{visualizer,stats,systemResources}` — desktop widgets
(the pctrade-style widget system landed upstream). Phone doesn't use these.
BUT: borrowed `Background.qml` reads `Config.options.background.widgets.*`
unconditionally → TypeError spam on laptop. **Fix: backport the keys into
our Config.qml (small surgical add), don't pull the widget machinery.**
- `claudeUsage` — Claude Pro/Max subscription gauge in the bar. Want later.
- `fileSearch` — indexed file search in the launcher. Want later.
- `sidebar.width`/`widthExtended`, AiChat `fontSize` live-binding. Want.
- `dpmsTimeout`, `unlockHook`, `autoIdleInhibit`, `termBgTone` — small knobs.
- GlobalStates super-press timing (`superPressTime`,
`shouldSuppressSuperReleaseSearch`) — press-and-hold-super suppresses
search. Conflicts with our `dockRevealPulse` patch (both touch the
super-release block). **Rebase needed eventually; not breaking anything
today.**
- Ai.qml: OpenAI Responses API strategy, `thoughtSignature`, FileView chat
save. Our Ai.qml is heavily customized (no hardcoded models, Bifrost
server, agent/resume) — **rebase here is the dangerous one; do carefully
or not at all.**
**What we have that upstream DROPPED:**
- `Config.options.dock.stacks` (fan-out stacks, "stackId|appId,appId") —
upstream removed it. Our `DockStack.qml` arc feature is ours alone now,
not just forked. Keep.
### Drift action items (priority order)
1. **Backport `background.widgets.*` keys into our Config.qml** — kills the
laptop TypeError spam. Small, surgical, no widget machinery pulled in.
2. GlobalStates.qml — rebase `dockRevealPulse` onto upstream's super-press
rewrite. Both touch the same block.
3. Ai.qml — decide: carry our customizations forward on the old base (safe,
current path) or rebase onto upstream's Responses-API Ai.qml (risky, gets
us thoughtSignature + FileView). Defer until we want one of those.
4. SidebarLeft/Right/Overview — dedupe the OSK flee-fix (15 lines triplicated)
into one place after any rebase.
5. Don't rebase dock/osk/TaskbarApps unless a specific breakage forces it.
## Pages still to build (deferred, "in time")
- **Display** — brightness (Brightness service), screen toggle
(`blueline-screen-toggle`), idle/suspend timeouts. hypridle.conf is
user-owned: regenerate whole from template, don't sed.
- **Network** — WiFi via existing Network service; **Cellular** needs a new
`services/Cellular.qml` wrapping `mmcli -J` (data toggle, APN, signal,
operator, SIM PIN). The real new work.
- **Bluetooth** — BluetoothStatus exists, but org.bluez activation fails on
the phone (journal, every boot). Fix the service before building UI on it.
- **App health check** — surfaced as a wanted page; not built.
- **Dock pins/stacks editor** — list editor with rename; consumes the staged
`renameStack`/`stackName` plumbing in TaskbarApps/DockStack.
## Other open items
- Phone cold-boot verification (autostart line flipped, unproven until next boot).
- `souveraine.phone` defaults false; Device page exposes the toggle but
deploy.sh --phone doesn't flip it. Tying it down on phone deploy would
satisfy idempotency doctrine.
- Services rename to be more "souveraine-esq" — deferred.
- Licensing sweep — see ~/Projects/MAKE_PROPER_LICENSES_FOR_ALL_PROJECTS.md.
## Ecosystem — the framework basics (2026-07-13)
Reference studied: `PostMarketOS-Blueline/references/phosh` (full source
checkout). Phosh's shell is built on three primitives we can learn from
without copying its C: `PhoshLayerSurface` (every visible thing subclasses
it), the zwlr_layer_shell_v1 layer it sits on (BACKGROUND/TOP/OVERLAY), and
`zphoc_stacked_layer_surface_v1` — phoc's extension for ordering
layer-surfaces above/below each other *within* a layer (bare wlr can't).
Plus a `PhoshState` bitmask (NONE / MODAL_SYSTEM_PROMPT / BLANKED / LOCKED /
SETTINGS / OVERVIEW) that the shell reads to gate layer visibility —
`use_top_layer = !phosh_shell_get_locked()` is the canonical line. State
drives layer visibility, not the reverse.
Note: `PhoshDockedManager` is NOT "the dock" in our sense — it's *hardware*
docking (phone → external display: disables OSK, stops auto-maximize, flips
`is-phone`). It's the system-level analog of our `souveraine.phone` flag:
the phone-becomes-desktop transition. They rhyme; they aren't the same
feature.
### What we're actually building (three pieces, compose incrementally)
1. **Layer registry + ShellState** — declare each surface's layer and
stack-order explicitly, driven by a state bitmask. GlobalStates is
*almost* this already (it has the state bits) but doesn't own the
layer/stack declarations. Quickshell gives us layer-shell via
`PanelWindow` anchors + exclusive zones — same protocol as Phosh, QML
binding not C. Steal the model, not the code.
2. **Live manifest per surface** — the dock (then each major surface)
projects its current state as a queryable structure: pinned apps,
stacks, positions, visibility, mode. This is a *service*, not UI —
`dock.manifest``{pinned, stacks, hidden, mode}`. The dock already
holds this state internally; the manifest is the projection for
external consumers.
3. **Method abstraction for the agent** — the agent does NOT get a new
toolcall integration. Souveraine is already a fully-fleshed harness
with its own integration state; we use THAT. What lives on the dock
side is a small method surface (`dock.pin(appId)`, `dock.restack(...)`,
`dock.reveal()`) with **state checks baked in** — validate inputs,
refuse mutation when the dock is in a state that forbids it (locked,
mid-drag), return real results. The agent calls a guarded method, not
a footgun; it genuinely can't mess up the dock through the abstraction.
### Where the lessons live — Souveraine School
The *teaching* of these methods — what they are, when to use them, the
lessons — is NOT inline in the dock or the agent. It lives in the
Souveraine School, taught to agent and human in proper time. The dock's
job is to expose the abstraction; the School's job is to teach it. Two
separate concerns; do not conflate.
### First artifact
The **dock manifest** is the smallest concrete first step: the dock is
built, working, and already has internal state (pinned apps, stacks,
reveal/pulse). Projecting it into a queryable manifest + guarded method
surface proves the pattern. The layer registry generalizes it after.
### Reference material on disk
- Phosh source: `~/Projects/PostMarketOS-Blueline/references/phosh` (full
C/meson checkout, read-only reference — do not edit).
- end4-pC fork (pctrade): `~/Projects/end4-pC` — studied for the
panelFamilies + background-widget patterns; not copied.
- Pure Maps (Kirigami/QML nav) — referenced in
`Pixel3Arch/docs/car-and-dock-references.md`; not yet pulled as source.