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

453 commits

Author SHA1 Message Date
Fimeg
29ec9fe223 fingerprint-preview: root in Singleton, not QtObject
The reload killer: FileView under a QtObject root — QtObject has no
default property, so the whole service tree failed to compile. Every
working service singleton roots in Quickshell's Singleton type.
2026-08-10 21:41:24 -04:00
Fimeg
cb7dd73d2b sidebar: the garden's micro-view — Lens service, vault card in the right panel
The vault card lives where notifications were — header with sync pill
(clean/ahead/behind/dirty), today's note entry, five freshest notes,
cold start and push rows — over the notification list. Lens.qml owns
souveraine-lens the way Face owns the rig: one socket, event lines up,
no vault access of its own. Kiyoshi's slash grammar and tool registry
are noted for the fuller app; the micro view only opens and plants.
2026-08-10 21:24:23 -04:00
Fimeg
658217e72e polkit: add temporary FPC confirmation 2026-08-10 20:46:28 -04:00
Fimeg
902a724855 lock: add FPC wiring preview 2026-08-10 20:10:50 -04:00
Fimeg
6eda491496 turn: the cache split reaches the message, not just a log line
a10ef5e added the counters and nothing read them — assistant_with_usage
had zero callers, so ConversationMessage.usage was always None and the
only proof caching worked was a grep. The turn now sums usage across its
rounds and commits it with the reply, and the per-round log carries the
split on every provider rather than only the Anthropic bridge.

memory: expose sliding_reflect. The tool offered sliding_window, whose
own doc comment says to use SlidingReflect unless you want blind
truncation, and hid the safe variant entirely.
2026-08-10 19:35:34 -04:00
Fimeg
30e1c34a34 providers: the provider follows the model, not the agent
Subconscious, reflection and archivist each pick a model independently
of the primary, then took the primary's provider to run it on. A
subconscious on deepseek-v4-flash under a claude-subscription primary
was sent to api.anthropic.com asking for a model it has never heard of,
so a split like Opus-5 primary with a DeepSeek subconscious could not
work at all.

ProviderRegistry now carries the [models.<name>] provider map and
resolves by model, falling back to the agent's provider when a model
has no entry — the single-provider case every agent used before.
2026-08-10 14:36:51 -04:00
Fimeg
eee26fcf57 turn: keep the reply a raced interjection used to erase
A finished text response arriving with a queued interjection was pushed
nowhere: not streamed, not added to messages, and overwritten in
final_content on the next round. The surface showed nothing and she
answered the interjection blind to what she had just said. It now
streams, enters history, and is carried into the single commit.

compact: summary dropped the system anchor. Index 0 is excluded from
to_summarize because it must not be compressed, then was left out of
keep_indices too, so the primary lost persona and covenant on her first
compaction. Every other strategy seeds vec![0]; culled_count already
counted as though this one did.
2026-08-10 14:24:32 -04:00
Fimeg
dfc89d09ea claude: log the cache split per call
A cache hit and a short prompt are indistinguishable from outside;
this provider logged nothing per request at all, which is how an
uncached bridge went unnoticed across 93 turns.
2026-08-10 13:33:54 -04:00
Fimeg
a10ef5e3ed claude: cache the prefix the bridge was re-billing every turn
No cache_control was ever set, so tools, system and the whole transcript
were charged in full on every round. Breakpoints now sit on the tail of
each stable span; message content is always a block array so the marked
tail cannot change the prefix bytes as it moves.

Mid-conversation system notes — the turn loop's pulse and interjections,
the subagent round warnings — were hoisted into the top-level system
field, rewriting the front of the prefix on the round they fired. They
stay where they happened now. Usage carries the cache split; input_tokens
alone understates the prompt by whatever was served cheaply.
2026-08-10 13:33:00 -04:00
Fimeg
bf469c4216 lock: answer touchKeypad on a cold start, not just a reload
PersistentProperties is in-process, so it carries the surface choice
through a reload and not through a fresh shell. sessiond locks before the
shell exists, so a greetd-started shell adopts a live lock with
Config.ready still false and binds the desktop surface — and
WlSessionLock.surfaceComponent cannot change once active. A lock screen
that will not take your PIN, on the iPhone 7 tonight.

