# ▶ Lumina Everywhere — Master Sprint Plan (2026-06-17)

Goal: run Lumina's full self on **.41** as well as **.158** (her dedicated home), expose her
creative + chat capabilities across **Telegram (done), skchat-app/webui, and OpenCode/.41**,
with **pinpointed sync** (no 150GB ~/clawd replication) and **Telegram-style in-app media**
(gallery + delete). Designed by a 5-agent planning swarm; this is the synthesis.

## The 5 epics
| | Epic | What it delivers |
|---|---|---|
| **A** | Pinpointed Sync Architecture | .158↔.41 are one self (memory+config+soul+skills converge) without syncing 150GB |
| **B** | .41 Lumina Deployment | Lumina's full stack current + running on .41 (skos), worship renders via .100 |
| **C** | Surface-Agnostic Delivery + OpenCode | One delivery abstraction (Telegram \| skchat \| filepath); worship MCP in OpenCode on .41 |
| **D** | skchat-app Tool-Calling | The in-app reply path gains MCP tool-calling so worship/all tools work in the app + webui |
| **E** | In-App Media UX | Telegram-style media gallery + message delete (app + webui + MCP) |

## Critical cross-cutting findings (from the swarm)
1. **Sync (A):** It's NOT "config syncs via nothing" — **.41's Syncthing link to .158 is DEAD** (device `4U3J4V6` never-connected, folder `skcapstone-sync`→`~/.skcapstone` at 91.5%/238MB behind; `.stignore` even marks .41 "decommissioned"). Config (`lumina-mcp.yaml`, `profile.yaml`, soul) **already lives inside the synced `~/.skcapstone` tree and is NOT ignored** — so **reviving the link auto-fixes config drift.** skskills → set `SKSKILLS_HOME=~/.skcapstone/skskills` to ride the same sync (registry honors it; nothing hardcoded).
2. **.41 deploy (B):** `.41`'s lumina-creative tracks **skgit** (`chefboyrdave2.1`), not **github** (`chefboyrdave21`) where worship lives → **repo-remote split blocker**. `~/clawd/tools/mcp-wrappers/` is **absent on .41** (nextcloud/gog/skmemory wrappers already dangling there). `skcapstone@lumina` daemon not running on .41. `profile.yaml` exists on **.158** (created today) but **not .41** (Sync epic propagates it once link is live). **DO NOT run the Telegram bridge on .41** (two getUpdates consumers = 409 conflict).
3. **Delivery (C):** clean — a new `worship-mcp/sinks.py` with `TelegramSink` (lift current code verbatim) / `SkchatSink` (`skchat.attachments.AttachmentService.send_attachment` → posts a file-message into the conversation) / `FilepathSink` (return path for OpenCode). Sink chosen from context (`deliver_chat_id`→TG, `deliver_skchat_peer`→skchat, neither→filepath). **OpenCode needs a *synchronous* filepath path** (server.py currently detaches the worker with stdout=DEVNULL → printed path is lost). OpenCode confirmed: `1.14.33` at `/usr/bin/opencode`, qwen3.6 via beellama provider, MCP block in `~/.config/opencode/opencode.json`, tool-calling with this model already proven.
4. **skchat-app (D):** The in-app reply is generated by the **daemon** (`advocacy.py` → `LLMBridge.generate`, **completion-only, no tools**), NOT the webui (webui is send/render only). Fix = factor the Telegram tool loop into a package module **`skchat.tool_loop.ToolLoopEngine`** and route advocacy through it (reuses `bridge_consciousness.McpToolRouter`/`LiveMemory` + the `profile.yaml` curation). **The model-picker is currently decorative** (only the dead `lumina-bridge.py` reads it) — D-S4 can make it real.
5. **Media (E):** media = `ChatMessage` + `FileRef` attachments (no `MessageType` enum — stale doc); files at `~/.skchat/received/{transfer_id}/`. Flutter app = `~/clawd/skcapstone-repos/skchat-app` (Riverpod). **Flutter `ChatMessage` has NO attachment fields** → the app can't even tell a message is media (S1 prerequisite: push attachment metadata through CLI/daemon JSON + model). No general delete today; tombstone precedent in `ephemeral.py`. Delete-for-everyone in P2P = best-effort.

