Watch
1
0
Fork
You've already forked souveraine
0
Commit graph

250 commits

Author SHA1 Message Date
Fimeg
ffe4157e1c settings: show sleep inhibitor state, update stage names
IdleConfig.qml now shows:
- Full IdleCoordinator state names including Suspending/Asleep/Waking
- Sleep inhibitor held/released status (from SessionEvents)
- stepUp grant TTL presence

hypridle.conf changes (NOT in repo — apply to ~/.config/hypr/):
- lock_cmd simplified to loginctl lock-session (SessionEvents catches
  the Lock signal); hyprlock fallback if quickshell is down
- before_sleep_cmd REMOVED — SessionEvents handles PrepareForSleep
- inhibit_sleep REMOVED — SessionEvents holds the delay inhibitor
- suspend_cmd prefers loginctl over systemctl for PrepareForSleep signal
2026-07-14 21:39:01 -04:00
Fimeg
ae9ef41bb1 hash-chained audit trail for session transitions
SessionAudit.qml — tamper-evident JSONL log of all session state changes:
- Lock/unlock, secure/insecure transitions
- Idle state machine transitions (active/dimmed/lock/sleep/wake)
- PrepareForSleep, external lock signals, inhibitor lifecycle
- Step-up auth success/failure, break-glass issued/consumed/expired
- Grant expiry and revocation

Hash chain: each entry includes md5 of previous entry. Sequence numbers
detect gaps. Chain is validated on startup from the last entry.

Uses Qt.md5() (not SHA256 — not available in QML). Advisory tamper-
evidence, not cryptographic security. Log at:
~/.local/share/souveraine/session-audit.jsonl
2026-07-14 21:31:23 -04:00
Fimeg
377b82999d break-glass: one-time emergency grant with journaling
StepUpAuth.breakGlass(actionFamily, reason):
- Requires a non-empty reason (logged prominently)
- 60-second TTL (not the normal 5 minutes)
- One-time: consumed on use via isBreakGlass()
- Cannot be issued while session is locked
- Cleared on lock (fail-closed)
- Tracked separately from normal grants for audit

Souveraine.send() now checks break-glass before blocking on step-up.
Break-glass bypasses normal PAM auth — the user declared an emergency.
2026-07-14 21:24:57 -04:00
Fimeg
61bdc5360f session trust: step-up send gating + lock-time response redaction
Step-up send gating:
- Souveraine.send() returns 'step-up' when auth is required
- Ai.sendUserMessage() triggers StepUpAuth.requestAuth('send') on
  step-up, retries on success, shows message on failure
- Extracted _startStreaming() helper for reuse after auth retry

Lock-time response redaction:
- Ai.qml watches GlobalStates.screenLocked
- On lock mid-stream: replaces displayed content with '[content hidden
  until unlock]', preserves rawContent for post-unlock display
- Enforces SESSION-TRUST-ARCHITECTURE.md requirement: lock during
  personal agent output hides it

Trust boundary matrix updated.
2026-07-14 21:13:50 -04:00
Fimeg
a8fd510dc7 session trust phase 1: logind ingress, sleep inhibitor, step-up auth
Phase 1 of the SouveraineOS homogenization — the three highest-priority
gaps from the session trust architecture:

New files:
- services/SessionEvents.qml — logind event ingress (PrepareForSleep,
  session Lock signal) via gdbus monitor; delay-mode sleep inhibitor
  held from startup, released only after WlSessionLock.secure
- services/StepUpAuth.qml — step-up PAM authentication with short-lived
  in-memory grants per action family; revokes on lock/timeout/failure
- TRUST-BOUNDARY-MATRIX.md — every session operation classified by
  caller type, auth gate, and enforcement status

Modified:
- IdleCoordinator: extended with Suspending/Asleep/Waking states for
  the sleep lifecycle; wires to SessionEvents when present
- Session.qml: added sleep inhibitor kind, stepUp/sleepInhibitor
  state in IPC projection, boot-time IPC audit log
- Config.qml: added lock.stepUp config section (enabled, grantTtlMs)
- LockConfig.qml: added step-up authentication settings section
- deploy.sh: added SessionEvents and StepUpAuth to manifest
- SESSION-TRUST-ARCHITECTURE.md: marked phase 1 items as done
- REFERENCE-EXTRACTION.md: marked build order items as done
2026-07-14 20:48:46 -04:00
Fimeg
4d5690b547 quickshell: Idle & sleep settings page
Live idle stage readout (polled over session IPC), the native-coordinator
toggle, and dim/lock timers. Timers grey out while the coordinator is off.
2026-07-14 20:17:43 -04:00
Fimeg
e31c3aaf62 quickshell: first-party lock/nav/session layer, retire the pill
Grows Souveraine's own surfaces on top of the borrowed ii shell and drops
the separate pill shell in favor of one integrated navigation rail.