Reads the environment, which answers at construction. Unset behaves
exactly as before, so nothing changes on blueline until it sets it.
2026-08-09 22:21:14 -04:00
Fimeg
eb0292c342 sessiond: dim by percent, not an absolute
brightnessctl set 10 is 4% on blueline's 255-step backlight and 0.5% on
the iPhone 7's 2047-step Apple DWI, where it reads as fully off. Measured
on d10 2026-08-09: brightness=1 with the panel still powered, so the
screen went black on a dim that never blanked.
2026-08-09 21:19:30 -04:00
Fimeg
b2774c8aac sessiond: a power seam that cannot report an outcome it does not have
Power is the one irreversible transition and it bypassed the authority
entirely: both menus called Session.poweroff() straight into systemctl, so
there was no Action, no trail entry and no refusal path.

The daemon gains the verb and the shell gains a transport for it. The
request rides its own short-lived connection, never the heartbeat, because
suspend can hold the daemon's handler until resume while the heartbeat
must stay free to carry locked_ack and the EOF that means shell death. A
disconnect after the request was sent reports outcome_unknown rather than
guessing.

Session.qml keeps the legacy executor until this is exercised on hardware.
Unbuilt and unrun; CI is the first reader.
2026-08-09 19:31:33 -04:00
Fimeg
c802f7db48 packaging: sessiond ships on both arches, enabled on neither
CI already built the x86_64 daemon and then threw it away — the binary and
its user unit were copied into the package only under aarch64, so the
laptop could never receive the thing every lock, blank and button report
assumes is running.

Both now ship, and the package still neither enables nor starts the unit.
Phone-only reporters and surfaces stay aarch64.
2026-08-09 19:31:33 -04:00
Fimeg
32c019875c usb: land the HID controller the doorway was already calling
78d6743 committed PowerMenu's half and never added the file, so the
singleton in qmldir resolved to nothing and the shell would not load on a
tree that had not been hand-linked.

HidController streams to usb-hid-inject and acknowledges every accepted
report, closes both endpoint fds on the busy edge before usb-signaller
tears the functions down, and refuses non-ASCII on the glass instead of
clearing a field whose first report was never written.

The face reports the agent and host results back to the page, and
deploy.sh stages the tracked face assets before the QML switch so a new
control cannot arrive without the page that implements it.
2026-08-09 19:31:07 -04:00
Fimeg
abdf31087d docs: the working agreement for this repo
Points at the personal agreement and the cross-repo map, names this tree
as the substrate rather than a harness, and starts architecture at
saf/INDEX.md.
2026-08-09 19:30:56 -04:00
Fimeg
78d6743776 usb: make the HID controller doorway honest 2026-08-07 17:36:25 -04:00
Fimeg
9ceaf61fa6 memory: base scoped commits on HEAD 2026-08-07 16:06:41 -04:00
Fimeg
0c9db09888 memory: persist every git index mutation 2026-08-07 16:02:16 -04:00
Fimeg
8cd2adb828 usb: build the full KVM composite surface 2026-08-07 14:48:07 -04:00
Fimeg
16c6ee1033 multitasking: one owner for the transition, and the release travels
ZoneTransition owns the card rect, the four overview verbs, the end-target
table and the gesture clock. ZoneOverview and the rail read it; neither
derives a geometry.

Deletes poseActiveZone/clearPose/_posed, zoneCard.scale and
zonePullProgress. The card's ColumnLayout went too — its margin was a second
opinion about where a window sits in its zone; panes are the compositor's
tiling scaled.

The swipe felt wrong because the release committed where the thumb left it.
settleTo() travels to the destination first and commits on arrival, with
quickstep's numbers (350ms cap, min(1/0.7, 1/0.3)). Abandoned half-swipes
settle to last_zone instead of snapping. Dwell gate restored — quickstep
gates the same way and "ever paused" is a latch.

Card box is measured from the surface, not assumed from the screen: the
overview panel respects exclusive zones and its height moves.

