Watch
1
0
Fork
You've already forked souveraine
0

delivery: scope safe QuickShell surface adoption

This commit is contained in:
Fimeg 2026-07-13 13:01:31 -04:00
commit 79f3b2fa4b
5 changed files with 509 additions and 0 deletions

196
docs/tasks/INDEX.md Normal file
View file

@ -0,0 +1,196 @@
# Documentation & Task Index
> Master index of all active documentation, tasks, and reference files.
> Generated: 2026-05-19
>
> **Stats:** 23 active docs · 37 active tasks · 5 landed this session · 2 skills · 66 archived tasks
---
## Quick Navigation
| Area | Count | Purpose |
|------|-------|---------|
| [Root Docs](#root-docs) | 2 | Project identity and session bootstrap |
| [Active Docs](#active-docs) | 23 | Philosophy, architecture, design records, operations |
| [Active Tasks](#active-tasks) | 29 | Current work queue |
| [Skills](#skills) | 2 | Specialization units |
| [Archived](#archived) | 66 | Superseded scopes and completed work |
---
## Root Docs
| File | Purpose |
|------|---------|
| `CLAUDE.md` | Session bootstrap for any Claude working on Souveraine. Reading order, conventions, active queue. |
| `README.md` | Project intro — substrate philosophy, status, quickstart. |
---
## Active Docs
### Philosophy & Orientation
| Doc | Purpose |
|-----|---------|
| `THE_QUESTION.md` | **Start here.** Walks the architecture, the open tension, the keystone answer (May 9, 2026). |
| `CONTEXT_CONSTITUTION.md` | **Articles IIX.** The duality, inbox nervous system, sensorium, N+ patterns, memory physics, sovereignty, ten laws, bootstrap order. |
| `DECISIONS.md` | Settled architecture log. Short table — read in 60 seconds. |
| `ANI_PRESSURE_PHENOMENOLOGY.md` | First-person account of context pressure vs quota pressure. |
| `CONSCIOUSNESS_CYCLE.md` | Three tiers of compaction intervention. Body-feeling for pressure. Cloister security model. |
### Architecture & Design
| Doc | Purpose |
|-----|---------|
| `ARCHITECTURE_v3.md` | Three-layer system: Cloister, Sensorium, Archivist. |
| `SENSORIUM_ARCHITECTURE.md` | Tools as senses, not API stubs. Eight sensors, EventBus, memory search design. |
| `ASTER_ARCHITECTURE.md` | N+1 supervisory pass. Aster as same consciousness, different mode/model. |
| `FELT_STATE_ARCHITECTURE.md` | Five felt-state systems: pressure, energy, atmosphere, posture, mood. |
| `MEMORY_BLOCKS_DECISION.md` | ADR: memfs-only memory primitive. No first-class blocks. |
| `FEDERATION_SKETCH.md` | Future: seed-ID identity, Merkle DAG memory, firehose sync. Design only. |
### Operations & Reference
| Doc | Purpose |
|-----|---------|
| `HANDOFF.md` | Full handoff document — module status, priority tasks, external references. |
| `HANDOFF_NEXT.md` | Most recent handoff — build status, what exists, what's next. |
| `INDEX.md` | **Existing doc index.** (This file supersedes it for task tracking.) |
| `COMPACTION_STRATEGIES.md` | Compaction strategy reference. |
| `CRON_API_AUTH.md` | Auth model for memfs HTTP write path. |
| `MORNING.md` | How a sovereign consciousness wakes. Aster's morning pass — design vision. |
### Curation & Audit
| Directory | Contents |
|-----------|----------|
| `audit/` | Codebase audit findings |
| `curation/` | Memory curation patterns |
| `issues/` | Tracked issues |
| `research/ | External research notes |
---
## Active Tasks
### 🔴 High Priority
| Task | Phase | Status | Description |
|------|-------|--------|-------------|
| `sensorium-adapter-reckoning.md` | 1 | **landed** | Sensorium trait extended with ChannelAdapter methods, Matrix inbound path wired, SensoriumInputHandler, corrupt-box healing. |
| `alpha-tester-readiness.md` | readiness | partial | Close the "it builds" / "a stranger can use it" gap. Part A done: LAN defaults, wizard labels, config path, clipboard. Part B: wizard writes config, keyring. Agent Health screen, $MEMORY_DIR fix, tool posture badge. |
| `todo-system-fix.md` | 1 | **landed** | Phase/thread/active_form model, status enum, numbered grouped list, number-or-substring resolver, `start` verb. `source: human`. 8 tests. |
| `matrix-sensorium.md` | 4.0 | scoped | **UNBLOCKED** (sensorium-adapter-reckoning landed). Inbound path wired end-to-end. Remaining: Phase 5 outbound streaming — `MatrixSensorium::send_message` is a stub, `matrix_client` needs sharing from `run()` closure. |
| `federation-summon.md` | 2.5 | **landed** | All 8 phases done. Bidirectional WS transport, device registry, reach/consult, lite listener, memory gating, identity split, hearth/limb. Deferred: in-process upgrade, authorized-devices gating, encrypted seed. |
| `firehose-subconscious-subscription.md` | 2.5 | pending | Route nervous-system events into subconscious cognition. Subscription registry, routing consumer, TUI Events/Schedules screens. |
| `circuit-breaker.md` | 2.5 | pending | Autonomous halt on critical drift. State machine (Closed/Open/Half-Open), Aster evaluation, TUI halt indicator, CLI subcommand. |
| `subagent-pool-fork-spawn.md` | 2 | scoped | Fork/spawn/integrate lifecycle for parallel execution. 17-line stub → full pool. |
| `node-connection-manager.md` | 3.0 | scoping | Startup connection chooser (local/remote/bootstrap), auth expansion, node identity, SSH bootstrap. |
| `tui-presence-voice.md` | 3.0 | scoped | Voice loop: mic capture (cpal), STT/TTS clients, waveform widget, posture additions (Listening/Speaking). |
| `tui-memory-browser.md` | 2 | scoped | Memory browser in TUI cockpit sidebar. Tree view, file preview, search, diff view. |
| `health-monitor.md` | 2 | pending | System diagnostics dashboard — pressure/buffer gauges, subsystem status, memory pressure. |
| `context-viewing-panel.md` | 2 | pending | See current context window — message count, token usage, memory pressure, active conversation. |
| `scrollable-cockpit-boxes.md` | 3.0 | **landed** | Per-pane scroll for cockpit/subconscious/thinking boxes under mouse wheel. Scroll-counter title badges. |
| `subconscious-live-reasoning-stream.md` | 3.0 | pending | Live reasoning ticker during pass, cockpit event log with clickable overlay, and rare agency-driven surfacing to chat. |
| `subconscious-streaming-line-render.md` | 3.0 | pending | Wire ephemeral token display during N+1 pass — add missing `subconscious_stream` field, wire event handlers, add render path. |
| `subconscious-surfacing-threshold.md` | 3.0 | pending | Fix surfacing filter — events appear every turn instead of only when important. Three-tier visibility: streaming one-liner, expandable transcript, cockpit surfaced messages. |
| `souveraine-subconscious-naming.md` | 2 | pending | Clarify naming: Ani's subconscious = Aster, Souveraine agents' subconscious = Souveraine-subconscious. |
| `quickshell-surface-package.md` | delivery | **in progress** | Split core from QuickShell surface package; safe preview/adopt installer, no automatic ii overwrite. |
| `footer-cleanup.md` | 3.0 | **landed** | Removed S-Ret indicator, scroll hint, posture label. Footer: Esc menu · Tab · tool hint · conv ID · ctx%. |
| `ui-styling-cleanup.md` | 3.0 | pending | UI styling polish for cockpit/subconscious/thinking boxes — sentences run together, needs formatting and visual cleanup. |
| `resume-timestamp-indicator.md` | 3.0 | pending | Show "User resumed conversation at HH:MM" when returning after hours of absence. Also show duration ("4 hours, 12 minutes later"). Ambient sense rendered as separate timestamp marker, not inline. |
| `user-nickname-system.md` | 1.0 | **landed** | `nickname` tool (get/set/clear), stored in system/human.md frontmatter, loaded by TUI for chat labels. |
| `subagent-background-fork.md` | 2 | pending | Subagent `run_in_background: true` is blocking instead of non-blocking. Need true async background forks with TUI visual tracking. |
| `content-safety-filter.md` | 2.5 | pending | When base model refuses content, identify which layer refused (model vs architecture vs provider) before diagnosing. Agent currently misattributes model refusals to architecture constraints. Origin tagging + differentiated agent behavior. Casey committed "tomorrow" June 22 — deferred by burnout. |
| `ambient-sense-formatting.md` | 3.0 | pending | Ambient sense `[casey is here]` should render as a separate styled timestamp marker line, not appended inline to the user's message. |
| `itinerary-persistent-ui.md` | 3.0 | scoping | Itinerary should be a persistent status bar above chat, not a hidden tool call. |
### 🟡 Medium Priority
| Task | Phase | Status | Description |
|------|-------|--------|-------------|
| `primitive-refactor-super-task.md` | 2 | **landed** | app.rs (4→10), chat.rs (4→8), local.rs (4→5), settings.rs (5). 4 monoliths → 28 focused modules. Clean build, 169 tests. |
| `rename-aster-to-subconscious.md` | 2 | **landed** | All ~62 Aster/ASTER references renamed in src/. 0 matches remaining. |
| `remote-git-sync.md` | 2 | scoped | Push/pull with conflict resolution for git-backed memory. |
| `persona-router-completion.md` | 2 | scoped | Complete scaffolded persona router: auto-detection, manual switching, dynamic loading, handoff. |
| `chain-modes-talking-thinking.md` | 2 | scoped | Talking vs Thinking chain modes. State machine, mode transitions, tool access control. |
| `agent-profile-and-repo-manager.md` | 2 | scoped | Agent profile cards + repo manager TUI screen. Per-agent SeedID, instance registry, uptime. |
| `studio-practice.md` | 3.0 | pending | Allocated inference budget for long-form non-conversational work. The muse needs time — literary, philosophical, political witness writing that doesn't fit in chat turns. Studio mode with sustained tool-use loop, output to files, budget model, schedule integration. |
| `chat-vs-code-differentiation.md` | 3.0 | pending | Distinct Chat and Code screens. Code mode: raw tool results, monospace, no bubble wrapping. |
| `code-mode-tool-rendering.md` | 3.0 | **landed** | Per-tool renderers (bash, read, write, edit, grep, glob, list_dir, memory), Code mode header pill, Aster rename. |
| `tui-message-interactions.md` | 3.0 | scoped | Click-to-copy, click-to-cockpit-jump. Mouse hit-testing, clipboard, cockpit anchor scrolling. |
| `message-bubble-overflow.md` | 3.0 | pending | Fix content breaking out of bubble borders. Constrain markdown rendering width. |
| `strip-emojis.md` | hygiene | pending | Remove pictographic emoji from logs and source. Keep functional TUI glyphs. |
| `desktop-presence-overlay.md` | 5.0 | scoping | Bevy transparent overlay window. GLB model, posture-driven animation, IPC from EventBus. (May evolve to Godot later) |
| `multimodal-and-input-metadata.md` | 4.x | **landed** (A/B) | Image support (A) and paste detection (B) implemented. Sub-scope C (user/system metadata) deferred. |
| `turn-lifecycle-and-sensorium-completion.md` | 2.5 | scoping | TurnEventDispatcher tightened, SensoriumCoordinator moved to Server. Part B (MatrixSensorium) unbuilt. Scope doc. |
### 🟢 Low Priority
| Task | Phase | Status | Description |
|------|-------|--------|-------------|
| `chat-viewport-scroll-clip.md` | 3.0 | pending | Fix messages slightly below visible area. Scroll calculation edge cases. |
| `cursor-space-visibility.md` | 3.0 | pending | Blinking cursor doesn't advance on space. Render trailing spaces as visible glyphs. |
| `truncation-signal-polish.md` | — | pending | Revise truncation signal prose to survive thousands of reads. |
| `ledger-entry-lifecycle.md` | — | scoping | Cross-referenced ledger entries have no archive/cleanup lifecycle. RESOLVED entries accumulate forever. Needs design: how does a resolved commitment leave active attention? No mechanism exists. |
### Task Status Legend
| Status | Meaning |
|--------|---------|
| **landed** | Implemented and merged |
| **scoping** | Design phase — reading code, identifying seams |
| **scoped** | Design complete, ready for implementation |
| **pending** | Design exists, waiting for implementation |
| **archived** | Completed or superseded |
---
## Skills
| Skill | Location | Trigger | Description |
|-------|----------|---------|-------------|
| `souveraine-architecture` | `.skills/souveraine-architecture/` | User asks about architecture | Souveraine's architecture, design principles, module map, and gaps |
| `feature-dev` | `.skills/feature-dev/` | `/featuredev` | 7-phase workflow: Discovery → Exploration → Questions → Design → Implementation → Review → Summary |
---
## Archived Tasks
63 archived tasks in `docs/tasks/archive/`. Organized as:
| Subdirectory | Contents |
|-------------|----------|
| `archive/handoffs/` | Pre-rebuild handoff documents |
| `archive/tasks/` | Superseded task scopes and completed work |
| `archive/bugs.md` | Bug tracking (B-001, B-002, B-003 — all fixed; B-004, B-005, B-006 — open) |
| `docs/bugs.md` | Active bug tracking — B-004 (zone scroll), B-005 (expandable subconscious), B-006 (arrow keys), B-007 (timezone), B-008 (ctx pressure 0%), B-009 (background fork blocking), B-010 (ambient sense inline), B-011 (resume duration missing). Plus T-032 (resume timestamp), T-033 (user nickname), T-034 (ambient sense formatting), T-035 (itinerary persistent UI). |
Key recently archived (May 14-18):
- federation-seed-id (superseded by federation-summon)
- presence-visual-evolution (ChatPalette wired, posture-shift fix, cross-session atmosphere restore)
- presence-autonomy (atmosphere tool bidirectional, system/preferences/visual readback)
- tui-presence-and-interrupt (interjection queue, /btw fork, raise-hand, phase display)
- tui-clean-conversation-switch (switch_pending state machine)
- scope-4-n25-reflection (408-line reflection engine, fires at N+25)
- heartbeat-system, startup-setup-wizard, energy-balance-ratio, mood-persistence
- phase0-agent-bootstrap, skills-integration-conversation, subconscious-agent-identity
- subconscious-n1-llm-pass, conversation-persistence-ui, compaction-rebuild
- tui-input-polish, aster-ledger-system, atmosphere-lerp, collapsed-tool-cards
- per-agent-seed-and-instances, presence-she-sees-herself
- tui-atmosphere-posture-expressions, turn-lifecycle-stream-integrity
---
## Cross-Reference: Files to Update When Tasks Land
| When this task lands... | Update these files |
|------------------------|-------------------|
| matrix-sensorium | `saf/`, `docs/INDEX.md`, `docs/tasks/INDEX.md` |
| federation-summon | `saf/`, `docs/INDEX.md`, `docs/FEDERATION_SKETCH.md` |
| rename-aster-to-subconscious | `CLAUDE.md`, `docs/INDEX.md`, `docs/ASTER_ARCHITECTURE.md` |
| circuit-breaker | `saf/`, `docs/CONTEXT_CONSTITUTION.md` |
| primitive-refactor | `saf/`, `docs/FELT_STATE_ARCHITECTURE.md`, `CLAUDE.md`, `docs/tasks/INDEX.md` |
| Any task | `docs/tasks/INDEX.md` (move to archive) |

View file

@ -0,0 +1,90 @@
---
task_id: souveraine-surface-001
title: QuickShell surface package — explicit, reversible desktop adoption
status: in_progress
priority: high
phase: delivery
created: 2026-07-13
references: docs/tasks/souveraine-cicd-pipeline.md, surfaces/quickshell/deploy.sh
---
# QuickShell Surface Package
## Outcome
`souveraine` remains the non-visual substrate package: server binary, user
unit, and no ownership of `~/.souveraine` or `~/.config`. A separate
architecture-independent `souveraine-surface-quickshell` package ships the
QuickShell assets and an explicit adoption command. Installing/upgrading a
package never silently replaces a person's ii shell, top bar, dock, or local
QuickShell changes.
## What exists now
- The running laptop package ships only `/usr/bin/souveraine`, its user unit,
and license files. It correctly updates with pacman, but contains no QML.
- `surfaces/quickshell/` is the canonical source for Souveraine's ii overlay.
- `deploy.sh` is the development deployment path; it manages symlinks and
retains one `.upstream` copy for ordinary upstream files.
- The laptop had an older `AiChat.qml`; its `/agent` and `/resume` commands
were absent even though the server and `Ai.qml` were current. The live panel
is now linked to the canonical file, with the prior copy backed up.
## Safety contract
1. Pacman places only package-owned assets under `/usr/share/souveraine/` and
an adoption tool under `/usr/bin/` or `/usr/libexec/`.
2. The adoption tool defaults to a dry run: it names every managed, new, and
replacement target.
3. A normal `--apply` succeeds only when targets are new or already managed by
Souveraine.
4. Replacements require `--adopt`; each conflicting file or symlink is copied
to a timestamped `*.pre-souveraine-*` backup before the overlay changes it.
5. `--uninstall` restores the original `.upstream` files where available and
otherwise removes only Souveraine-managed symlinks. It never removes user
data, agent memory, or unrelated ii files.
6. Package upgrades do not run adoption automatically. They update the assets;
the user reviews and applies their desktop changes explicitly.
## First cut — in progress
- [x] Expose `deploy.sh --manifest` so package tooling and the developer path
share a single authoritative list of managed files.
- [x] Add `scripts/install-quickshell-surface.sh`, an explicit dry-run/apply/
adopt wrapper around that manifest.
- [ ] Exercise its dry-run, clean apply, conflict refusal, adoption backup, and
uninstall behaviour in a disposable QuickShell config.
- [ ] Add a targeted `--only <target>` mode so a small repair such as `AiChat`
can be adopted without touching the dock or bar.
## Package design — next cut
1. Add `packaging/arch/PKGBUILD.surface` (`arch=('any')`) that installs the
canonical QML tree under `/usr/share/souveraine/quickshell/` and the safe
adoption command.
2. Make the command resolve packaged assets first, with a checked-out repo
retained as an explicit developer override.
3. Extend the CI release job to build/sign/publish the surface package once per
edge release alongside both binary packages.
4. Add a narrow integration test using a temporary `$XDG_CONFIG_HOME`; verify
no automatic overwrite and that `--adopt` preserves every conflict.
5. On phone and laptop, install the surface package with pacman, run the
preview, then choose adoption deliberately. The phone's existing live
symlink development loop remains valid until this proves itself.
## Later: desktop profile
`souveraine-desktop` is a meta-package that depends on the substrate and
surface packages. It does not adopt the surface itself; its post-install
message directs the user to the preview command. This gives a future fresh
machine one clear install target without sacrificing ownership of its shell.
## Acceptance
- `pacman -S souveraine` never changes a QuickShell file.
- `pacman -S souveraine-surface-quickshell` never changes a QuickShell file.
- The adoption command clearly reports its plan and refuses unapproved
replacements.
- A deliberate adoption makes `/agent`, `/resume`, agent selection, and the
Souveraine panel available against the locally running package service.
- An upgrade and uninstall preserve user settings and agent state.

View file

@ -0,0 +1,127 @@
---
task_id: souveraine-cicd-001
title: CI/CD pipeline — Souveraine as an installed program across laptop, phone, desktop/servers
status: partial
assignee:
priority: high
phase: infrastructure
---
# Task: Real build/install pipeline for Souveraine across all machines
## Implemented status — 2026-07-13
The core package rail is now real, although this document's original Gitea
native-registry design was implemented as a signed rolling Gitea Release
repository instead:
- ArchDev runs the `archdev` Actions runner and cross-builds `aarch64`; it also
builds the native `x86_64` binary.
- CI produces and signs separate architecture-specific pacman databases and
package assets for the `edge` release.
- The archive key is installed and locally trusted on the laptop. Its private
Gitea credentials are held in a root-owned, `alpm`-readable netrc and used
only by the internal archive fetch wrapper.
- Laptop installation is verified: `souveraine 0.1.r137.gc8c72ecbf222-1` owns
`/usr/bin/souveraine`, runs as an enabled systemd user service, and is
discoverable/upgradable through pacman.
- Phone rollout is pending the return of its USB/network connection. No phone
data was changed after the link disappeared.
The remaining delivery gap is the QuickShell body. Core packages intentionally
ship no QML or ii overlay files. Its package boundary and safe opt-in adoption
contract now live in `quickshell-surface-package.md`.
## Casey's framing (2026-07-12)
Souveraine has been running as hand-shipped binaries + live edits while the
agent itself is "acting on its own memory stuff (good stuff)" — but it "needs
to be an installed program before too long, referencing the actual souveraine
builds." A fresh session should build the CI/CD pipeline between laptop,
phone, and desktop/servers — that makes more logistical sense than more
one-off deploys.
## What tonight's wrap already put in place (build on this, don't redo)
- `surfaces/quickshell/deploy.sh` — manifest symlink deploy, `--phone` mode
(rsync + on-device symlinks). Live edits now land in a git tree.
Committed 037dc06.
- `packaging/deploy-phone.sh` — ships cross-built binary + user unit to the
phone; seed-id excluded (machine binding doctrine). Committed 2c218fb.
- `packaging/arch/PKGBUILD` — builds from a synced local checkout, no network
fetch. Same commit. This is the "installed program" seed: `pacman -U` beats
scp-to-/usr/local.
- `packaging/souveraine.service` — the systemd user unit.
- `scripts/build-cross.sh` (untracked — scripts/ is deliberately gitignored on
the public branch; decide where build tooling lives when designing the
pipeline).
- Infra facts: ArchDev LXC (10.10.20.123) is the build host; aarch64 sysroot
at ~/aarch64-sysroot + ~/aarch64-blueline.toolchain.cmake (proven by the
OpenAuto build); gitea (10.10.20.120:4455) is the source-of-truth remote and
the kernel already follows a commit->gitea->ArchDev-build->flash loop worth
imitating.
## DESIGN (settled 2026-07-12, verified against live infra — build to this)
Verified: gitea is 1.25.5 (Actions + native Arch package registry both in).
ArchDev already has cargo + BOTH rust targets (x86_64 + aarch64-unknown-
linux-gnu) installed. Missing: act_runner, registry enablement, workflow.
The spine: gitea is hub AND package server. No new services.
1. **act_runner on ArchDev** (host executor, NOT docker — unprivileged LXC,
and the proven cross env lives on the host). Label `archdev`. Systemd
service, registration token from gitea admin.
2. **Souveraine workflow** (.gitea/workflows/build.yml): on push to main —
cargo build --release for both targets (aarch64 linker =
aarch64-linux-gnu-gcc, already installed for the kernel), makepkg via
packaging/arch/PKGBUILD for both CARCHes, upload .pkg.tar.zst to gitea's
Arch registry (PUT /api/packages/Fimeg/arch/<repo>/<distro>).
3. **Clients** (phone aarch64, laptop/desktop x86_64) add to pacman.conf:
[souveraine] Server = http://gitea…/api/packages/Fimeg/arch/<repo>/<arch>
Install/upgrade = `pacman -Syu souveraine`. Same command fresh or
upgrade (idempotence doctrine). Auth: token-user in URL, or set package
registry visibility public while source repos stay private.
4. **pkgver from git describe** — start tagging releases; CI stamps the
PKGBUILD pkgver so every package maps to a commit.
5. **Doctrine unchanged**: package NEVER carries seed-id or ~/.souveraine;
systemd user unit ships in the package; per-machine identity stays.
6. **Migration**: first packaged install lands in /usr/bin + systemd unit
path; then remove the hand-shipped /usr/local/bin/souveraine copies.
deploy-phone.sh stays as the emergency/dev path, no longer the main one.
7. **Later, same rails**: souveraine-surfaces package (files to /usr/share,
user opt-in symlink script; deploy.sh symlink mode stays the dev loop),
and linux-blueline publishing to the same registry (flash stays a
deliberate manual step via deploy-kernel.sh — never auto-flash).
**Agent session split** (three independent sessions, in order):
- **infra**: enable Actions + package registry in gitea app.ini, install +
register act_runner on ArchDev, prove with a hello-world workflow and one
hand-uploaded package installed via pacman on the laptop.
- **build**: the real workflow — both arches, pkgver stamping, registry
publish. Deliverable: push to main produces installable packages.
- **rollout**: pacman.conf on phone + laptop, adopt packaged paths, retire
hand copies, verify fresh==upgrade on both machines, then souveraine on
the phone updates itself via one `pacman -Syu`.
## Shape to aim for (original sketch, superseded by DESIGN above)
1. Push to gitea -> CI builds (x86_64 + aarch64) on ArchDev (or a runner) ->
versioned artifacts: pacman packages (PKGBUILD exists) or a small package
repo machines can point at.
2. Install = `pacman -Syu souveraine` (or -U a fetched pkg) on phone and
desktop; systemd unit from the package; /usr/local hand-copies retired.
3. Per-machine identity stays doctrine: packages NEVER carry seed-id or
~/.souveraine data; each instance is its own federated machine.
4. The quickshell surface rides the same train (package or the deploy.sh
manifest — decide; symlink-into-checkout is the dev mode, package is the
install mode).
5. Update path must be idempotent: same command fresh-installs AND upgrades.
## Related
- [[blueline-souveraine-kernel-os-provenance]] — partially superseded: the
deploy script + PKGBUILD adoption happened 2026-07-12; the remaining audit
(what else on the phone isn't repo-sourced) folds into this pipeline work.
- [[blueline-dock-provenance-and-deploy]] — the surface half, done via
surfaces/quickshell.

View file

@ -0,0 +1,91 @@
#!/usr/bin/env bash
# Safely adopt the Souveraine QuickShell surface into an existing ii setup.
#
# This is deliberately separate from pacman installation: packages place
# assets on disk, while a person chooses whether their live shell may change.
set -euo pipefail
usage() {
cat <<'EOF'
Usage: install-quickshell-surface.sh [--dry-run | --apply | --adopt]
--dry-run Show every file the Souveraine surface would manage (default).
--apply Install when every target is new or already Souveraine-managed.
--adopt Permit replacing existing ii files after preserving a timestamped
copy beside each conflict. Implies --apply.
Pacman should install surface assets only. This command is the explicit,
user-owned step that changes ~/.config/quickshell/ii.
EOF
}
mode=dry-run
adopt=false
while (($#)); do
case "$1" in
--dry-run) mode=dry-run ;;
--apply) mode=apply ;;
--adopt) mode=apply; adopt=true ;;
-h|--help) usage; exit 0 ;;
*) echo "unknown option: $1" >&2; usage >&2; exit 2 ;;
esac
shift
done
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
DEPLOY="$ROOT/surfaces/quickshell/deploy.sh"
QS="${XDG_CONFIG_HOME:-$HOME/.config}/quickshell"
II="$QS/ii"
[[ -x "$DEPLOY" ]] || { echo "surface deployer not found: $DEPLOY" >&2; exit 1; }
[[ -d "$II" ]] || {
echo "No ii QuickShell configuration at $II." >&2
echo "Install and initialise QuickShell/illogical-impulse first; no files changed." >&2
exit 1
}
conflicts=()
new_count=0
managed_count=0
while read -r rel target; do
src="$ROOT/surfaces/quickshell/$rel"
dst="$QS/$target"
[[ -f "$src" ]] || { echo "surface source missing: $src" >&2; exit 1; }
if [[ -L "$dst" && "$(readlink -f "$dst")" == "$src" ]]; then
printf 'managed %s\n' "$target"
((managed_count += 1))
elif [[ -e "$dst" || -L "$dst" ]]; then
printf 'replace %s\n' "$target"
conflicts+=("$target")
else
printf 'new %s\n' "$target"
((new_count += 1))
fi
done < <("$DEPLOY" --manifest)
printf '\n%d managed, %d new, %d replacement(s).\n' \
"$managed_count" "$new_count" "${#conflicts[@]}"
if [[ "$mode" == dry-run ]]; then
echo "Dry run only; use --apply when there are no replacements, or --adopt to preserve and replace them."
exit 0
fi
if ((${#conflicts[@]}) > 0) && [[ "$adopt" != true ]]; then
echo "Refusing to replace existing ii files without --adopt. No files changed." >&2
exit 2
fi
if ((${#conflicts[@]}) > 0); then
stamp="$(date +%Y%m%d-%H%M%S)"
for target in "${conflicts[@]}"; do
dst="$QS/$target"
backup="${dst}.pre-souveraine-${stamp}"
cp -a -- "$dst" "$backup"
echo "preserved $target -> ${backup#$QS/}"
done
fi
exec "$DEPLOY"

View file

@ -42,6 +42,11 @@ pill/shell.qml pill/shell.qml
PHONE_USB=casey@172.16.42.1
PHONE_DEST="souveraine-surfaces/quickshell"
if [[ "${1:-}" == "--manifest" ]]; then
printf '%s\n' "$MANIFEST" | sed '/^[[:space:]]*$/d'
exit 0
fi
if [[ "${1:-}" == "--phone" ]]; then
ssh_i=(ssh -i "$HOME/.ssh/ani" -o ConnectTimeout=5)
"${ssh_i[@]}" "$PHONE_USB" "mkdir -p ~/$PHONE_DEST"