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

553 commits

Author SHA1 Message Date
Souveraine
6d0f891d6e shell: own the agent message delegate and the reasoning card
TASK-72 step 2. AgentMessage consumes the typed segment list and dispatches
to owned primitives; ThinkingCard draws reasoning as a segment kind rather
than as <think> punctuation inside a flattened string, which removes the
think-fence collision class by construction.

MessageTextBlock and MessageCodeBlock are deliberately reused from the vendor
snapshot: they are markdown renderers, not agent vocabulary.

Composed by MANIFEST, imported by nothing. The activating edit is queued as
patch 0008. Qt6 qmllint: zero syntax findings; remaining warnings are the
widget-resolution class the vendor AiMessage also produces (38 vs 46).

Not verified: nothing has loaded this. No real tool round has rendered here.
2026-08-12 13:11:19 -04:00
Fimeg
3def2920b8 shell: owned agent surface — tool vocabulary and card
First step of TASK-72's owned destination. modules/souveraine/agent/ is
original Souveraine code; no further agent-surface work lands in ii-base.

ToolVocabulary transcribes src/ui/chat/tool_renderers.rs — the same event
stream, solved once already for the TUI. All 19 registered tools have a kind,
an icon and a summary. The vendor card knew 8: bash read write edit grep glob
list_dir memory. The 11 it could not name are the interiority verbs.

ToolCard groups by what the act is rather than which subsystem serves it, so
acts on the machine and acts on herself read as different families. Status is
legible without opening the payload; collapsed by default except running or
failed.

Composed by the manifest, imported by nothing. Registration is a later step.
2026-08-12 12:55:11 -04:00
Fimeg
5a20307ddd patches: queue 0007, render context occupancy and stop reading hyprctl errors as cursor
Requires f266136 in the running server; without it the pill honestly shows
an em dash rather than a wrong number. Unapplied, unloaded.
2026-08-12 12:20:11 -04:00
Fimeg
e784fe48a3 patches: queue 0006, step-up authenticates through PAM
Authored in a parallel session (Rook, Codex side) on 2026-08-12; committed
here because untracked is the fragile state, not because authorship is mine.
Finding stands on its own: StepUpAuth called souveraine-pam-auth, a binary
never written, and fell back to pkcheck against an action never shipped, so
every grant request was silently denied. Unapplied, unloaded.
2026-08-12 12:20:11 -04:00
Souveraine
f266136510 context pressure carries usage and ceiling as named fields
BackendEvent::ContextPressure was (f32, usize) whose second element was the
context limit. A positional tuple crossing a module boundary made every
consumer guess: the TUI guessed limit and was right, the HTTP layer named it
tokens and was wrong. So every non-TUI surface rendered the ceiling as the
usage — a constant 250000 that looked like a measurement. Nothing failed and
nothing logged.

Name the fields, and carry tokens_used explicitly rather than leaving it to
be reconstructed as pressure x limit. bifrost_pressure already computed the
token count and discarded it.
2026-08-12 12:11:21 -04:00
Fimeg
5cc7a90f44 packaging: the FPC pam module is pam_souveraine_fpc.so
blueline-fingerprintd installs /usr/lib/security/pam_souveraine_fpc.so
(PKGBUILD:48). cc541d1 named pam_fpc_polkit.so, which exists nowhere.

The leading '-' means a missing module is skipped without complaint, so
a wrong name here fails silently and permanently: the finger does
nothing and no log says why.

The module returns PAM_IGNORE outside PAM_SERVICE=polkit-1
(fpc-polkit-pam.c:86), so step-up falls through to the password stack
until that allowlist widens.
2026-08-12 10:50:12 -04:00
Fimeg
cc541d1eaa packaging: ship the step-up PAM stack and polkit fallback
SESSION-AUTHORITY-DOCTRINE §3 names /etc/pam.d/souveraine-stepup by path.
Root-owned config can only arrive by package: rootfs-overlay/ reaches a
device on flash and the phone does not flash.

auth_self, never auth_admin — step-up re-proves the user to themselves, it
does not escalate. The leading '-' on pam_fpc_polkit.so loads the fingerprint
factor only where it is installed, so one file serves phone and laptop.