Strand repro passes on hardware.
2026-08-07 12:26:12 -04:00
Fimeg
72171accec the card is the window's size through the whole pull
Two fixes to the same seam. columnLayout was still gated on
missionControlOpen, so a peek raised a panel whose contents were
invisible — the same line that had been left behind once before, with
its own comment saying so.

The card scaled 0.6 -> 1.0 while pose runs 1.0 -> 0.6 against the same
progress, so at the handoff the window was at 0.6 of the glass and the
card arrived near full-bleed. Same curve now, and the 26/12 inset is
gone: scale is the inset, and stacking both squashed the aspect because
the bottom label margin has no counterpart at the top.
2026-08-07 08:52:58 -04:00
Fimeg
452acea0ad restore every window the drag posed, not the ones the poll names
Going home from a pull left the app scaled down until the pill was
dragged back to clear it. clearPose walked ViewtopControl.windows, which
is the 2 s poll's list, so a window that list no longer named never got
its 1.0 back. Track the ids actually posed and clear those too.
2026-08-07 08:52:58 -04:00
Fimeg
f699f57235 multitasking draws under a dwelling thumb
The overview loader was only active once missionControlOpen was already
true, so nothing existed during the pull and ZoneOverview.progress
following the rail was dead mid-drag. The cards appeared at release and
animated on their own clock — two motions, which is the seam TASK-60's
acceptance names.

missionPeek gates presentation only: visibility, mask, which body the
loader builds. Focus, dismissal and every commit path still read
missionControlOpen, so a preview draws and decides nothing. Masked to a
zero-size item while peeking so the in-flight gesture stays the rail's.

Dwell rather than any pull, so a flick to home never flashes the blur,
and it drops above the multitasking detent so the preview never shows a
destination the release would not commit.
2026-08-07 08:42:00 -04:00
Fimeg
57208c886a rail: the pose rides the drag, not each exit path
A partial slide left the app scaled small until another pull brought it
back (DUMP-bugs 8). Every path anyone checked did call endPull, so the
hunt for the one that didn't was the wrong shape: while restoring is a
step, some path skips it. It is now a function of `dragging`.

Release gates on speed and length as one projected number instead of a
distance test with a flick promotion bolted on. That promotion had never
fired anyway — it read rail.tapSlop, which is undefined, so the test was
`travel >= undefined`. Every commit on this rail has been distance-only.
2026-08-07 08:41:54 -04:00
Fimeg
14c3c80b14 handoff: 2026-08-07 2026-08-07 02:29:39 -04:00
Fimeg
630d6912fd sidebar: the keyboard leaves with the panel that summoned it
The drawer clears oskOpen on close and this did not, so the OSK outlived the
surface holding the only text field it was serving — and with nothing focused
there was no obvious way to put it away.

On the state, not on a visibility handler: the panel's `visible` is a binding
to that flag, so reacting to visibility would be reacting to our own effect.
2026-08-07 02:24:24 -04:00
Fimeg
f4caaae1cb drawer: the keyboard comes up on a tap, not on a press
Summoning on onPressed meant any gesture that merely began over the search
field raised the keyboard — including the swipe that scrolls the app grid,
which starts at the top of the drawer more often than not. The press now only
remembers where it landed and the release decides, with a generous slop: a
thumb reaching the top of a 540px panel is not steady, and a few pixels of
drift while tapping a text field is a tap.
2026-08-07 02:22:28 -04:00
Fimeg
47e8135cdc face: her postures reach the rig, and she stops miming on startup
`posture()` called window.live2dMotion, which does not exist — measured
undefined on the device. Nine states advertised to her in the prompt and
wired to nothing. The bundle exposes two levers: #live_talk, a motion slot it
reads every frame, and its own head/body hit test. The nine collapse onto
those rather than pretending: speaking talks, idle rests, and the rest are a
look — head for attention, body for effort.

#live_talk starts at "0". "1" means start a talk motion, so she came up
mouthing words with no voice behind them.

