Watch
1
0
Fork
You've already forked souveraine
0
souveraine/surfaces/quickshell
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Fimeg ca44b0be2a shell: the keyboard owns the bottom edge, and nothing measures it
Two bugs with one cause — the bottom edge was being reasoned about
twice, by hand, against a compositor that is gone.

The rail set ExclusionMode.Ignore (exclusive zone -1: ignore what
everyone else reserved, anchor to the whole screen) and then computed
its own lift from the keyboard's height, probed by shelling out to
`hyprctl -j layers`. Under viewtop there is no hyprctl, so every probe
threw a JSON.parse on empty output and logged it in a loop every second
or two, forever, while the margin stayed at a hardcoded fallback
measured against a keyboard that is not the one running. A 200px
fallback against some other height is exactly "the pill spawns in the
middle of the keyboard". Zone 0 with Normal — the idiom SidebarRight and
ReloadPopup already use — reserves nothing and respects what others
reserved, so the compositor anchors the rail to the top of the
keyboard's exclusive zone. Correct at any height, any rotation, across a
swap, with nothing to go stale. The probe, its retry timer and
probeOskHeight() are deleted rather than ported: a second measurement of
a number the protocol already carries is what this class of bug is made
of.

The dock consulted oskOpen only in its empty-desktop branch, below
effectivePinned, so a PINNED dock ignored the keyboard and sat under it.
DockManifest.dockState() has always reported "suppressed-by-osk" and
_blockReason() has always refused mutations with "osk-open" — the
manifest promised a suppression the dock never performed, so the agent's
view of the screen and the screen disagreed. The check moves above
pinning and applies in every state, staying below dockRevealPulse
because an explicit reveal is the one thing that should outrank the
keyboard.

Verified on the phone: the probe loop is gone from the journal. The
resulting pill and dock positions want eyes on the glass.
2026-08-03 16:53:06 -04:00
..
assets/keyboard shell: dock reorder, fullscreen detection fix, idle-power, sessiond, misc shell work 2026-07-22 22:18:20 -04:00
ii-base sessiond: double-tap-to-wake wakes, and the volume keys work again 2026-08-02 18:28:49 -04:00
ii-phone shell: quick toggle types come from the chooser, not a second list 2026-07-31 12:51:10 -04:00
modules shell: the keyboard owns the bottom edge, and nothing measures it 2026-08-03 16:53:06 -04:00
panelFamilies lock: hoist the lock out of the Config.ready loaders so a reload can adopt 2026-07-31 21:25:05 -04:00
scripts/wallpaper shell: dock reorder, fullscreen detection fix, idle-power, sessiond, misc shell work 2026-07-22 22:18:20 -04:00
services shell: wait longer for shell_ready than sessiond takes to answer it 2026-08-02 11:15:44 -04:00
deploy.sh deploy: never --delete into the phone's tree 2026-07-31 12:58:52 -04:00
GlobalStates.qml osk: polkit holds the keyboard open instead of poking it once 2026-07-26 16:56:34 -04:00
II-BASE.md quickshell: pin shared ii base and phone overlay 2026-07-21 18:55:02 -04:00
ii-base.pin quickshell: pin shared ii base and phone overlay 2026-07-21 18:55:02 -04:00
qmldir shell: dock reorder, fullscreen detection fix, idle-power, sessiond, misc shell work 2026-07-22 22:18:20 -04:00
README.md surfaces: commit the quickshell README, stranded since 07-10 2026-07-29 08:39:53 -04:00
settings-launch.sh shell: dock reorder, fullscreen detection fix, idle-power, sessiond, misc shell work 2026-07-22 22:18:20 -04:00
settings.qml shell: dock reorder, fullscreen detection fix, idle-power, sessiond, misc shell work 2026-07-22 22:18:20 -04:00
SettingsWindow.qml shell: dock reorder, fullscreen detection fix, idle-power, sessiond, misc shell work 2026-07-22 22:18:20 -04:00
shell.qml lock: hoist the lock out of the Config.ready loaders so a reload can adopt 2026-07-31 21:25:05 -04:00
souveraine-settings.desktop shell: dock reorder, fullscreen detection fix, idle-power, sessiond, misc shell work 2026-07-22 22:18:20 -04:00

Souveraine quickshell surface

The desktop shell as a Souveraine surface — the primary visual frontend for SouveraineOS, with the TUI remaining the dive-in instrument.