Inert until a consumer calls it; no src/ path does yet.
2026-08-12 10:39:47 -04:00
Fimeg
acb2b6c608 claude: 529 is Anthropic overload, not a permanent failure
529 is Anthropic's own overload signal on this wire, so classify_status
treated it as Permanent and bailed the whole request with zero retries.
The bail string reaches the surface, where it reads as an auth failure.

Adds 529 to the transient arm and a status_hint() clause naming capacity
rather than credentials, on both the retry warning and the final bail.
2026-08-12 10:39:40 -04:00
Fimeg
d02df0c6bd patches: the queue is 0001-0004, say so 2026-08-12 09:24:06 -04:00
Fimeg
b5671b0b8a patches: retire the stale 0005 entry, record what closed 2026-08-12 09:23:39 -04:00
Fimeg
f7e0e51116 config: never store a null option
Null-valued options serialised into config.json and segfaulted
JsonAdapter on the next launch, killing the shell after load.
Tristate strings (auto/on/off) with boolean fallback.
2026-08-12 09:23:19 -04:00
Fimeg
fb5e9bb80c osk: retire the dead dual-keyboard path 2026-08-11 19:21:21 -04:00
Fimeg
dd19ab227f agent sessions: show conversations, not storage ghosts 2026-08-11 18:47:54 -04:00
Fimeg
12da479c23 bar: finish the shared resource widget 2026-08-11 18:40:35 -04:00
Fimeg
013a06aacf patches: retire the old top-bar agent mount 2026-08-11 18:40:35 -04:00
Fimeg
62638e0e5f osk: recover with Squeekboard, not Stevia 2026-08-11 18:37:57 -04:00
Fimeg
692455c8f0 chat: raise the keyboard when the field is tapped 2026-08-11 18:24:24 -04:00
Fimeg
41d13c9468 dock: yield the bottom edge to the keyboard 2026-08-11 17:21:45 -04:00
Fimeg
7842c04053 turns: never mistake an empty success for Annie 2026-08-11 17:09:42 -04:00
Fimeg
dfc72d7214 subconscious: heal persisted tool-call history 2026-08-11 16:05:38 -04:00
Fimeg
2179b627d1 agent sessions: leave the bar and sit beside chat 2026-08-11 15:43:30 -04:00
Fimeg
3bdc1c8e3c patches: keep island work outside turn fix 2026-08-11 15:01:38 -04:00
Fimeg
3aa7019eb5 turns: survive the surface disappearing 2026-08-11 15:01:18 -04:00
Fimeg
783f09606a island: fix three defects found by actually loading the shell
The island had never been load-tested. All three were fatal or noisy and
none were visible by reading.

StyledToolTip takes `text`, not `content`. Two occurrences, each one a
hard "Cannot assign to non-existent property" that failed the entire
module chain up to shell.qml — the bar would not have come back.

The provider-health tooltip could never have shown even once fixed: a
MaterialSymbol has no `hovered`, and our own StyledToolTip fix treats a
non-hoverable parent as never-show. That block exists specifically so an
unavailable provider is not mistaken for "no sessions", so a tooltip was
the wrong carrier. Stated visibly now.

Island read root.QsWindow.window through a non-optional access; inside a
Loader the attached object is not resolved at construction and it threw.

Revealer takes implicitHeight from childrenRect, so anchoring its child
to its own centre closes a cycle once it sits in a Loader. ii-base hid it
by letting the layout drive the Revealer height directly.

Verified: qs -c souveraine reaches "Configuration Loaded" with no warning
naming any of these files.
2026-08-11 14:46:41 -04:00
Fimeg
391e239010 bar: one BarContent for every device, layout as data
ii-base and ii-phone each carried a 357-line BarContent to express eight
differences, all of them either "is this widget shown" or "which slot is
it in". No behaviour differed. Every bar edit had to be made twice or
diverge silently against the pin.

Widgets are now declared once as Components in a registry; each slot is a
Repeater over a list of widget names, so placement and order are data.
Config names a slot or a device profile picks it. "auto" derives the
profile from the same cramped-ness test behind useShortenedForm, so the
phone keeps its arrangement with no config file. Loaders are active only
when placed, so an unplaced widget is never constructed.