The gaze socket used onConnectedChanged; Quickshell's Socket emits
onConnectionStateChanged, so the subscribe was never sent — a handler for a
signal that does not exist.
2026-08-07 02:21:06 -04:00
Fimeg
e218601199 Revert the duplicate onCanceled on the rail
The handler already existed and already did this — a second one in the same
MouseArea is "Property value set multiple times", which failed the whole
module and took the shell down. The pill's stranded-pose symptom is
something else; the cancel path was never the hole.
2026-08-07 02:07:22 -04:00
Fimeg
4826574166 pill: a cancelled climb puts the app back
onReleased is the only thing that clears the pull's pose, and a MouseArea
whose grab is taken away never gets one — it gets onCanceled, which had no
handler. So a cancelled climb left `dragging` true, the pull progress set and
the app posed at 0.6: shrunken, with nothing on screen to say why, and no way
back except pulling the pill again to force a fresh press and release
through.

Never a commit. A gesture nobody finished only has to put the glass back.
2026-08-07 02:06:12 -04:00
Fimeg
5c44ea06d5 dock: scale it up, and put the scale in settings
44px buttons with 35px icons read small on a 540px panel, and a stack's
members were 12px inside a 35px box — unreadable, which is the whole job of
the collapsed form. 56/44 now, and the member icons give back the border and
padding that were being subtracted from them as well as the grid spacing.

Both numbers live in Config so this is a setting rather than a rebuild, with
spin boxes in Settings > Dock. Two numbers and not one ratio: the button is
the row's height and the icon is what you see, and fixing the ratio would
mean either cramped icons in a tall row or icons overflowing a short one.
2026-08-07 02:04:12 -04:00
Fimeg
a1d9a874e5 multitasking: inset the cards so neighbouring zones show through 2026-08-07 01:34:43 -04:00
Fimeg
6f375286bf multitasking: the cards were zero pixels wide
ZoneOverview took its width from the Column it sits in, and a Column is as
wide as its widest child. The drawer's search widget supplies that; mission
control is the cards alone and has no search, so the only child left was the
loader — whose width came from the column, whose width came from the loader.
The cycle resolves to zero.

Full-height zero-width cards draw nothing, which is why multitasking was a
blurred backdrop and nothing else while every other signal read healthy:
zones 2, windows 1, subscribed true, loader active, item present, opacity 1,
progress 1. Bound to the panel's width instead, which is what this surface
covers anyway.

Also adds `overview missionControl` and `overview state` — the surface that
had been reported broken was the one nothing but a pill swipe could raise,
and the state readout is what located this.
2026-08-07 01:32:27 -04:00
Fimeg
5ec6bfdc63 overview: a verb for mission control, and a state readout
Multitasking was raised only by the pill's first-stage swipe, so the one
surface that has been reported broken was the one neither an agent nor a test
could reach. state() reports what the cards are drawn from.

Used it immediately: with a window open the model is not empty — zones 2,
windows 1, subscribed true — so the missing cards are not missing data.
2026-08-07 01:23:14 -04:00
Fimeg
075ddf19eb face: locking sends her away, and she stays away
Gated on screenLockSecure, the compositor's ack, not on screenLocked. The
request drifts: measured on the phone, `session lock` answered already-locked
while logind reported LockedHint=no and the phone was in use. That is a
shadow copy of state the protocol owns, and a face gated on it would have
been permanently dismissed with nothing on screen to explain why.

No return on unlock. You come back to the clock and summon her if you want
her, rather than finding whatever was left on.
2026-08-07 01:11:13 -04:00
Fimeg
c8dc24d3d1 face: follow the finger anywhere on the panel
Subscribes to viewtop's gaze feed and dispatches a synthetic pointer move on
the canvas, so live2d.js's own mousemove path drives head angle and eye
direction with its existing damping. Synthetic is the point: she is
deliberately not being given those contacts, and this lets her watch them
anyway.

Screen coordinates in, her window's coordinates out — the origin comes from
the compositor's furniture report rather than assumed, because the layout
decides it and it moves with the zone.
2026-08-07 01:01:05 -04:00
Fimeg
ae432e7654 dial: hold the camera to record the screen
Entries may carry a hold verb beside verb; the ring fills while it charges so
the commitment is visible while it is still cancellable, and sliding off
cancels. Holding the camera starts a recording, tapping or holding it again
stops it — the same seat, because the dial is muscle memory.