Architecture

  • services/Souveraine.qml — the substrate singleton. The ONE server connection every shell module hangs off: agent inventory, conversation lifecycle, the SSE turn stream (raw events re-emitted via streamEvent(var)), the backchannel (cancelTurn() / interject(text)), and the desktop sensorium — every send carries ambient context (active window, open apps, cursor position) so she perceives the room she is being spoken to in. Device sensors (SouveraineOS positional data from the Pixel 3 kernel path) extend collectAmbient().
  • services/Ai.qml — ii-compat adapter. Keeps the API the illogical-impulse sidebar expects; owns no transport. Shapes wire events into the message objects the existing chat UI renders.
  • modules/souveraine/ (ours: lock, navigation, dial, subconscious), settings/, common/, and ii/ (the files where we override upstream). Each subscribes to the Souveraine singleton. Still pending here: presence (portrait PNGs from memfs, posture state machine), the cockpit pane and the agent manager.

What changes

  • "Models" in the sidebar are Souveraine agents (GET /v1/agents). Picking one starts a conversation with that agent — memory, sensors, subconscious and all.
  • Messages stream over the server's SSE endpoint (POST /v1/conversations/:id/messages), authenticated with the agent's bearer token from ~/.souveraine/server/agents/<id>/api_token.
  • Subconscious surfacings, reflection, and archivist pressure render in the chat as interface notes (dedicated widgets later).
  • Reasoning and sensor activity render inside collapsible <think> blocks.
  • Keys/providers/temperature are owned by souveraine.toml — the sidebar's /key and /temp commands now just point there. The keyring path is dead.
  • Token pressure is fetched after each turn from GET /v1/conversations/:id/tokens.

Portability (KDE / non-Hyprland)

Souveraine.qml itself is compositor-agnostic: quickshell runs on any wlroots-ish Wayland compositor and KWin; window sensing uses the foreign-toplevel protocol (KWin implements it); the cursor read tries hyprctl, then kdotool, then degrades to nothing — ambient never blocks a send. Server autostart is desktop-neutral (systemd user unit, nohup fallback), so opening any surface summons her.

What is NOT portable yet is the chrome: the chat UI is illogical-impulse's sidebar. The path for "I run KDE, can I use this?" is a standalone quickshell config (own ShellRoot + a window hosting the chat/presence modules) that ships Souveraine.qml unchanged — planned once the modules stop being ii-embedded. Same service, same mappings, different shell.

Deploy

./deploy.sh        # compose ~/.config/quickshell/souveraine
./deploy.sh -u     # remove the composed config (ii untouched)
./deploy.sh --phone  # rsync this surface to the phone and deploy there

deploy.sh no longer just swaps Ai.qml — it BUILDS the whole config: our files symlinked from the repo, untouched upstream directories borrowed as whole-dir symlinks into ~/.config/quickshell/ii, and that ii tree itself rsynced from this repo's ii-base/ pin on every run (plus ii-phone/ on aarch64). Never hand-edit ~/.config/quickshell/ii — the next deploy overwrites it. Read the header of deploy.sh; it is the authority.

Requires the server: souveraine server (default http://127.0.0.1:8484, override with ai.souveraineUrl in the ii config).

Wire contract

The server's SSE layer is a full mirror of BackendEvent (see src/api/models.rs::StreamEvent — exhaustive From impls both ways, so a new engine event is a compile error at the seam, not a silent skip). The surface consumes the personification channel: subconscious tokens buffer and flush as one bubble when the N+1 pass ends (subconscious_pass), halts land as body signals, interstitials render by register (cenno = quiet aside, her_voice = gutter passage), primary_complete releases the input while the stream stays open for the subconscious, and context_pressure drives the live token counter. atmosphere/outfit/itinerary are logged, awaiting their shell-chrome layer.

Server-side, the backchannel and verbs exist for every surface: POST /v1/conversations/:id/cancel (interrupt, *[raised hand]* semantics), .../interject (mid-turn notes, queued between turns), GET .../messages (transcript backfill), POST .../fork (/btw side-quests). SendMessageRequest.ambient injects the sensorium note. RemoteBackend rides all of it, so TUI remote mode gained cancel/interject/ fork/resume in the same stroke.

Not yet wired

  • Sidebar UI hooks for cancel (Esc) and interject (type-while-busy) — the service functions exist, the ii chat input doesn't call them yet
  • Conversation resume in the sidebar (server verb exists; surface always starts fresh)
  • Atmosphere/outfit/itinerary driving actual shell chrome (events arrive; modules pending)
  • File/image attachments (server has an image path; surface doesn't use it yet)
  • Regenerate (Souveraine conversations are forward-only by doctrine)
  • "Blank LLM mode" — a memoryless passthrough agent for throwaway questions; needs a server-side agent flavor first
  • Dedicated widgets for surfacing/subconscious bubbles instead of interface notes