The agent island becomes a placeable widget rather than a mount smuggled
into UtilButtons: it reaches every device bar from one declaration.

ClockWidget is unified for the same reason. Its phone fork existed solely
to add customFormat, which BarContent now sets on every device.

bar.agentSessions was landing under background.widgets, not bar, so
Config.options.bar.agentSessions was always undefined and only the ?? true
fallback made the island appear wired. Moved, and merged into the existing
bar.indicators rather than declaring a second one.
2026-08-11 14:40:07 -04:00
Fimeg
d87d6117a4 patches: queue 0005, mount the agent island 2026-08-11 14:22:42 -04:00
Fimeg
b21184217e agent sessions: use shellPath convention for collector path 2026-08-11 14:21:37 -04:00
Fimeg
47ce2d1970 agent sessions: one collector, one island
Collector emits a single JSON envelope for every agent session (Souveraine,
Claude Code, Codex) and always exits 0; a failing provider reports
available:false rather than taking the envelope down.

AgentSessions.qml owns the cadence and projects the envelope. Transport is not
the contract: when the TASK-69 daemon lands, only the source changes.

Island is a morph host for the bar - dot on a cramped bar, pill where there is
room, derived from the same threshold BarContent uses.

Inert until registered in services/qmldir and mounted; see patches/0005.
2026-08-11 14:19:45 -04:00
Fimeg
928bd8d143 face: recreate a refused rig socket
Quickshell retains the failed QLocalSocket object, so toggling its requested state cannot reconnect. Replace the Socket body until the host answers.
2026-08-11 14:08:12 -04:00
Fimeg
e7929e41ca agentsd: collapse the scan predicate 2026-08-11 14:05:51 -04:00
Fimeg
d739f3597d agentsd: drop dead limit collection from the session parser 2026-08-11 14:05:28 -04:00
Fimeg
60a29782d1 agentsd: one collector for claude, codex and souveraine sessions 2026-08-11 14:03:57 -04:00
Fimeg
5afa132ff4 face: keep knocking until the rig answers 2026-08-11 14:03:23 -04:00
Fimeg
e314d4fa23 face: expose the two live gaze links
Let the remote shell deploy accept the assets its caller already staged, so a successful composition does not fail after switching the tree.
2026-08-11 14:02:02 -04:00
Fimeg
8fd1a72edd face: reconnect to the rig after host startup 2026-08-11 13:33:09 -04:00
Fimeg
9149c409b7 subconscious: carry her thread across restarts
One unreadable conversation.json aborted the whole listing, so hydration
returned an error, the caller read it as no prior thread, and a fresh
conversation opened on every boot. Skip the damaged record and warn.

Pick the thread by activity, not registration order: list_for_agent().last()
is the oldest conversation once hydration has pushed them newest-first.
Same fix for the scheduled background turn.
2026-08-11 13:18:58 -04:00
Fimeg
cfad6881d1 api: carry ordered text and image parts across the message boundary
`Message.content` was `String`, so an attachment could not reach the
substrate even though everything downstream was ready for it: the session
already stores `ContentBlock::Image`, `run_turn` already builds OpenAI
multi-part content, and the provider client already speaks `image_url`.
The whole pipe was plumbed and the tap was welded shut at the door.

`MessageContent` is untagged — a bare JSON string is exactly the wire it
has always been, an array carries ordered parts in the substrate's own
`ContentBlock` vocabulary. Same shape `ContentValue` uses facing the
provider, turned inward. No new noun.

Only `text` and `image` cross. `tool_use`, `tool_result` and `reasoning`
are the engine's to write; a surface posting one gets a 400 rather than a
forged turn quietly filed in history. And the vision gate now answers at
the door: an image sent to a text-only model returns 422 naming the model
instead of being stripped to "[Image: attached by user]" downstream,
which reads to the human like she looked and said nothing. Conversion
happens for every message before any of them is stored, so a rejection in
the second cannot leave the first half-committed.