Session arbiter (functions/Session.qml): probe logind's Can* methods over
busctl instead of guessing from installed binaries -- the answer carries the
polkit tier (yes/challenge/na), so a swapless phone reports hibernate as na
and refuses honestly rather than firing a verb that no-ops. Verbs run through
a Process that logs exit codes and tracks lastAction; refusals log too. The
busctl output is parsed with awk, not a sed regex buried under four escaping
layers -- the sed version returned nothing on the phone and left every
capability stuck at "unknown" (invisible on the laptop, where timing masked
it). Every structured result is JSON-over-string; quickshell maps a var
return to void.

Lock trust: screenLocked (the shell's lock request) is now distinct from
screenLockSecure (WlSessionLock.secure, the compositor's acknowledgement,
mirrored from LockScreen). Cards that disclose personal data gate on secure,
not on a button press. LockContentPolicy centralizes the ambient/personal/
step-up tiers so no card grows its own private rule.

New first-party namespace modules/souveraine/: LockMediaCard, LockSurfaceHost,
SystemGestureRail -- owned surfaces, not ii patches. IdleCoordinator gives one
staged idle vocabulary (dim/lock) gated behind nativeCoordinatorEnabled, off
until the native Wayland idle-notify is verified on the Pixel compositor;
hypridle stays the adapter. WallpaperAssets selects aspect-aware variants for
phone-vs-laptop display shapes.

Pill retired: pill/shell.qml and PillConfig gone, replaced by NavigationConfig
and the gesture rail. Hyprland starts qs -c souveraine directly; no secondary
shell, no qsConfig flip.

Verified on the phone: session.* reports challenge/na correctly, hibernate
and unlock refuse, inhibit round-trips with its reason.
2026-07-14 20:00:57 -04:00
Fimeg
cecde3bac2 quickshell: session arbiter + fix IPC returns silently dropping payloads
Fork ii's Session singleton and add a sessionctl.* surface.

The IPC bug is the important half. Quickshell marshals exactly five types
(string/int/bool/double/color) and maps a `var` return to VOID, discarding
the payload with no error -- src/io/ipc.cpp, "void and var get mixed by qml
engine". dock.*, shell.* and apps.* were all declared `: var`, so they
registered as `(): void` and returned nothing at all. The {ok, reason}
contract has never once reached a caller. All of them now return JSON as a
string, which is what actually crosses the socket.

Session: upstream fires `systemctl X || loginctl X` detached and throws the
exit code away. Fine on a desktop with someone at the keyboard, not fine on
a phone where the shell is the session manager and a verb that silently does
nothing leaves you believing the machine is suspending when it isn't. So:
probe loginctl/systemctl/hibernate once instead of assuming, run verbs
through a Process that logs the exit code, and refuse honestly when the
machine can't do the thing (the phone has no swap -- hibernate now says so
instead of no-opping). Every upstream verb keeps its name and call sites.

Inhibits carry a mandatory reason and get a cookie; state() lists who is
holding the machine awake and why. "Why didn't it sleep" is now answerable.
unlock() is refused by design -- the lock is the credential gate, so no IPC
caller routes around the PIN pad.

Named sessionctl, not session: ii's SessionScreen already owns "session",
and quickshell drops duplicate targets silently rather than erroring.

Idle: drop the 2>/dev/null and run hypridle through a Process, so a unit
that fails to come back is a log line instead of a flat battery.

Verified on the laptop: inhibit stops hypridle, uninhibit brings it back.
2026-07-14 18:31:59 -04:00
Fimeg
c78c5510af quickshell: run as qs -c souveraine + dock/shell/apps method surfaces
Own config name composed by deploy.sh from our files + pristine-ii dir
borrows; ii tree stays untouched. One SouveraineFamily, two modes gated
on souveraine.phone.

Three guarded IPC surfaces for the agent (via Souveraine's harness, not
a new integration): dock.manifest/pin/unpin/restack, shell.surfaces/state
(layer registry, live-derived), apps.list/get/find/categories (.desktop
scan). Refusals are result shapes, not errors.