No wf-recorder or wl-screenrec on the device, so it is grim piped into
ffmpeg. Half scale: at 1080x2160 grim manages about 3.5 fps and a recording
that captures a third of its claimed frames plays back at triple speed.

Its own process group, and SIGINT to the group: only ffmpeg can finish the
file, so killing the shell alone would orphan a screen capture with no way to
stop it.

Reachable as a verb too, not only by thumb.
2026-08-07 00:24:12 -04:00
Fimeg
ac35b3436b her face on the glass: it draws, it listens, and it gets out of the way
The rig never drew. live2d.js is not only the Cubism runtime — it carries the
reference's character layer, which reads #live_talk every update as its
motion-state slot. Our page omitted the element, so it threw on the first
frame after the model and all four textures had loaded: assets 200, WebGL
live, no error reaching Rust, blank canvas.

--app-id was a no-op. set_prgname ran after GTK had already created the
surface, so the compositor saw souveraine-web and window rules could only
match the title. It has to run before the event loop.

Press and hold her to speak: pw-record at 16k mono s16, release transcribes
through souveraine-stt --file and goes out over Souveraine.send, so the
sidebar logs it. Whisper wraps with newlines and the transcript arrives
through a SplitParser, so it is collapsed here or one utterance becomes four
turns. Double tap dismisses; the clock and quote fade out when she is up and
the clock stops being a target, because a double tap on an invisible object
is not a way back.

The page reports its silhouette and the host installs it as the input region.
Claiming the GL context for preserveDrawingBuffer must happen after the
canvas is sized — before it, the context is born 300x150 and she renders as a
thumbnail in the corner.

Console and errors are forwarded to the host's stdout. Without that a rig
that fails to draw is silent in every direction, which is what cost this
the afternoon.
2026-08-07 00:24:12 -04:00
Fimeg
78496e10e1 gamma goes to the compositor, not to a binary that is not there
hyprsunset does not exist under viewtop and execDetached cannot fail loudly,
so the brightness slider and the night light have done nothing since the
move. Same public surface, pointed at viewtop's gamma verb. TASK-61.

Keeps the upstream name: every consumer in the tree spells it, and renaming
across the base tree and the phone overlay is its own sweep.

import Quickshell was missing, which made the Singleton type unavailable and
failed the whole qs.services module — 29 singletons, 28 had it. The phone's
shell was in a restart loop with a 26-line cascade whose only real line was
the last one.
2026-08-07 00:24:12 -04:00
Fimeg
4ff8d2e236 gamma: the brightness slider drives viewtop's LUT, not hyprctl (TASK-61) 2026-08-06 18:57:01 -04:00
Fimeg
c2dcbe7b7f rail: a keyboard-up climb means only a swap, never navigation 2026-08-06 11:54:45 -04:00
Fimeg
7f294a5fa2 the face draws: relative asset paths over loopback, and a dead socket stops being a gate 2026-08-06 11:18:23 -04:00
Fimeg
d1e580ee00 drawer: the search field stops auto-focusing on the phone; tapping it summons the keyboard 2026-08-06 11:03:47 -04:00
casey
3d3eb2cc8e the avatar draws: serve the rig over loopback, not the opaque scheme 2026-08-05 22:14:07 -04:00
Fimeg
a5f0fadba8 unlocking closes a keyboard nobody asked for 2026-08-05 21:55:11 -04:00
Fimeg
269c151899 the wry host is optional through the whole pipeline; it must not block sessiond 2026-08-05 21:29:24 -04:00
Fimeg
d4f9213a34 wry host compiles: tao 0.36 event loop, Cow bodies, app id is the program name 2026-08-05 21:00:35 -04:00
Fimeg
620c7d313d placement grades a covered sensor instead of gating on it; squeeze test follows the fix 2026-08-05 20:23:29 -04:00
Fimeg
fe48bb76c5 the rig ships with the repo; it is self-hosted 2026-08-05 20:11:49 -04:00
Fimeg
8e3120c5a0 the face stays quiet when the rig is not staged; add stage-face.sh 2026-08-05 20:11:31 -04:00