Nine tests: legacy string, typed text, mixed order, round trip, replay
out of persistence, refusal of engine-owned blocks, the gate's question.

The surface half is untouched. `Ai.qml::attachFile()` still refuses, and
its comment is now out of date — that is the next checkpoint, and it is
Casey's to compose and restart.
2026-08-11 12:30:17 -04:00
Fimeg
c367a4dbd9 rescue: preserve unversioned source copy found on archdev
/home/casey/souveraine on the build box is a full copy of this repo with no
.git at all, newest sources 2026-08-09 21:07. Audited by hashing every file
and querying this repo's object database: 1545 checked, ten unknown after
excluding the vendored upower submodule.

Eight carry real deltas; roughly fifty substantive lines have no upstream
equivalent. They are the follow-up to b2774c8 that was never committed: a
logind capability query before firing a power verb, and a failure-path release
of the in-flight power latch without which a refused suspend deafens the verb
until the next boot.

Preserved verbatim, not merged. The tree has moved 100+ commits and the
sessiond power seam wants a human.
2026-08-11 11:06:11 -04:00
Fimeg
517d8c1927 subagent: send task as user message, not folded into system prompt 2026-08-11 10:48:55 -04:00
Fimeg
e498e72b77 memory: gate write over an existing file, report the delta
write replaces a whole file and reported success identically whether the
file grew, held, or was erased. Replacing an existing file now requires
overwrite: true, and the refusal names append/edit as the likely intent.
Every write returns a WriteDelta so the result carries magnitude; a write
that drops a file below half its former size says so loudly.

Internal callers (archivist, compaction, subconscious ledgers, REST) keep
the ungated path — their replacement is structural.
2026-08-11 10:33:20 -04:00
Fimeg
d290b12441 patches: queue QML compatibility fix 2026-08-11 09:37:09 -04:00
Fimeg
23cebc531d shell: keep typed segments QML-compatible 2026-08-11 09:35:53 -04:00
Fimeg
8c434dfb74 shell: render typed chat segments
Keep assistant, reasoning, tool-call, and tool-return frames structured through the sidebar delegate. Tool cards bind returns by wire id and fold their output by default.

Reasoned from the SSE contract and existing TUI renderer. Diff check passed. Untested against a running shell: Casey applies and reloads staged patches.
2026-08-11 09:13:50 -04:00
Fimeg
a8f7f62471 shell: stop sensor calls closing an open reasoning fence
A tool_call/tool_return arriving while a <think> block was open emitted its
own self-closing fence, whose </think> closed the outer block early. Every
reasoning token after that point rendered as prose, and the stray close left
the trailing assistant text mis-segmented. Append inside the open fence
instead; only open one when arriving in prose.
2026-08-11 09:13:50 -04:00
Fimeg
52f379f230 patches: queue typed chat segments 2026-08-11 08:56:08 -04:00
Fimeg
f17fa7c31b patches: queue think-fence collision fix 2026-08-11 08:10:39 -04:00
Fimeg
aaea09fdd6 shell: patches queue — agent stages, human applies
The composed config is symlinked into the repo and quickshell reloads on
write, so an agent editing QML edits the live shell mid-turn. Stage changes
as patches instead; the human applies and reloads on their own beat.

First in the queue: 0001-resume-offer — the agent-established hook offers
the latest thread instead of silently attaching it. Explicit resume paths
and the e4e6594 amnesia fix are untouched. Untested against a running
shell.
2026-08-10 23:04:59 -04:00
Fimeg
ce6741bf77 compaction: target the active conversation, not the oldest one 2026-08-10 22:50:24 -04:00
Fimeg
28ed6f2151 lens: explicit status guard instead of optional chains 2026-08-10 22:35:37 -04:00
Fimeg
3175700ea2 subconscious: a failed pass must not report as a quiet one
The Err branch surfaced the same 'no anomalies detected' text as the
success path, at Low urgency. A subconscious erroring on every turn was
indistinguishable from one noticing nothing. The only record of the real
cause was a tracing::warn on a stderr whose socket has no reader.

Carry the error in-band at High, and say the pass failed.
2026-08-10 22:27:53 -04:00