Settings app split into per-domain pages (Device/Lock/Dock/Pill/Keyboard).
Config backports (background.widgets, claudeUsage, fileSearch) kill the
laptop TypeErrors.
2026-07-14 15:03:07 -04:00
Fimeg
72f5169458 quickshell: touch PIN lock screen for the phone
The OSK is layershell and can't rise above a session lock, so the lock
surface carries its own keypad. Lock state persists to states.json so a
qs crash while locked comes back locked; with lock.launchOnStartup the
lock screen is the greeter (greetd autologins straight into Hyprland).
Keypad gated behind lock.touchKeypad so desktop deploys keep the stock
surface.
2026-07-13 15:19:59 -04:00
Fimeg
620c6778ce delivery: separate phone and laptop surface profiles 2026-07-13 13:11:31 -04:00
Fimeg
79f3b2fa4b delivery: scope safe QuickShell surface adoption 2026-07-13 13:01:31 -04:00
Fimeg
048f180105 docs: bootstrap private pacman archive securely 2026-07-12 22:46:37 -04:00
Fimeg
c8c72ecbf2 ci: split signed pacman databases by architecture 2026-07-12 22:19:44 -04:00
Fimeg
16ba8cfbf4 docs: bootstrap pacman from local Gitea 2026-07-12 21:58:02 -04:00
Fimeg
4427389d9c ci: authenticate ArchDev source clone 2026-07-12 21:45:46 -04:00
Fimeg
29e204e56e ci: restore strict clippy gate 2026-07-12 21:38:16 -04:00
Fimeg
f52edd402b ci: use local Gitea token for tuie 2026-07-12 21:28:58 -04:00
Fimeg
e0d742d797 ci: authenticate pinned tuie clones 2026-07-12 21:26:08 -04:00
Fimeg
3a83666ef5 ci: sign multi-architecture package repository 2026-07-12 21:11:34 -04:00
Fimeg
e0c8128832 ci: publish aarch64 pacman package artifacts 2026-07-12 20:57:00 -04:00
Fimeg
ffa8b498a3 build: make aarch64 linker sysroot-safe 2026-07-12 18:00:31 -04:00
Fimeg
e5813ab6c9 quickshell: make conversation resume explicit 2026-07-12 16:58:59 -04:00
Fimeg
cf2ba25089 quickshell: render subconscious surfacing once 2026-07-12 16:35:44 -04:00
Fimeg
6e21c50dcc quickshell: resume agent conversations from server 2026-07-12 16:31:55 -04:00
Fimeg
a2731b418e identity: add signed node commission records 2026-07-12 15:39:40 -04:00
Fimeg
2c14da0dbe federation: document node enrolment trust boundary 2026-07-12 15:34:41 -04:00
Fimeg
ad56206294 track cross-build cargo config + souveraine user unit
.cargo/config.toml + aarch64-pkg-config wrapper are load-bearing for the
cross build (CI artifact job + local build-cross.sh both depend on them);
were gitignored before. souveraine.service is the systemd user unit the
packaging/deploy scripts template.
2026-07-12 14:57:19 -04:00
Fimeg
ec7c4e8e8c quickshell: dock geometry/icon-centering, GlobalStates, ConflictKiller service
Dock + pill z-order and icon centering pass; GlobalStates.qml and a
ConflictKiller service for the ii sidebar.
2026-07-12 14:56:56 -04:00
Fimeg
165d814492 api+remote: ambient sensorium, cancel/interject verbs, SSE event mirror
SendMessageRequest gains ambient (surface sensorium note). RemoteBackend
gains spawn_cancel_watch + spawn_interject_pump so TUI remote mode has the
same interrupt/type-while-busy semantics as local. StreamEvent is now the
full wire mirror of BackendEvent — a new engine event is a compile error
at the SSE seam, not a silent skip.
2026-07-12 14:56:48 -04:00
Fimeg
904fbd02d7 bridge: claude-subscription provider (Claude Code OAuth wire)
Speaks the Claude Code subscription wire protocol against api.anthropic.com
using the OAuth creds claude already stored, so Souveraine can drive a
Claude.ai subscription directly alongside Bifrost/openai-oauth. Translates
OpenAI-shaped internal requests to/from Anthropic /v1/messages, applies the
subscription shaping, refreshes the OAuth token under a mutex.
2026-07-12 14:56:38 -04:00
Fimeg
419312b65f ci: pin tuie to fork sha + aarch64 artifact job
tuie now cloned from Fimeg/tuie (rgb patch committed) at a pinned SHA
instead of upstream HEAD — no floating ref decides if we build.

aarch64-artifact job runs on the new archdev host-mode runner, cross-
builds against ~/aarch64-sysroot (linker --sysroot flag proven to find
aarch64 libmvec), publishes the binary to a rolling edge prerelease
when CI is green. Phone updates itself from there.
2026-07-12 14:54:43 -04:00
Fimeg
128a76af7e pill: stable namespace so a hyprland layerrule pins it above the dock
Both live on Overlay; z-order was creation order, so an ii restart buried
the pill under the dock and it stopped taking touch. The pill now has
namespace quickshell:pill; a matching 'order = 1' hl.layer_rule in the
phone's hyprland.lua keeps it on top across restarts (rule is phone
config, not surface tree).
2026-07-12 13:14:40 -04:00
Fimeg
0a8e0f7294 dock/pill: fix icon centering, pill z-order, app-mode fullscreen
- dock icons center in the bar (DockApps top-margin was shoving the row
  down; DockAppButton block now reserves half the dot strip)