---

## Execution waves (cross-epic)

### Wave 0 — Foundation (careful/sequential; mostly hands-on, minimal farm)
- **A-S1** revive .158↔.41 Syncthing link; **A-S2** reconcile config drift (.158 authoritative) BEFORE first live sync (avoid `.sync-conflict` storm).
- **B-S1** .41 hygiene (stale `~/.local/bin/skcapstone`, doctor --fix); **B-S2** git pull + reinstall skchat/skmemory/skcomms/skvoice on .41.
- **Repo-remote fix**: mirror github `chefboyrdave21/lumina-creative` → skgit `chefboyrdave2.1` (or add github remote on .41) — unblocks B-S3.
- **A-S4 decision**: `SKSKILLS_HOME=~/.skcapstone/skskills` (relocate runtime into the synced tree) — set on both boxes.

### Wave 1 — Parallel builds (FARMABLE to swarms)
- **C-S1** `sinks.py` abstraction (new module). ‖
- **D-S1** extract `skchat.tool_loop` from the bridge (no behavior change; well-tested). ‖
- **E-S1** attachment metadata through CLI/daemon JSON + Flutter model → **E-S2** `list_media` backend + **E-S3** video thumbnails.

### Wave 2 — Integrations (FARMABLE, gated on Wave 1)
- **C-S2/S3** wire workers + arc_lib to sinks; **C-S5** OpenCode-on-.41 (filepath sink) → the OpenCode win.
- **D-S2** route daemon advocacy through `ToolLoopEngine` (tools fire in-app on direct qwen).
- **E-S4** backend delete + tombstone propagation.
- **B-S3/S4/S5/S6** worship wrapper+config on .41, skos registration, render verify.

### Wave 3 — Surfaces + polish
- **C-S4** SkchatSink (in-conversation delivery) — unlocks media-in-app.
- **D-S3** in-app delivery context (needs C-S4); **D-S4** make model-picker real (gated).
- **E-S5/S6** app gallery + delete UI; **E-S7** webui parity.

---

## Decisions that gate the work (need Chef)
1. **skskills relocation** → `SKSKILLS_HOME=~/.skcapstone/skskills` so skills sync? (Recommended — your idea, confirmed feasible.) [A-S4]
2. **secrets.env**: it currently rides the synced folder to every peer (incl. .100). Move to per-box-local + git-crypt, or accept? (Recommend: stop syncing it.) [A-S3]
3. **Repo remote**: mirror github→skgit (clean, Sync-owned) vs add github remote+creds on .41. (Recommend mirror.) [B-S3]
4. **.41 identity**: device is named `jarvis-laptop` on .158 but `cbrd21-laptop12thgenintelcore` on .41 (same ID), and `.stignore` calls it "decommissioned" — confirm .41 is genuinely Lumina's 2nd home. [A-S1]
5. **OpenCode NSFW**: explicit PNGs as openable file paths in the .41 TUI — OK? [C-S5]
6. **In-app delete**: ship "delete for everyone" (best-effort P2P disclaimer) or local-only v1? [E-S4]
7. **In-app model**: default in-app tools to direct qwen (parity, known-good) and make the picker real later (D-S4), or block on SKGateway tool-passthrough now? (Recommend qwen-first.) [D]

## Hard dependencies
- **C (delivery) blocks** D-S3 (in-app delivery) and E (worship images arrive via SkchatSink/AttachmentService).
- **A (sync link) blocks** B-S4 config parity (propagates `lumina-mcp.yaml`+`profile.yaml` to .41).
- **Repo-remote fix blocks** B-S3 (worship source on .41).
- **D-S1 (tool_loop extract) blocks** D-S2; **E-S1 (attachment metadata) blocks** E-S5.

## Farm map (what goes to build-swarms vs hands-on)
- **Hands-on / careful:** A-S1/S2 (Syncthing, cross-box, conflict-prone), repo mirroring, B-S1 (stale installs), D-S1 (foundational refactor of a live bridge).
- **Farmable (isolated, testable):** C-S1, E-S1/S2/S3/S4, C-S2/S3, E-S5/S6/S7 (app), D-S2 (with care), C-S4/S5.