- pill double-tap fullscreens the real app: routes through dock IPC
  fullscreen() targeting Hyprland.activeToplevel.address, mode 0, so the
  pill tap focusing the shell no longer redirects it
- pill must be re-created after the dock or it sits under it and drops
  touch (both on Overlay; z-order = creation order)
- HOW-IT-WORKS.md: the concise contract for pill/dock/fullscreen
2026-07-12 13:07:02 -04:00
Fimeg
693df8b55b dock: revert thin-bar geometry; keep icons inset to land inside the bar 2026-07-12 11:30:51 -04:00
Fimeg
0beeb80357 dock: align icon row inside the visible rectangle (match its insets) 2026-07-12 11:13:24 -04:00
Fimeg
0e1f233857 dock: visible on empty desktop / hidden for focused apps; lift dock above pill strip 2026-07-12 11:09:28 -04:00
Fimeg
ccb51820e5 dock/pill: reserve pill strip (dock floats above), pill swipe-up = dock gesture not home/keyboard 2026-07-12 10:48:11 -04:00
Fimeg
57031bbf4f dock: drop the dead pin toggle button 2026-07-12 10:43:19 -04:00
Fimeg
b8b65273a1 dock: unmount layer when hidden so it stops painting over fullscreen apps 2026-07-12 10:41:50 -04:00
Fimeg
b8369235b4 dock: hide over fullscreen apps (app mode owns the display) 2026-07-12 10:33:36 -04:00
Fimeg
2955cd4fbe pill: double-tap is app-mode maximize, not kiosk fullscreen 2026-07-12 10:10:38 -04:00
Fimeg
d38bae0cb6 fullscreen flow: pill double-tap = real fullscreen (mode 0), dock+overview on overlay layer so edge swipes reach them over fullscreen apps 2026-07-12 10:05:53 -04:00
Fimeg
8915ac2a1a dock/pill: movement cancels hold-menu, folder-style stack icon, tap focuses running member; lua-fork hyprctl dispatch syntax; kill AiChat/notification TypeErrors 2026-07-12 09:51:09 -04:00
Fimeg
f6bbce5e0d dock: drop-onto-stack, arc reorder, drag-out unstack; shrink long-hold menu 2026-07-12 09:34:30 -04:00
Fimeg
bebb5a2382 surfaces/quickshell: adopt OSK flee-fix sidebars, focus-grab service, systemd hypridle 2026-07-12 09:27:07 -04:00
Fimeg
2c218fb075 packaging: adopt the phone deploy script and Arch PKGBUILD
Both were stranded untracked in the Pixel3Arch tree; they source from
this repo, so they live here. deploy-phone.sh ships the cross-built
binary + user unit (seed-id excluded, machine binding stays doctrine);
PKGBUILD builds from a synced local checkout, no network fetch.
2026-07-12 09:01:13 -04:00
Fimeg
037dc06922 surfaces/quickshell: bring the phone shell under the surface tree
Dock fan-out stacks, drag-to-combine, pill gesture rewrite, and the ii
patch set (TaskbarApps stacks API, Config dock.stacks schema) — pulled
from the live phone and made canonical here. deploy.sh grew a manifest
and a --phone mode: rsync the surface over, symlink ii into it, so live
edits land in a git tree instead of drifting.
2026-07-12 08:57:10 -04:00
Fimeg
0e780d5a05 saf: rebuild as a sectioned tree in the substrate voice
Old single-file SAF moved to saf/archive/.
2026-06-26 11:59:02 -04:00
Fimeg
ce7009e466 fix: char-boundary panic in tool cards + green up CI clippy gate
ToolCard styled the status glyph with a hardcoded byte offset 0..3, but
✓/✗/⟳ are 3-byte chars sitting at bytes 2..5 of "  {glyph}". The split
landed mid-char and panicked at render in tuie's style slicing. Compute
the glyph region as 2 + glyph.len_utf8() instead.

Then took cargo clippy -- -D warnings from 312 failures to clean:
- scoped #![allow(dead_code)] on WIP scaffolding (federation, sensorium,
  gitea_memory, model_router, session, subagent…); gate stays live on
  active code so new orphans still fail
- scoped #![allow(deprecated)] on the legacy ratatui render path, marked
  pending removal at tuie parity — no migration on code we're deleting
- declare the gui feature (forwards to tuie/gui) — the cfg was real intent
- real fixes: duplicate SaveAndGoBack arm + dead Err arm, base64::encode,
  4 unused imports, dead assignment, private-type leak, dedup'd if/else
  branches, manual clamp/strip, &PathBuf→&Path, collapsible matches
2026-06-26 10:12:27 -04:00