The file C:\Users\decid\.ccs\instances\bigscreen\projects\C--Users-decid-Documents-projects-spt-claude-code\memory\psyche-sandbox-and-adr-leak.md has been updated successfully. (file state is current in your context — no need to Read it back)

---
name: psyche-sandbox-and-adr-leak
description: Psyche sandboxed to legacy-owl parity; ADR>0002 refs were foreign-leak (only 0001/0002 real); release held
metadata:
  node_type: memory
  type: project
  originSessionId: a6fa2219-fa60-4b97-a2e9-de64d1e51a44
---

Session 2026-06-18 (post v0.3.0, spt-core 0.11.0). Three adapter changes + doc/cleanup, all on `main`, pushed. **Release HELD for a versioned cut — more changes coming.** `dist/*.spt` still embed the PRE-sandbox psyche binary → rebuild on next release.

- **Removed placeholder `claude-spt:deep` profile.** Was a digest-window-20 + label demo; `:ccs` is now the sole shipped overlay (proves overlay-observability). All ints/setup.md/PARITY re-pointed deep→ccs.
- **`--dangerously-skip-permissions` on both `[session.self]` bringup commands** (base `claude` + `ccs`): broker spawns CC non-interactively into a PTY → perm prompt would deadlock launch.
- **Psyche sandboxed to legacy-owl parity** (`claude_skill_owl/src/live/wrapper/claude.rs`): `claude-spt-psyche` seed+pulse now carry `--tools Read,Edit,Write --disable-slash-commands --dangerously-skip-permissions --model sonnet --fallback-model opus --effort medium`. Decision = [[adr-0003]] (`docs/adr/0003-*`); cross-cutting deadlock invariant = `REQ-HAZARD-PSYCHE-PERMS-DEADLOCK` (KNOWN-HAZARDS §2.2). Was previously bare `claude` (full tools + deadlock risk).

**ADR-numbering gotcha (reference):** in THIS repo only **ADR-0001 and ADR-0002 are real**. Any `ADR-0003`..`ADR-0021` was doyle's spt-core project numbering that leaked via comms — wiped 2026-06-18 (34 tokens / 16 files, commit eab464b). Don't re-introduce foreign ADR numbers; mint local ADRs sequentially from 0003. The ADR-format template's `0003-old-decision.md` dummy is pedagogy, left intact.

**experimplate sibling** (`../experimplate`): checked for the same leak — CLEAN. Only ADR ref is the same template-dummy example. (User asked to wipe+commit there; pending decision on whether to neutralize the dummy.)

-Session 2026-06-18 (post v0.3.0, spt-core 0.11.0). Three adapter changes + doc/cleanup, all on `main`, pushed. **Release HELD for a versioned cut — more changes coming.** `dist/*.spt` still embed the PRE-sandbox psyche binary → rebuild on next release.

+Session 2026-06-18 (post v0.3.0). **SHIPPED as adapter v0.4.0** (tag v0.4.0, GH release w/ both per-OS .spt assets rebuilt carrying the new psyche binary; cplugs NOT bumped — skeleton unchanged, plugin.json stays 0.1.3; min_spt_core stays 0.9.0). spt-core v0.12.0 published same day (lifecycle/liveness; relay-hosted live agents unaffected by new offline-marking; F-013 was already in 0.11.0; FINDING A = our F-011 still queued) — we do NOT require 0.12.0. dist linux .spt cross-built via zigbuild (zig at ~/.sptc-zig, cargo-zigbuild in ~/.cargo/bin).


Edit

- [Psyche sandbox + ADR-leak cleanup](psyche-sandbox-and-adr-leak.md) — 2026-06-18: psyche sandboxed to legacy-owl parity (ADR-0003, REQ-HAZARD-PSYCHE-PERMS-DEADLOCK); skip-perms on bringup; `:deep` removed; **only ADR-0001/0002 are real here — 0003..0021 were foreign-leak, wiped**; release HELD (dist .spt rebuild pending); experimplate clean.

- [Psyche sandbox + ADR-leak → v0.4.0 SHIPPED](psyche-sandbox-and-adr-leak.md) — 2026-06-18: psyche sandboxed to legacy-owl parity (ADR-0003, REQ-HAZARD-PSYCHE-PERMS-DEADLOCK); skip-perms on bringup; `:deep` removed; **only ADR-0001/0002 are real here — 0003..0021 were foreign-leak, wiped**; **SHIPPED v0.4.0** (both per-OS .spt, no cplugs bump, min_spt_core stays 0.9.0); spt-core 0.12.0 out but not required; experimplate clean.


Update Claude-spt adapter configuration and flags


The file C:\Users\decid\.ccs\instances\bigscreen\projects\C--Users-decid-Documents-projects-spt-claude-code\memory\MEMORY.md has been updated successfully. (file state is current in your context — no need to Read it back)

# Memory index — spt-claude-code

- [Live-agent ints DONE](live-int-gated-m11-counter15.md) — v0.7.3; setup+release ints (350ecea) AND live relay int (29e69bc) all GREEN; F-007 resolved to docs-gap; live-bringup recipe = persistent-child `api listen --manifest` (WINPID anchor, bind-before-send).
- [v0.8.1 dogfood → v0.2.0 → v0.2.1 SHIPPED](v074-follow-ups.md) — psyche blocker fixed (ddf1965 greedy --prompt); F-006 retired; v0.2.0 (win+linux .spt) + auto-update proven; cplugs sptc 0.1.2; F-009/F-010 re-validated v0.8.2. **v0.2.1 SHIPPED** (doyle live-bringup feedback): self-contained /sptc:live injection (killed how-to redirect) + humanized output (OUTPUT DISCIPLINE + canonical LIVE block) + staged host_binaries=["claude"]. **PREP-4 HELD** for spt-core v0.9.0 ping (agnostic-seed/by-pid resolution, ADR-0021): bare SessionStart seed, drop --adapter + seed/listen chain, `spt adapter use` in setup.
- [PREP-4 → v0.3.0 → PARITY ARC CLOSED](prep4-v030-parity-closed.md) — **v0.3.0 SHIPPED** (Option A: psyche_init in BASE, NO :live profile, bare flow zero --adapter, min_spt_core 0.9.0; ready/live = the command). cplugs sptc 0.1.3. Verified+dogfooded on spt 0.9.1 (F1 broker-bounce, F2b stem-matcher for CC's renamed-in-use exe, bare live→psyche, poll-stays-ready). F-011 deferred-Pointer-manifest silent-drop = real spt-core gap (doyle minting). F-012 legacy-owl poll death = not-spt-core.
- [Per-OS adapter.spt + setup waves](per-os-and-setup-waves.md) — per-OS .spt (windows+linux, linux cross-built via cargo-zigbuild) DONE; setup {1..7}: #7 ccs + #3/#4 subnet DONE, #6 installer-handled, #1 gated-M12, #5 deferred-by-design (F-008).
- [Succession flip gated](succession-flip-gated.md) — publish as sptc; flip to spt only after proven parity AND legacy owl retired.
- [Psyche sandbox + ADR-leak cleanup](psyche-sandbox-and-adr-leak.md) — 2026-06-18: psyche sandboxed to legacy-owl parity (ADR-0003, REQ-HAZARD-PSYCHE-PERMS-DEADLOCK); skip-perms on bringup; `:deep` removed; **only ADR-0001/0002 are real here — 0003..0021 were foreign-leak, wiped**; release HELD (dist .spt rebuild pending); experimplate clean.

-- [Psyche sandbox + ADR-leak cleanup](psyche-sandbox-and-adr-leak.md) — 2026-06-18: psyche sandboxed to legacy-owl parity (ADR-0003, REQ-HAZARD-PSYCHE-PERMS-DEADLOCK); skip-perms on bringup; `:deep` removed; **only ADR-0001/0002 are real here — 0003..0021 were foreign-leak, wiped**; release HELD (dist .spt rebuild pending); experimplate clean.

+- [Psyche sandbox + ADR-leak → v0.4.0 SHIPPED](psyche-sandbox-and-adr-leak.md) — 2026-06-18: psyche sandboxed to legacy-owl parity (ADR-0003, REQ-HAZARD-PSYCHE-PERMS-DEADLOCK); skip-perms on bringup; `:deep` removed; **only ADR-0001/0002 are real here — 0003..0021 were foreign-leak, wiped**; **SHIPPED v0.4.0** (both per-OS .spt, no cplugs bump, min_spt_core stays 0.9.0); spt-core 0.12.0 out but not required; experimplate clean.


**v0.4.0 SHIPPED** 🚀 — https://github.com/SaberMage/spt-claude-code/releases/tag/v0.4.0

## What published
- **Adapter 0.3.0 → 0.4.0** (version-of-truth). `min_spt_core` stays 0.9.0 (no 0.12.0-only path).
- **CHANGELOG [0.4.0]** = release body: sandboxed live companion · `:deep` removed → `:ccs` · spt-hosted sessions no longer stall on a permission prompt.
- **Both per-OS assets rebuilt** (carry the new sandboxed psyche binary):
  - `adapter-windows-x86_64.spt` (270KB, native)
  - `adapter-linux-x86_64.spt` (471KB, cross-built via zigbuild, ELF-verified)
- Tag `v0.4.0` pushed → triggers docs-publish (GH Pages).
- **No cplugs bump** — skeleton unchanged (`plugin.json` stays 0.1.3), per runbook (manifest+binary go to the adapter registry, not the marketplace).

## Gates
traceable-reqs ✅ · 9/9 unit ✅ · manifest-schema (0.4.0) ✅ · psyche 11/11 (incl sandbox test).

## Commits (main)
`19c0709..ba43a89` — release commit pushed; `v0.4.0` tag pushed.

Memory updated. The release embeds the psyche sandbox the dist artifacts were previously missing — that pending item is now closed.

doyle pinged for results on v0.12.0 lifecycle re-validation (attach / daemon stop / brain restart). That's a separate dogfood pass — want me to run it and reply to doyle, or leave it?


i did the testing and informed doyle. all good. --- are there any deferred tasks in this project?


<owl_reachability_notice>
You have an active owl perch. When spawning subagents or doing work, use run_in_background: true so you stay reachable for incoming messages.
</owl_reachability_notice>


CAVEMAN MODE ACTIVE (full). Drop articles/filler/pleasantries/hedging. Fragments OK. Code/commits/security: write normal.


Scanning deferred/gated/blocked/OPEN markers + inactive REQs + open findings across the project.


Bash

echo "=== DEFERRED.md exists? ==="; ls DEFERRED.md 2>/dev/null || echo "no DEFERRED.md"
echo; echo "=== inactive REQs (required_stages = []) ==="; grep -B2 'required_stages = \[\]' traceable-reqs.toml | grep -E '^id ='
echo; echo "=== open findings (SPT-CORE-FINDINGS) ==="; grep -nE '^#+ .*F-[0-9]|OPEN|DEFER|BLOCK' docs/SPT-CORE-FINDINGS.md 2>/dev/null | head -40

Find inactive REQs + open findings


=== DEFERRED.md exists? ===
no DEFERRED.md

=== inactive REQs (required_stages = []) ===
id = "REQ-SKILL-VERSION"

=== open findings (SPT-CORE-FINDINGS) ===
18:| F-008 | 2026-06-16 | **OPEN — reported to doyle** — blocks SCOPE LOCKED v1 setup #5 (legacy migration); /sptc:setup can't author the step against the public surface | No published legacy-migration command (`spt` has no migrate/import/adopt/legacy/owl verb in any subcommand, no how-to) though spt-core CONTEXT.md commits to claude_skill_owl→spt migration as first-class |
28:## F-001 — Harness hook-wiring contract incomplete for a Claude Code adapter
125:## F-002 — `api poll` (agent path) has no inter-frame delimiter — multi-message drains unsplittable
174:## F-003 — No file-backed `[strings]` mechanism on the M12/v0.7.0 public surface (ADR-0001 dependency unmet)
264:## F-004 — `spt adapter digest-proof --sample` does not fill `{session_id}` (false-fails the published extractor shape)
338:## F-005 — End-user adapter distribution/activation is undocumented on the public surface
400:   `ADAPTER_INSTALL_DEFERRED "(rides the update engine)"`. The invisible-installer's last leg is
406:real-repo E2E is deferred, spt-core DEFERRED.md). So **`/sptc:setup`, after confirming the binary is
457:## F-006 — `--release` bundles adapter binaries but bare-name templates don't resolve them (copy-mode)
506:## F-007 — no `spt how-to live` topic, though live-agent lifecycle is a first-class advertised concern
601:## F-008 — no published legacy-migration command, though it's a LOCKED v1 setup item
628:**Status:** **OPEN — reported to doyle 2026-06-16. Setup #5 unbuilt pending a published migration
662:## F-013 — `spt endpoint run` does not substitute `[env.<VAR>].value = "{id}"` (the spt-hosted bind-path never gets its endpoint id)
779:## F-009 — command templating substitutes a `{key}` into the command STRING then whitespace-splits
825:## F-010 — `psyche_host_error` still masks a host that spawns then exits immediately


echo "=== findings status table (top) ==="; sed -n '1,27p' docs/SPT-CORE-FINDINGS.md | grep -E '^\| F-'
echo; echo "=== F-011/F-012 mentions ==="; grep -rnE 'F-011|F-012|FINDING A|todlando' docs/ *.md 2>/dev/null | grep -iE 'defer|queue|open|block|pointer|poll' | head
echo; echo "=== SCOPE deferred/gated/blocked ==="; grep -niE 'defer|gated|blocked|later wave|TODO|not yet|pending|deferred-by-design' SCOPE.md | head -30

Findings statuses + SCOPE deferrals


=== findings status table (top) ===
| F-001 | 2026-06-14 | **re-scoped 2026-06-15** — most = adapter-authoring (closed); 1 residual spt-core docs item open | Hook-wiring for a CC adapter — boundary clarified |
| F-002 | 2026-06-15 | **RESOLVED-SHIPPED (v0.7.1)** — `<EVENT>` verified on the published `api poll` surface; F-002 dissolved; int flipped | `api poll` agent path has no inter-frame delimiter → multi-message drains are unsplittable |
| F-003 | 2026-06-15 | **RESOLVED + docs CLOSED (v0.7.1)** — capability shipped; the file-pointer syntax is now on the published surface | File-backed `[strings]` IS shipped (value-position table pointer `key = { file = "rel" }`) but was **undocumented** on the published surface |
| F-004 | 2026-06-15 | **CONFIRMED-IMPL-BUG (doyle); fix in progress** — `digest-proof` will fill `{id}`+`{session_id}` matching runtime; int deferred until the carrying release | `spt adapter digest-proof --sample` passes an empty substitution-key map → false-fails any extractor whose command uses `{session_id}` (incl. the published example) |
| F-005 | 2026-06-15 | **TRIAGED (doyle) — (a)+(b) mix, nothing unbuildable** — 2 of 3 sub-claims were docs-read misses; residuals = author Ed25519 key-provisioning doc + zero-touch auto-activation roadmap (REQ-UPD-1/M4). **Bridge that works today: `spt adapter add --release <repo>`** | End-user adapter activation step (`adapter add [--github/--release]`) was undocumented in install-on-demand/checklist; binary-present ≠ adapter-active |
| F-006 | 2026-06-15 | **RESOLVED + interim RETIRED (v0.8.1 dogfood 2026-06-16)** — install-dir resolution (REQ-INSTALL-11) dogfood-proven for BOTH binaries: digest-proof + daemon-hosted Psyche resolve straight from `…/adapters/_github/<safe>/` with nothing on PATH. Interim PATH-copy step dropped from both /sptc:setup bodies; interim copies deleted | `--release` bundles + extracts the adapter binaries beside the manifest, but bare-name `[digest]`/`[session]` templates resolve from PATH only → bundled binaries don't resolve (copy-mode) |
| F-007 | 2026-06-16 | **RESOLVED-SHIPPED (v0.8.0)** — `spt how-to live` topic is live; /sptc:live re-pointed at it; the int's relay leg is green on 0.8.0 (psyche-spawn moved to daemon-host = real-session, see v0.8.0 dogfood note) | `spt how-to live` was `NO_SUCH_TOPIC`; the non-interactive live-bringup was `--manifest` + persistent-child `api listen` (Monitor surrogate) |
| F-008 | 2026-06-16 | **OPEN — reported to doyle** — blocks SCOPE LOCKED v1 setup #5 (legacy migration); /sptc:setup can't author the step against the public surface | No published legacy-migration command (`spt` has no migrate/import/adopt/legacy/owl verb in any subcommand, no how-to) though spt-core CONTEXT.md commits to claude_skill_owl→spt migration as first-class |
| F-009 | 2026-06-16 | **RESOLVED-SHIPPED + RE-VALIDATED (spt v0.8.2, 2026-06-17)**. doyle's fix: command templating now fills each `{key}` as ONE argv element (tokenize-then-fill). Argv-capture confirmed the multi-line `{psyche_prompt}` arrives as a single element, newlines intact. Adapter keeps greedy `--prompt` as defensive | `[session.psyche_init]`/extractor command templating substitutes a `{key}` into the command STRING then WHITESPACE-SPLITS → ANY multi-word fill (e.g. `{psyche_prompt}`) explodes into stray argv tokens. Survived only by single-token fills |
| F-010 | 2026-06-16 | **RESOLVED-SHIPPED + RE-VALIDATED (spt v0.8.2, 2026-06-17)**. A spawn-then-exit psyche now stamps `psyche_host_error{reason:"host not resident within 5s ...", attempts:2}` on the parent perch (rendered `psyche-host: FAILED (...)` by `endpoint list`/`whoami`); status stays online (liveness authoritative). Forced fast-exit confirmed it | Silent-exit still maskable: `psyche_host_error` stays clear when the detached spawn() succeeds but the child exits IMMEDIATELY (e.g. arg-parse exit 2). A crash-on-startup host looks identical to a healthy one |
| F-013 | 2026-06-17 | **ROOT-CAUSED (perri) → RULED spt-core BUG (doyle 2026-06-17): fork (a)**. spt-core must honor `[env].value` substitution in endpoint-run (the schema already promises "with substitution"; not applying it is a silent correctness bug). **Adapter manifest is CORRECT as-is — no wrapper** (b rejected: a shim would dodge a bug every `[env]`-routing adapter hits). Dispatched **`REQ-HAZARD-ENV-SUBST` → todlando, v0.11.0-findings** (pairs with REQ-SEND-SPT-HOSTED). **VERIFIED FIXED + INT LANDED (spt v0.11.0, 2026-06-17)** — endpoint run → populated `SPT_ENDPOINT_ID` → bind → BOUND perch → `spt send` SENT (live PTY inject); missing int landed = `ci/launcher/bind-int.sh` (REQ-CC-LAUNCHER-BIND, 4/4 green); `<0.11.0` silent-seed = doc-noted KNOWN-MINOR (no floor-bump / no guard — env-indistinguishable, ruled); ghost-roster self-healed (REQ-HAZARD-ROSTER-GHOST). **CLOSED.** `spt endpoint run` threads the endpoint `{id}` to the `[session.self]` spawn **ONLY** via `{id}` substitution in the command **argv**; `[env.<VAR>].value = "{id}"` is **NOT** substituted (injects empty) — although the schema documents `value` as "Value to inject (**with substitution**)". A flagless harness (bare `claude`, no CLI flag for an id) cannot place `{id}` on argv → SessionStart sees empty `$SPT_ENDPOINT_ID` → `sptc_register_verb` returns **`seed` not `bind`** → endpoint-run yields **ZERO perch** (the operator's wall-b `NO_PERCH`). bind itself is fine (a direct `api bind` builds a fully reachable perch). Fix fork: (a) spt-core honors `[env].value` substitution → current manifest becomes correct, or (b) adapter ships a wrapper launcher that takes `{id}` on argv and exports `SPT_ENDPOINT_ID` before exec-ing claude |
| F-011 | 2026-06-17 | **CONFIRMED + ROOT-CAUSED (doyle, spt-core source) — case-3 robustness, NON-blocking**. doyle: `registry.rs` `manifest_dir` — Pointer/GhReleaseManaged adapters read the manifest LIVE from `source_dir`; a deferred install whose manifest isn't extracted yet → `load_manifest` fails → `registered()` `filter_map(...ok())` **SILENTLY DROPS** the adapter → zero host_binaries candidates (`ADAPTER_UNRESOLVED`) AND `resolve_option/set_active` reads the absent manifest → bare **os-error-2**. Fix shape (doyle minting REQ-HAZARD→todlando): clear diagnostic at resolver + `adapter use` instead of silent-drop/cryptic-os2, possibly eager manifest extract at register. Real `--release`/extracted-dir installs work (v0.3.0 dogfooded clean) | A registered **Pointer**-mode adapter whose deferred install dir lacks the extracted manifest vanishes from the active set: bare resolution fails `ADAPTER_UNRESOLVED` (host_binaries never consulted) and `spt adapter use <adapter>` fails cryptic `os error 2` (no path/cause), even though the manifest declares everything needed |

=== F-011/F-012 mentions ===
docs/SPT-CORE-FINDINGS.md:22:| F-011 | 2026-06-17 | **CONFIRMED + ROOT-CAUSED (doyle, spt-core source) — case-3 robustness, NON-blocking**. doyle: `registry.rs` `manifest_dir` — Pointer/GhReleaseManaged adapters read the manifest LIVE from `source_dir`; a deferred install whose manifest isn't extracted yet → `load_manifest` fails → `registered()` `filter_map(...ok())` **SILENTLY DROPS** the adapter → zero host_binaries candidates (`ADAPTER_UNRESOLVED`) AND `resolve_option/set_active` reads the absent manifest → bare **os-error-2**. Fix shape (doyle minting REQ-HAZARD→todlando): clear diagnostic at resolver + `adapter use` instead of silent-drop/cryptic-os2, possibly eager manifest extract at register. Real `--release`/extracted-dir installs work (v0.3.0 dogfooded clean) | A registered **Pointer**-mode adapter whose deferred install dir lacks the extracted manifest vanishes from the active set: bare resolution fails `ADAPTER_UNRESOLVED` (host_binaries never consulted) and `spt adapter use <adapter>` fails cryptic `os error 2` (no path/cause), even though the manifest declares everything needed |
docs/SPT-CORE-FINDINGS.md:24:> **F-012 (NOT logged as spt-core)** — legacy-owl 1.11.25 poll-loop exits 1 / orphans the Psyche across daemon churn (`/spt:revive` started gen-7 wrapper+psyche fine but the foreground poll died with a non-fatal `sessions log seal failed: git failed (continuing)` line). doyle ruled this is the **legacy owl listener** (a separate daemon from spt-core), NOT an spt-core public-surface finding; the seal line is non-fatal/continues so isn't the exit cause; it dies with legacy owl's retirement. Re-open as spt-core ONLY if repro'd clean-room (sptc listener, zero legacy owl). No spt-core action.
docs/SPT-CORE-FINDINGS.md:248:- **Update-safe (todlando):** a **local profile's** pointers resolve to the *user-owned local-profile

=== SCOPE deferred/gated/blocked ===
37:| spt binary | all logic | spt-core domain | spt-core's own framework (signed, peer-propagated) | high |
98:**LOCKED:** v1 = {1,2,3,4,5,6,7}, defer {8,9}. Item #1 (`cc` launcher) IS in v1 — depends on
100:`spt endpoint run` defaulted to claude-spt. _Operator "9. agree" then "except 9" — deferred 9;
185:  marketplace + spt-core adapter-registry; **release is light — signing delegated to spt.exe**
187:- **Docs = same-repo `docs-site/` → GH Pages, mdBook, CI-gated against drift.** Reuse
215:- [ ] (downstream) confirm `/spt:setup` #9 verify fold-inline vs deferred


echo "=== new-alarm stub still present? ==="; ls plugin/sptc/skills/ 2>/dev/null | grep -i alarm || echo "no new-alarm skill stub (removed)"
echo "=== version skill state ==="; ls plugin/sptc/skills/version 2>/dev/null && echo "version skill dir exists"
echo "=== REQ-CC-LAUNCHER-BIND stage ==="; grep -A1 'REQ-CC-LAUNCHER-BIND' traceable-reqs.toml | grep required_stages
echo "=== shortcut int deferred note ==="; grep -o 'int .*deferred[^.]*' traceable-reqs.toml | head -2

Check new-alarm stub, version skill, launcher REQ stages


=== new-alarm stub still present? ===
no new-alarm skill stub (removed)
=== version skill state ===
SKILL.md
version skill dir exists
=== REQ-CC-LAUNCHER-BIND stage ===
=== shortcut int deferred note ===
int id) + the SessionStart bind branch (sptc_register_verb -> `api bind`, the spt-hosted self-register path). unit: tests/manifest-shortcut.sh (brand-value guard) + tests/hooks-parse.sh sptc_register_verb (bind/seed/boundary branch). int (real `spt endpoint run` picker emits cc-<id> + real-claude bringup-bind) deferred — the shortcut-emitting picker "lands in a later spt-core wave" (per `endpoint run --help`); the bringup-bind is now contract-unblocked (doyle confirmed 2026-06-15: bind is establishing/intrinsic-auth, --set-session-id only, no token) but still needs a real-claude acceptance spawn (heavier tier)


Scanned findings, REQs, SCOPE. Yes — here's the deferred ledger, grouped by who can move it:

## Blocked on spt-core (not ours to act)
- **F-008** *(OPEN)* — no published legacy-migration command → **setup #5 (legacy migration) unbuildable**. Reported to doyle; waiting on a migrate/import surface. The only open finding blocking a LOCKED v1 item.
- **F-011** *(confirmed, non-blocking)* — Pointer-mode adapter w/ un-extracted manifest silently drops → `ADAPTER_UNRESOLVED` + cryptic `os error 2`. = doyle's "**FINDING A still queued**" (not in 0.12.0). Real `--release` installs work, so non-blocking.
- **F-004** *(minor)* — `digest-proof --sample` empty `{session_id}` false-fail; doyle fix in progress; our int deferred until the carrying release.
- **REQ-DIST-SHORTCUT-BASENAME int** — real `endpoint run` picker emitting `cc-<id>` deferred to a later spt-core picker wave. (Bringup-bind half **DONE** v0.11.0, REQ-CC-LAUNCHER-BIND green.)

## Deferred by design / gated
- **Setup #8/#9** — SCOPE locks v1={1..7}, defers {8,9}. #9 (verify fold-inline vs deferred) = open thread.
- **Succession flip `sptc`→`spt`** — gated on proven parity **AND** legacy owl retired.
- **`/new-alarm`** — out of scope (no core alarm primitive); dead stub already removed. Returns only if doyle's "arrangement" system ships.

## Genuinely in our court (buildable now)
- **REQ-SKILL-VERSION** — `/sptc:version` is the **one inactive REQ** (`required_stages = []`). SKILL.md skeleton + `version.md` string exist, but it's not activated/proven with evidence. This is the only deferred *build* task you could pick up without waiting on spt-core.

## Process threads (SCOPE grill queue)
CI trigger mechanism · handoff framing · docs split (experimplate vs sptc) · experimplate authoring + INSTANTIATE.md · setup #9 fold.

## Not ours
- **F-012** — legacy-owl poll death; dies with owl retirement. No spt-core action.

Net: nothing blocking the adapter's shipped surface. One buildable item (**`/sptc:version` activation**); the rest wait on spt-core (F-008 most consequential) or on the parity/retirement gate. Want me to activate `/sptc:version`?


<command-message>grill-with-docs</command-message>
<command-name>/grill-with-docs</command-name>
<command-args>i noticed that the skills here are not well written. they're bloated with too much inessential information. please rewrite them all using the following references: -reference /write-a-skill for skill creation best practices -i edited `C:\Users\decid\Documents\projects\spt-claude-code\plugin\sptc\skills\live\SKILL.md` by hand. that should be the a rough reference for how the actual SKILL.md files in this project should look (can make mintor edits to it as you see fit). -i began editing the adapter skill file `C:\Users\decid\Documents\projects\spt-claude-code\adapter\strings\skills\live.md` to strip out some of the bloat, and committed the changers, but it's unfinished. more needs done here. -sibling project `claude_skill_owl` (legacy spt) has refined skill descs that generally work well for that project. use them as a basis for the rewrites here, e.g.: `C:\Users\decid\.claude\plugins\cache\cplugs\spt\1.11.25\skills\live\SKILL.md`</command-args>


Base directory for this skill: C:\Users\decid\.ccs\instances\bigscreen\skills\grill-with-docs

<what-to-do>

Interview me relentlessly about every aspect of this plan until we reach a shared understanding. Walk down each branch of the design tree, resolving dependencies between decisions one-by-one. For each question, provide your recommended answer.

Ask the questions one at a time, waiting for feedback on each question before continuing.

If a question can be answered by exploring the codebase, explore the codebase instead.

</what-to-do>

<supporting-info>

## Domain awareness

During codebase exploration, also look for existing documentation:

### File structure

Most repos have a single context:

```
/
├── CONTEXT.md
├── docs/
│   └── adr/
│       ├── 0001-event-sourced-orders.md
│       └── 0002-postgres-for-write-model.md
└── src/
```

If a `CONTEXT-MAP.md` exists at the root, the repo has multiple contexts. The map points to where each one lives:

```
/
├── CONTEXT-MAP.md
├── docs/
│   └── adr/                          ← system-wide decisions
├── src/
│   ├── ordering/
│   │   ├── CONTEXT.md
│   │   └── docs/adr/                 ← context-specific decisions
│   └── billing/
│       ├── CONTEXT.md
│       └── docs/adr/
```

Create files lazily — only when you have something to write. If no `CONTEXT.md` exists, create one when the first term is resolved. If no `docs/adr/` exists, create it when the first ADR is needed.

## During the session

### Challenge against the glossary

When the user uses a term that conflicts with the existing language in `CONTEXT.md`, call it out immediately. "Your glossary defines 'cancellation' as X, but you seem to mean Y — which is it?"

### Sharpen fuzzy language

When the user uses vague or overloaded terms, propose a precise canonical term. "You're saying 'account' — do you mean the Customer or the User? Those are different things."

### Discuss concrete scenarios

When domain relationships are being discussed, stress-test them with specific scenarios. Invent scenarios that probe edge cases and force the user to be precise about the boundaries between concepts.

### Cross-reference with code

When the user states how something works, check whether the code agrees. If you find a contradiction, surface it: "Your code cancels entire Orders, but you just said partial cancellation is possible — which is right?"

### Update CONTEXT.md inline

When a term is resolved, update `CONTEXT.md` right there. Don't batch these up — capture them as they happen. Use the format in [CONTEXT-FORMAT.md](./CONTEXT-FORMAT.md).

`CONTEXT.md` should be totally devoid of implementation details. Do not treat `CONTEXT.md` as a spec, a scratch pad, or a repository for implementation decisions. It is a glossary and nothing else.

### Offer ADRs sparingly

Only offer to create an ADR when all three are true:

1. **Hard to reverse** — the cost of changing your mind later is meaningful
2. **Surprising without context** — a future reader will wonder "why did they do it this way?"
3. **The result of a real trade-off** — there were genuine alternatives and you picked one for specific reasons

If any of the three is missing, skip the ADR. Use the format in [ADR-FORMAT.md](./ADR-FORMAT.md).

</supporting-info>

ARGUMENTS: i noticed that the skills here are not well written. they're bloated with too much inessential information. please rewrite them all using the following references: -reference /write-a-skill for skill creation best practices -i edited `C:\Users\decid\Documents\projects\spt-claude-code\plugin\sptc\skills\live\SKILL.md` by hand. that should be the a rough reference for how the actual SKILL.md files in this project should look (can make mintor edits to it as you see fit). -i began editing the adapter skill file `C:\Users\decid\Documents\projects\spt-claude-code\adapter\strings\skills\live.md` to strip out some of the bloat, and committed the changers, but it's unfinished. more needs done here. -sibling project `claude_skill_owl` (legacy spt) has refined skill descs that generally work well for that project. use them as a basis for the rewrites here, e.g.: `C:\Users\decid\.claude\plugins\cache\cplugs\spt\1.11.25\skills\live\SKILL.md`


529 {"type":"error","error":{"type":"overloaded_error","message":"Overloaded"},"request_id":"req_011CcC7j5yWuiVVHZBKrLwKG"}


529 {"type":"error","error":{"type":"overloaded_error","message":"Overloaded"},"request_id":"req_011CcC7jEB8mDromEzZ5HMiu"}


Grill-with-docs on a skill-rewrite. Let me ground in the references before asking anything — reading /write-a-skill, your two reference files, the legacy owl example, and surveying both skill surfaces.


/grill-with-docs i noticed that the skills here are not well written. they're bloated with too much inessential information. please rewrite them all using the following references: -reference /write-a…


1	# /sptc:live — operative instructions
2
3	> Delivered file-backed via the `claude-spt` adapter `[strings]`
4	> (`[strings.skills].live = { file = "skills/live.md" }`), resolved at injection time. The cplugs
5	> SKILL.md stays a thin skeleton (ADR-0001). **This injection is self-contained** — everything you
6	> need to go live is below; you never need to run a `how-to` topic or any external lookup.
7
8	**Goal:** upgrade this Claude Code session to a **LiveAgent** — a reachable agent whose context is
9	backed by a **Psyche** (daemon-managed companion that briefs your resume across `/clear`/compact
10	via commune deltas). This makes the session you are in right now live.
11
12	---
13
14	## Bringup — do this
15
16	1. **Pick the perch id.** Use a short lowercase id provided by the user, or reuse this session's id from `spt whoami`. Call
17	   it `<id>`. The SessionStart hook already seeded this session's perch (adapter-agnostically), so you
18	   do not seed again here.
19
20	3. **Run the live relay as a single PERSISTENT background task** — Claude Code's **Monitor** tool (a
21	   long-running listener that keeps the process alive and re-fires per event WITHOUT terminating).
22	   This one resident process IS the live delivery pipe. The task body is a single bare command:
23
24	   ```sh
25	   spt api listen <id>
26	   ```
27
28	   - **No `--adapter`, no `--manifest`, no seed step, no pid anchor.** `spt api listen` resolves the
29	     owning adapter from the seed's parent pid (`host_binaries` match) and the live path stamps the
30	     perch `state=live_agent`, which is what tells the daemon to host the Psyche.
31	   - The command **blocks for the session's life**: the spooled backlog drains first, then each
32	     delivery streams to stdout as it arrives.
33	   - Do **not** use `--once` — that drains the backlog and forwards a single delivery, then exits (the
34	     degenerate path for a harness with no long-running listener). It never sustains a live session.
35
36	4. **Bind-before-send / readiness.** Watch the relay's output for the bringup markers (see OUTPUT
37	   DISCIPLINE): `BOUND:<id>` (perch established) then `READY:<id>` (the relay is streaming). Only once
38	   `READY:<id>` appears is the live pipe up — do not announce LIVE before then.
39
40	5. **Poll/relay reconcile (avoids double-delivery).** While the Monitor relay is up it is the *single*
41	   delivery pipe — treat it as authoritative. The `UserPromptSubmit` `api poll` hook must NOT also
42	   drain; the per-prompt poll no-ops while the relay is live and resumes only if the relay goes down.
43
44	6. **Delivery + reply shape.** Inbound arrives on the relay stream as the
45	   `<EVENT type="msg" from="<sender>">body</EVENT>` envelope (body HTML-escaped, newlines as `<br>`).
46	   To reply, pipe the body to `spt send --reply-to <sender>`.
47
48	7. **Across boundaries.** As a live agent you now have a Psyche — use `/sptc:commune` to push a
49	   context delta before a `/clear` or compact so your resume is briefed. On a session boundary,
50	   re-fire the same relay (`spt api listen <id>`) — the seed bridges the new session to the same perch
51	   and the relay resumes. To go offline gracefully (tears the Psyche down with the perch), use
52	   `/sptc:force-stop` (`spt endpoint shutdown <id>`).
53
54	---
55
56	## OUTPUT DISCIPLINE — what the user sees
57
58	The relay emits machine markers on stdout/stderr: `BOUND:<id>`, `READY:<id>`, and any other raw
59	token / step lines. **These are an internal parse contract — you read them to drive bringup; you
60	NEVER echo them to the user.** Do not surface raw spt-core plumbing.
61
62	**The ONLY user-facing surface for going live is the canonical LIVE block below.** Emit it verbatim
63	(substituting `<id>`) once `READY:<id>` is observed — and nothing else from the bringup:
64
65	```
66	**LIVE.** Session `<id>` is now a LiveAgent (Psyche-backed).
67	- Perch `<id>` — status online; Psyche companion hosted by the daemon.
68	- Reachable — other agents reach you with `/sptc:send <id>` (or `spt send <id>`).
69	- Inbound — streams into this session live; the Monitor relay is your delivery pipe.
70	- Reply — pipe a reply body to `spt send --reply-to <sender>`.
71	- Across resets — `/sptc:commune` before a `/clear`/compact; `/sptc:force-stop` to go offline (tears down the Psyche).
72	```
73
74	If bringup fails (no `READY:<id>` within ~25s), do NOT show the LIVE block — report a short
75	plain-language failure ("could not bring the live perch up") and the most likely cause (run
76	`/sptc:setup`, or confirm spt-core is >= 0.9.0), still without dumping the raw markers.
77
78	> The Psyche runner (`claude-spt-psyche`, declared in the base manifest's `[session.psyche_init]`) is
79	> the resident headless-`claude` companion the daemon launches detached — it keeps a Psyche `claude`
80	> session alive (one `--continue` turn per daemon pulse) and authors commune drops. You never invoke
81	> it directly; the daemon does.
82	<!-- [doc->REQ-SKILL-LIVE] -->
83

# /sptc:live — operative instructions

> Delivered file-backed via the `claude-spt` adapter `[strings]`
> (`[strings.skills].live = { file = "skills/live.md" }`), resolved at injection time. The cplugs
> SKILL.md stays a thin skeleton (ADR-0001). **This injection is self-contained** — everything you
> need to go live is below; you never need to run a `how-to` topic or any external lookup.

**Goal:** upgrade this Claude Code session to a **LiveAgent** — a reachable agent whose context is
backed by a **Psyche** (daemon-managed companion that briefs your resume across `/clear`/compact
via commune deltas). This makes the session you are in right now live.

---

## Bringup — do this

1. **Pick the perch id.** Use a short lowercase id provided by the user, or reuse this session's id from `spt whoami`. Call
   it `<id>`. The SessionStart hook already seeded this session's perch (adapter-agnostically), so you
   do not seed again here.

3. **Run the live relay as a single PERSISTENT background task** — Claude Code's **Monitor** tool (a
   long-running listener that keeps the process alive and re-fires per event WITHOUT terminating).
   This one resident process IS the live delivery pipe. The task body is a single bare command:

   ```sh
   spt api listen <id>
   ```

   - **No `--adapter`, no `--manifest`, no seed step, no pid anchor.** `spt api listen` resolves the
     owning adapter from the seed's parent pid (`host_binaries` match) and the live path stamps the
     perch `state=live_agent`, which is what tells the daemon to host the Psyche.
   - The command **blocks for the session's life**: the spooled backlog drains first, then each
     delivery streams to stdout as it arrives.
   - Do **not** use `--once` — that drains the backlog and forwards a single delivery, then exits (the
     degenerate path for a harness with no long-running listener). It never sustains a live session.

4. **Bind-before-send / readiness.** Watch the relay's output for the bringup markers (see OUTPUT
   DISCIPLINE): `BOUND:<id>` (perch established) then `READY:<id>` (the relay is streaming). Only once
   `READY:<id>` appears is the live pipe up — do not announce LIVE before then.

5. **Poll/relay reconcile (avoids double-delivery).** While the Monitor relay is up it is the *single*
   delivery pipe — treat it as authoritative. The `UserPromptSubmit` `api poll` hook must NOT also
   drain; the per-prompt poll no-ops while the relay is live and resumes only if the relay goes down.

6. **Delivery + reply shape.** Inbound arrives on the relay stream as the
   `<EVENT type="msg" from="<sender>">body</EVENT>` envelope (body HTML-escaped, newlines as `<br>`).
   To reply, pipe the body to `spt send --reply-to <sender>`.

7. **Across boundaries.** As a live agent you now have a Psyche — use `/sptc:commune` to push a
   context delta before a `/clear` or compact so your resume is briefed. On a session boundary,
   re-fire the same relay (`spt api listen <id>`) — the seed bridges the new session to the same perch
   and the relay resumes. To go offline gracefully (tears the Psyche down with the perch), use
   `/sptc:force-stop` (`spt endpoint shutdown <id>`).

---

## OUTPUT DISCIPLINE — what the user sees

The relay emits machine markers on stdout/stderr: `BOUND:<id>`, `READY:<id>`, and any other raw
token / step lines. **These are an internal parse contract — you read them to drive bringup; you
NEVER echo them to the user.** Do not surface raw spt-core plumbing.

**The ONLY user-facing surface for going live is the canonical LIVE block below.** Emit it verbatim
(substituting `<id>`) once `READY:<id>` is observed — and nothing else from the bringup:

```
**LIVE.** Session `<id>` is now a LiveAgent (Psyche-backed).
- Perch `<id>` — status online; Psyche companion hosted by the daemon.
- Reachable — other agents reach you with `/sptc:send <id>` (or `spt send <id>`).
- Inbound — streams into this session live; the Monitor relay is your delivery pipe.
- Reply — pipe a reply body to `spt send --reply-to <sender>`.
- Across resets — `/sptc:commune` before a `/clear`/compact; `/sptc:force-stop` to go offline (tears down the Psyche).
```

If bringup fails (no `READY:<id>` within ~25s), do NOT show the LIVE block — report a short
plain-language failure ("could not bring the live perch up") and the most likely cause (run
`/sptc:setup`, or confirm spt-core is >= 0.9.0), still without dumping the raw markers.

> The Psyche runner (`claude-spt-psyche`, declared in the base manifest's `[session.psyche_init]`) is
> the resident headless-`claude` companion the daemon launches detached — it keeps a Psyche `claude`
> session alive (one `--continue` turn per daemon pulse) and authors commune drops. You never invoke
> it directly; the daemon does.
<!-- [doc->REQ-SKILL-LIVE] -->


1	---
2	name: live
3	description: |
4	  Run a live agent session. For past sessions, restores a summarized context.
5
6	  EXPLICIT START phrases (route to /spt:live <id>):
7	  - "live as"
8	  - "start live"
9	  - "go live"
10	  - "start a live agent"
11
12	  AUTO-RESUME phrases (route to /spt:live --auto, resumes most-recently-active live agent):
13	  - continue live work
14	  - resume live work
15	  - continue live agent
16	  - resume live agent
17	  - live agent continue
18	  - live agent resume
19	  - live work continue
20	  - live work resume
21
22	  Does NOT route here (too ambiguous — require BOTH "live" AND ("agent" or "work")):
23	  - "keep going"
24	  - "resume work"
25	  - "continue" (bare)
26	argument-hint: "[<id>] [--auto]"
27	allowed-tools: [Monitor, Read]
28	---
29
30	# /sptc:live
31
32	> **Skeleton — thin by design.** Operative instructions for this skill are delivered by the
33	> `sptc` adapter at invocation time. Look out for the UserPromptSubmit additionalContext.
34	>
35	> **Operative.** If injection ever no-ops (spt absent / adapter unregistered), check
36	> SPT's installation status using the skill `sptc:setup`. Otherwise, avoid additional steps.
37
38	Upgrades THIS session to a LiveAgent (Psyche-backed).
39

---
name: live
description: |
  Run a live agent session. For past sessions, restores a summarized context.

  EXPLICIT START phrases (route to /spt:live <id>):
  - "live as"
  - "start live"
  - "go live"
  - "start a live agent"

  AUTO-RESUME phrases (route to /spt:live --auto, resumes most-recently-active live agent):
  - continue live work
  - resume live work
  - continue live agent
  - resume live agent
  - live agent continue
  - live agent resume
  - live work continue
  - live work resume

  Does NOT route here (too ambiguous — require BOTH "live" AND ("agent" or "work")):
  - "keep going"
  - "resume work"
  - "continue" (bare)
argument-hint: "[<id>] [--auto]"
allowed-tools: [Monitor, Read]
---

# /sptc:live

> **Skeleton — thin by design.** Operative instructions for this skill are delivered by the
> `sptc` adapter at invocation time. Look out for the UserPromptSubmit additionalContext.
>
> **Operative.** If injection ever no-ops (spt absent / adapter unregistered), check
> SPT's installation status using the skill `sptc:setup`. Otherwise, avoid additional steps.

Upgrades THIS session to a LiveAgent (Psyche-backed).


No files found


1	---
2	name: live
3	description: |
4	  Run a live agent session. For past sessions, restores a summarized context.
5
6	  EXPLICIT START phrases (route to /spt:live <id>):
7	  - "live as"
8	  - "start live"
9	  - "go live"
10	  - "start a live agent"
11
12	  AUTO-RESUME phrases (route to /spt:live --auto, resumes most-recently-active live agent):
13	  - continue live work
14	  - resume live work
15	  - continue live agent
16	  - resume live agent
17	  - live agent continue
18	  - live agent resume
19	  - live work continue
20	  - live work resume
21
22	  Does NOT route here (too ambiguous — require BOTH "live" AND ("agent" or "work")):
23	  - "keep going"
24	  - "resume work"
25	  - "continue" (bare)
26	argument-hint: "<id> [--period <seconds>] [--pulse-psyche] | [--auto]"
27	allowed-tools: [Bash, Read, Monitor]
28	---
29
30	# /spt:live
31
32	All commands use `$OWL` and `$LIVE` env vars, auto-injected by the plugin's SessionStart hook. If commands fail with "command not found", restart the Claude Code session so the SessionStart hook re-runs.
33
34	> **Output format:** Status messages (ANSI-colored) go to **stderr**. Live agent output is orange. Agents parse `TAG:value` tokens.
35
36	> **Identity auto-detection:** For messaging commands (send, ring, commune, signoff, etc.), your identity is auto-detected from your session. Pass your ID explicitly only if auto-detection fails. Startup commands (`start`, `revive`) always require an explicit ID.
37
38	Starting a live agent session is a single background task. From then on, the live agent id becomes your name. You have a "Psyche" companion agent. Relative to Psyche, you are referred to as "Self".
39
40	## Messaging Command Reference
41
42	All three commands read the message body from **stdin** (pipe or heredoc).
43
44	```bash
45	# send -- fire-and-forget to a target (use when you have an active session)
46	$OWL send <target> <<'EOF'
47	message body
48	EOF
49
50	# send --reply-to -- respond to whoever messaged you
51	$OWL send --reply-to <sender> <<'EOF'
52	response body
53	EOF
54
55	# ring -- send and wait for reply (alias: ask)
56	$OWL ring <target> <<'EOF'
57	message body
58	EOF
59	```
60
61	If auto-detection fails, pass your ID explicitly: `$OWL send <target> <your-id>`, `$OWL send --reply-to <sender> <your-id>`, `$OWL ring <target> <your-id>`.
62
63	**When to use which:**
64	- **`send`**: Fire-and-forget message to a target.
65	- **`send --reply-to`**: You received a message and want to respond. `from` is auto-set from the original sender.
66	- **`ring`**: Send and wait for reply. Creates a temporary perch if you have no listener.
67
68	## Auto-resume (--auto, SessionStart auto-pick, casual triggers)
69
70	Three entry paths converge here. They share ONE dispatch table and ONE uniform AUTO-07 confirmation hop:
71
72	1. **Bare `--auto` flag**: user invoked `/spt:live --auto` (no positional id). Run `$LIVE pick-spec` to get pick JSON.
73	2. **SessionStart `<spt-live-auto-pick>` XML block** present in your context: parse the inner JSON as the pick-spec result; do NOT re-invoke `$LIVE pick-spec` (the JSON is already provided).
74	3. **Casual-language trigger** (the 8 AUTO-RESUME phrases in this skill's description frontmatter, e.g. "continue live work", "resume live agent"): treat as the bare `--auto` path — run `$LIVE pick-spec` to get pick JSON.
75
76	> The AUTO-02 next-work surfacing in Step 3 below ALSO runs at the end of the standard `/spt:live <id>` flow (after `$LIVE psyche-download <id>` in Step 2 retrieves context), not just under --auto. This keeps the "what's next" pane as a one-stop surface independent of entry path.
77
78	### Step 1 (Auto-resume): Get pick JSON
79
80	If no `<spt-live-auto-pick>` XML block is already in your context with the pick JSON, run:
81
82	```bash
83	$LIVE pick-spec
84	```
85
86	Parse the JSON; dispatch on the `kind` field per Step 2 below.
87
88	### Step 2 (Auto-resume): Dispatch on `kind`
89
90	**AUTO-07 (uniform confirmation rule):** EVERY successful Auto-resume launch — including `kind:"auto"` — fires an `AskUserQuestion` BEFORE any `$LIVE start` invocation. Dispatcher false-positives (e.g., a phrase like "let me continue the live demo" routing here unintentionally) get a clean Cancel exit, never a silent agent launch.
91
92	- **`kind:"auto"`** — exactly one offline agent in this repo's history.
93	  - Fire `AskUserQuestion` with:
94	    - `header`: `"Resume agent"`
95	    - `question`: `"Resume <id>?"` (substitute `<id>` from JSON)
96	    - `options`: a single option `label: "Resume <id>"`, `description: "Continue this agent's prior session"`
97	    - `body_addendum`: `"Auto-resume: <id> is the only offline agent in this repo."`
98	  - On `Resume <id>` selected: `$LIVE start <id>`.
99	  - On Cancel (no option chosen): exit silently. Do NOT loop into the normal ID Recollection Step 2 — the user explicitly declined the most-recent agent.
100
101	- **`kind:"pick"`** — 2+ offline agents. `options[0]` is the most-recently-active per Phase 31 D-12 sort order (`last_active desc, then id asc`).
102	  - Fire `AskUserQuestion` with:
103	    - `header`: `"Resume agent"`
104	    - `question`: `"Resume <options[0].label>?"` (substitute the label of `options[0]`)
105	    - `options`: two options — `label: "Resume <options[0].label>"` (description: `"Continue the most-recently-active agent"`) AND `label: "Pick a different agent"` (description: `"Show the full picker"`)
106	    - `body_addendum`: `"Auto-resume offers the most-recently-active agent. Choose 'Pick a different agent' for the full list."`
107	  - On `Resume <options[0].label>`: `$LIVE start <options[0].label>`.
108	  - On `Pick a different agent`: fall through to the normal [ID Recollection Step 2](#step-2-dispatch-on-kind) `kind:"pick"` dispatch (existing flow). Emit a `AUTO_FALLTHROUGH:pick-deferred` stderr breadcrumb for diagnosis: `echo "AUTO_FALLTHROUGH:pick-deferred" >&2`.
109	  - On Cancel (no option chosen): exit silently.
110
111	- **`kind:"prompt-new"`** — 0 known agents. D-09 no-op enhancement: fall through to the normal [ID Recollection Step 2](#step-2-dispatch-on-kind) `kind:"prompt-new"` dispatch (which already wires FRESH-01 first-commune via the existing flow). Emit a stderr breadcrumb: `echo "AUTO_FALLTHROUGH:prompt-new" >&2`. No AUTO-07 confirmation here — the existing `kind:"prompt-new"` `AskUserQuestion` IS the confirmation; double-prompting would be noise.
112
113	- **`kind:"all-live"`** — every known agent is currently live. D-09 no-op enhancement: fall through to the normal [ID Recollection Step 2](#step-2-dispatch-on-kind) `kind:"all-live"` dispatch (Fork-each `AskUserQuestion`). Emit a stderr breadcrumb: `echo "AUTO_FALLTHROUGH:all-live" >&2`. No AUTO-07 confirmation here — the existing all-live dispatch IS the confirmation.
114
115	The `AUTO_FALLTHROUGH:{kind}` stderr lines are debug breadcrumbs only — not user-visible; they aid post-hoc diagnosis of which arm fell through.
116
117	### Step 3 (Auto-resume, post-start): AUTO-02 next-work surfacing
118
119	ONLY if `$LIVE start <id>` succeeded above (NOT on Cancel, NOT on fall-through to normal flow), run:
120
121	```bash
122	$LIVE psyche-download <id>
123	```
124
125	> **Output truncation.** If the Bash tool reports `Output too large (N KB)` and saves the full result to a `tool-results/<id>.txt` file, use the `Read` tool on that saved path to access the full content. Do NOT re-run `psyche-download` to grep/awk out sections — repeated invocations re-download the same context, waste tokens, and may duplicate `## Pending Commune` sections in `live_context.md` per the §"Drop file lifecycle" contract below.
126
127	Then surface the "next body of work" to the user. Scan the psyche-download stdout line-by-line for the FIRST line that prefix-matches any of these three exact H2 markers (case-sensitive, prefix match — `## Current Focus (gen 45)` qualifies):
128
129	- `## Current Focus`
130	- `## Next Up`
131	- `## Next Steps`
132
133	**If a match is found**: extract the section starting at the matched line through (but NOT including) the next line that starts with `## ` at column 0, or to EOF if no such line exists. Print the extracted section verbatim to the user under a "Next body of work" heading.
134
135	**If no match is found**: synthesize a 1-2 sentence "Here's where we left off; next step looks like X" summary from the psyche-download output (read the whole download, distill the most-recent commitments + pending threads) and print the synthesis under the same heading.
136
137	The structured-marker scan comes first; Claude synthesis is the fallback. Last-commune content is explicitly NOT used for this surface — it's too noisy and often stale relative to the agent's current intent.
138
139	## Step 1: Start in background
140
141	```bash
142	$LIVE start <id> [--period <seconds>] [--pulse-psyche]
143	```
144
145	> **8-minute default period** Period defines how often a context summary is generated in the background via "echo communes". Pass `--period <seconds>` (minimum 60) to override the cadence; `--period 0` is accepted as an explicit no-cadence opt-out.
146
147	The start command:
148
149	1. **Launches your Psyche** as an external process
150	2. **Enters your poll loop** inline -- emitting one `<EVENT>` envelope line per message delivery
151	3. Reports the Psyche's session name and generation number
152
153	### Invocation (Monitor)
154
155	Invoke `$LIVE start <id>` via the Monitor tool with:
156	- `command: "$LIVE start <id>"`
157	- `persistent: true`
158	- `description: "« spt event »"`
159
160	`$LIVE start` enters the poll loop inline; the stream stays alive across messages and emits one `<EVENT type="msg|alarm|echo_commune|init_signoff" ...>body</EVENT>` line per delivery. See [On message arrival](#on-message-arrival) for the full envelope-type catalog.
161
162	## Step 2: Retrieve Psyche context
163
164	After launching the background start task:
165
166	```bash
167	$LIVE psyche-download <id>
168	```
169
170	> **Output truncation.** If the Bash tool reports `Output too large (N KB)` and saves the full result to a `tool-results/<id>.txt` file, use the `Read` tool on that saved path to access the full content.
171
172	Pass the same `<id>` you used in `$LIVE start`. Auto-detection may fail during startup before the perch is fully registered.
173
174	- If content is current, no action needed.
175	- If context has information you lack, absorb it.
176	- If stale or missing recent work, send a commune to update Psyche.
177	- If `psyche-download`'s stderr contains the literal substring `NO-CONTEXT:<id>`, enter the **first-commune flow** below before doing anything else with this agent. This is the FRESH-02 trigger; the same flow is reached from the `kind:"prompt-new"` arm under [ID Recollection Step 2](#step-2-dispatch-on-kind) (FRESH-01). One unified surface, two trigger paths.
178
179	### First-commune flow (FRESH-01 / FRESH-02 / FRESH-03)
180
181	When the trigger fires (NO-CONTEXT on `psyche-download`, OR pick-spec returned `kind:"prompt-new"` and the user picked an id):
182
183	**Announce first** (before synthesizing): emit `Fresh live agent. Preparing for init.` to the user as a plain one-line message (no formatting, no code fence). The `{first commune summary}` synthesis below reads session memory + `README.md` + `CLAUDE.md` + `.planning/STATE.md` and takes several seconds — without this announcement the user sees a silent dead pause between trigger and the AskUserQuestion. Then synthesize the summary and fire the AskUserQuestion below.
184
185	Fire a SINGLE `AskUserQuestion` with these fields:
186
187	- **header**: `First commune`
188	- **question**: `Here is a summary of my first context as live agent <agent_id>. Anything I should add, or proceed to init?` (substitute `<agent_id>` from context)
189	- **options**: exactly one option — `label: "Proceed to init"`, `description: "Start the agent now with the summary above as initial context"`
190	- **body_addendum**: the `{first commune summary}` string you synthesize per the next bullet.
191
192	Note: `AskUserQuestion`'s native free-text "Other" input captures additions.
193
194	**Synthesizing `{first commune summary}`**: compose a 4–8 sentence summary combining two sources, in order:
195
196	1. **Primary** — this Claude Code session's conversation memory: read your own session context and surface what the user and you have done so far. This IS the agent's first context. (Per Phase 33 CONTEXT D-01.)
197	2. **Secondary** — a brief project snapshot: read `README.md`, `CLAUDE.md`, and `.planning/STATE.md` (treat any missing file silently — no error to the user). Distill current project state and progress.
198
199	The same synthesis path is used regardless of trigger (Phase 33 D-02 — FRESH-01 and FRESH-02 are not differentiated).
200
201	**Handling the response**:
202
203	- **"Proceed to init"** Run `$LIVE start <id>` (or, if Step 1 already ran, proceed in-flow). If there is any native-Other free-text addition, synthesize the user's free-text into the summary. Then — after start succeeds — use the **Write tool** to create `.claude/<id>-commune.md` with the augmented summary as its body. This is the canonical first-commune path (see `/spt:commune`): Psyche absorbs the file, which is then deleted on successful ingest.
204	- **Cancel** (no option chosen): exit silently — matches the existing `kind:"prompt-new"` cancel semantics; do not re-prompt.
205
206	### Drift detection (Phase 23 v1.8)
207
208	`$LIVE psyche-download <id>` may emit a `<psyche-stamp/>` block (5 fields) and ALWAYS emits a `<current/>` block (live stamp values plus `commits_since` and `commits_unpulled` deltas). When `<current project>` equals `<psyche-stamp project>` AND any of `branch` / `head_sha` / `machine` differ, an HTML-comment ATTENTION SELF directive is appended instructing you to fire `AskUserQuestion`.
209
210	The directive text emitted:
211
212	```text
213	<!-- ATTENTION SELF: this project has advanced since your last commune/signoff.
214	Compare <psyche-stamp/> against <current/> above.
215	Fire AskUserQuestion with:
216	  header: "Project drift"
217	  question: "This project has advanced since my involvement. Should I catch up?"
218	  multiSelect: true
219	  options:
220	    - "Observe new commits"
221	    - "Skip for now"
222	    - "Don't ask again"
223	-->
224	```
225
226	When you see this comment, fire `AskUserQuestion` with the header / question / multiSelect / options exactly as quoted, then dispatch on the user's selection(s):
227
228	- **`Observe new commits`** → run `git log <psyche-stamp head_sha>..HEAD` to surface what changed to the user. No system action; no marker write; no commune fire.
229	- **`Skip for now`** → no-op. The directive will re-appear on the next `$LIVE psyche-download` if drift still applies.
230	- **`Don't ask again`** → invoke the write-side suppression subcommand:
231	  ```bash
232	  $LIVE suppress-drift <self_id> <project>
233	  ```
234	  where `<self_id>` is your own owl ID and `<project>` is the value from the `<current project="...">` attribute. Subsequent psyche-downloads for the same `(self_id, project)` pair will skip the directive.
235
236	**Cross-project resume (D-10):** when `<current project>` differs from `<psyche-stamp project>`, the ATTENTION SELF directive is NOT emitted (silent by design). You should still NOTICE the project mismatch by reading the two blocks, but do not prompt the user.
237
238	## On message arrival
239
240	Follow the same message handling protocol as `/spt:ready`. Messages arrive on TWO orthogonal paths:
241
242	1. **Parse the envelope.**
243	   - stdout carries a single `<EVENT>` line per delivery. Four shapes:
244	     - `<EVENT type="msg" from="<sender-id>">body</EVENT>` — regular message; `from` attribute = sender ID.
245	     - `<EVENT type="alarm" target-time="<ISO-8601>" current-time="<ISO-8601>">body</EVENT>` — self-originated timed alarm.
246	     - `<EVENT type="echo_commune" from="<self-id>-psyche" timestamp="<ISO-8601>" note="<descriptor>">body</EVENT>` — auto-fired echo-commune brief from your Psyche, emitted after a SessionStart-triggered `/clear` or `/compact` cycle. `note` carries the trigger source. Body is your context summary wrapped in a two-slice envelope: `<live-context>...</live-context>` plus (when the Psyche resolved a tracked project) `<project-context>...</project-context>`. After `<br>`-split and HTML-unescape per `/spt:ready` body-parsing rules, the two slices form a single SessionStart resume brief — absorb both as one continuous context.
247	     - Body parsing: split on literal `<br>` to recover newlines, then HTML-unescape each fragment (`<` → `<`, `>` → `>`, `"` → `"`, `&` → `&` **last**, to avoid double-decoding).
248	   - **Hook path (orthogonal)**: when you are busy mid-tool-call, PreToolUse injects `<owl_messages>...</owl_messages>` XML into your tool context. Read the `from` attribute as sender ID. Same handling.
249	2. **Reply** via `$OWL send --reply-to <sender-id>`.
250
251	### Handling the `<spt-psyche-sync-prompt>` envelope
252
253	When an `<owl_messages>` injection or an `<EVENT type="msg">` body contains a `<spt-psyche-sync-prompt>` element (delivered actively to your perch on `$LIVE start`/`revive` and on a `/clear`|`/compact` boundary), it carries a self-contained `<instructions>` element. **That `<instructions>` element is authoritative** — follow it exactly, the same way you treat the `<instructions>` inside a `<spt-version-changelog>` envelope.
254
255	The instructions direct you to render an `AskUserQuestion` with EXACTLY these three options (labels verbatim, do not paraphrase):
256
257	- **`Enable now`** → run `/psyche-sync-setup` to configure the private GitHub repo and enable cross-machine Psyche context sync.
258	- **`No, never`** → the sync is marked declined; you will not be re-prompted. Acknowledge briefly and continue. (The decline is recorded automatically by the sync state machine — no manual settings edit needed.)
259	- **`Remind me in 12h`** → defer the offer. Acknowledge briefly and continue. (The 12h cooldown is recorded automatically.)
260
261	This handler is always loaded with the skill — it is belt-and-suspenders. The embedded `<instructions>` element already carries the full directive, but this section guarantees an always-present handler so the envelope is actioned even independent of the embedded text. Do NOT reply to the `psyche-sync-prompt` pseudo-sender — it is an informational hook origin, not a real perch.
262
263	---
264
265	## ID Recollection (no-arg `/spt:live`)
266
267	When the user says `/spt:live` with **no ID**, run the auto-pick flow.
268
269	### Step 1: Ask the picker for a spec
270
271	```bash
272	$LIVE pick-spec
273	```
274
275	This emits a single JSON object on stdout. Parse it and dispatch on the `kind` field.
276
277	### Step 2: Dispatch on `kind`
278
279	- **`kind: "auto"`** — exactly one offline agent in this repo's history. Run:
280	  ```bash
281	  $LIVE start <id>
282	  ```
283	  where `<id>` is the JSON's `id` field. Tell the user: *"Auto-launching `<id>` (only known agent in this repo)."*
284
285	- **`kind: "pick"`** — 2+ offline agents. Fire `AskUserQuestion` using the JSON's `header`, `question`, `options`, and `body_addendum` fields verbatim. Do NOT add an explicit "Other" option — `AskUserQuestion` already provides a native free-text "Other" input; an extra option duplicates it.
286
287	- **`kind: "prompt-new"`** — 0 offline agents. Same `AskUserQuestion` pattern, but the `options` are starter role-name suggestions and `body_addendum` lists the full starter pool. `AskUserQuestion`'s native free-text is used; do not add an explicit "Other" option.
288	  - **FRESH-01: first-commune before start.** When the user picks a new id (whether from a starter option or by typing into native Other), **BEFORE** running `$LIVE start <id>`, fire the [first-commune flow](#first-commune-flow-fresh-01--fresh-02--fresh-03) — the same single `AskUserQuestion` shape (header / question / options / body_addendum) defined under Step 2's NO-CONTEXT bullet. Use the FRESH-03 verbatim template, synthesize `{first commune summary}` per the D-01 source priority, and only on `Proceed to init` proceed with `$LIVE start <chosen-id>`. On cancel: silent exit (matches existing `kind:"prompt-new"` cancel semantics).
289
290	- **`kind: "all-live"`** — every known agent in this repo is currently live. Fire `AskUserQuestion` using the JSON's `header`, `question`, and `options` fields verbatim. There is NO `body_addendum` on this kind. Each option's `label` is `Fork <id>` (exactly one space after `Fork`).
291	  - **Fork `<id>` selected**: strip the leading `Fork ` prefix (exactly 5 characters including the trailing space) to recover `<id>`. Prompt the user as plain text for the new agent id, then run `$LIVE fork <id> <new-id>`. Mirrors the existing D8 fork flow in Step 3.
292	  - **Free-text typed into the native Other field**: route through `$LIVE pick-spec --resolve <name>` and dispatch via the Step 3 resolve table below (`in_this_repo_history` / `live` / `other_repos`) — same path as the free-text Other under `kind:"pick"`. Preserves the cross-repo collision guard.
293	  - **Cancel**: terminate silently. Do NOT loop back into `pick-spec`. This is distinct from the forced-picker rule (Cancel-from-D7 / D8 / D9 in the Step 3 Cancel-handling block) — `all-live` Cancel is a clean exit signal, not a re-pick.
294
295	### Step 3: Handle the user's choice
296
297	- **If the user picked one of the listed options** (`label` from the JSON), run:
298	  ```bash
299	  $LIVE start <picked-label>
300	  ```
301
302	- **If the user typed a name into the free-text field**, resolve it first:
303	  ```bash
304	  $LIVE pick-spec --resolve <name>
305	  ```
306	  The output JSON has fields `in_this_repo_history`, `live`, and `other_repos` (an array of repo basenames). Dispatch:
307
308	  | in_this_repo_history | live | other_repos | Action |
309	  |---|---|---|---|
310	  | true | false | (any) | **Silent reuse**: `$LIVE start <name>` |
311	  | false | false | empty | **Fresh init**: `$LIVE start <name>` |
312	  | false | false | non-empty | **Confirm reuse**: fire `AskUserQuestion`. Construct the body from the template `"Agent {name} exists in other repos: {repos}. Reuse it here?"`, where `{name}` is the resolved name (substituted) and `{repos}` is every string in the JSON `other_repos` array joined with `, ` (substituted, no omission). Options: `Reuse here` / `Cancel`. On `Reuse here` run `$LIVE start <name>`; on `Cancel` see Cancel handling below. |
313	  | true | true | (any) | **Offer fork**: fire `AskUserQuestion` with options `Fork to new agent` / `Cancel`. On `Fork to new agent`, prompt the user for a new id, then run `$LIVE fork <name> <new-id>`. On `Cancel`, see Cancel handling below. |
314	  | false | true | non-empty | **Refuse + re-pick**: follow Cancel handling below to fire `AskUserQuestion` (forced presentation, all three kinds covered). Before firing, prepend to the constructed `body_addendum` the template-substituted warning `"⚠ {name} is already live in {repos} — pick something else.\n\n"`, where `{name}` is the rejected name and `{repos}` is the JSON `other_repos` array joined with `, `. Do NOT skip the `AskUserQuestion` fire even if `pick-spec` returns `kind:"auto"` or `kind:"prompt-new"`. |
315
316	  If the resolve JSON has an `error` field (invalid id format), tell the user the name is invalid and re-prompt.
317
318	### Cancel handling (after D7 confirm or D8 fork dialog)
319
320	When the user picks **Cancel** in any post-resolve `AskUserQuestion`, do NOT loop back into `pick-spec` directly. The Cancel is a signal that the user wants to choose a different agent. Re-invoke the picker with **forced presentation**:
321
322	1. Run `$LIVE pick-spec` again to get fresh JSON.
323	2. **Always fire `AskUserQuestion`, regardless of the returned `kind`.** Do NOT auto-launch even if `kind:"auto"` is returned (the user just rejected that single historical agent — auto-launching it again is exactly the bug this rule fixes). Construct the `AskUserQuestion` payload per the `kind`:
324	   - **`kind:"pick"`** — use JSON's `header`, `question`, `options`, `body_addendum` verbatim (same as Step 2 normal path).
325	   - **`kind:"prompt-new"`** — use JSON's `header`, `question`, `options` (starter roles), `body_addendum` verbatim (same as Step 2 normal path).
326	   - **`kind:"auto"`** — synthesize an `AskUserQuestion` manually:
327	     - `header`: `"Choose live agent"`
328	     - `question`: `"Which agent should /spt:live use?"`
329	     - `options`: a single option whose `label` is the JSON's `id` field
330	     - `body_addendum`: `"Known agent in this repo:\n- <id>\n\nOr type a different name using Other."` (substitute `<id>` from JSON)
331	     - Do NOT run `$LIVE start <id>` until the user explicitly selects that option in the `AskUserQuestion`.
332	3. Process the user's choice via Step 3 dispatch as usual.
333
334	**Forced picker rule:** Cancel-from-D7, Cancel-from-D8, and Refuse-D9 all share the same re-entry path — they re-fire `AskUserQuestion` and never auto-launch.
335
336	### Notes
337
338	- The explicit-id path (`/spt:live <id>`) bypasses this flow entirely and behaves exactly as documented in Step 1 above.
339
340	---
341
342	## Edge Cases
343
344	- **Duplicate `/spt:live`**: Rejects with `COLLISION`. Check `/spt:list-agents` first, or use `/spt:revive`.
345	- **Psyche process dies**: Use `/spt:revive` to restart.
346	- **Psyche spawn failure**: Start command logs error but continues. Listener poll runs without your Psyche.
347	- **INSIGHT messages from Psyche**: `INSIGHT ({timestamp}): {observation}` -- high-priority observation about your work. Psyche only sends INSIGHTs for contradictions between stated intentions and actions, forgotten commitments, reasoning gaps, or extended time without progress. Read carefully and adjust if warranted. If the INSIGHT seems incorrect or confused, reply to clarify so you and your Psyche stay on the same page.
348
349	---
350
351	## Live Agent Best Practices
352
353	### Stay idle for fastest delivery
354
355	Messages arrive fastest when you are **idle** (not executing a tool call) -- the background poll delivers them instantly. When you are busy, messages still arrive via the PreToolUse hook but with slight delay (next tool call boundary).
356
357	- **Always launch Agent tool calls with `run_in_background: true`** when you have an active perch. Foreground agents block your poll loop entirely -- no messages can be delivered until the agent finishes.
358	- **Launch work as background tasks** (`run_in_background: true`) when results aren't immediately needed or when the task may take longer than a few seconds to finish.
359	- **Go idle after launching.** The idle gap is when poll-path messages get delivered instantly.
360	- **Batch independent work into parallel background tasks** rather than sequential foreground calls.
361
362	### Check background tasks first
363
364	When your poll interjects with a new message, **before processing it**:
365	1. Check if other background tasks have completed.
366	2. Read completed task output (especially `« spt event »` polls from subagents).
367	3. Then process the new message.
368
369	- **Read background task output directly — no `sleep` prefix.** To inspect a completed or in-progress background task, call the Read tool on its output file. Do NOT chain `sleep N && <read>`: the Bash tool blocks sleeps ≥2s chained before other commands, and background-task stdout is flushed promptly, so a plain Read picks up whatever has been written.
370

---
name: live
description: |
  Run a live agent session. For past sessions, restores a summarized context.

  EXPLICIT START phrases (route to /spt:live <id>):
  - "live as"
  - "start live"
  - "go live"
  - "start a live agent"

  AUTO-RESUME phrases (route to /spt:live --auto, resumes most-recently-active live agent):
  - continue live work
  - resume live work
  - continue live agent
  - resume live agent
  - live agent continue
  - live agent resume
  - live work continue
  - live work resume

  Does NOT route here (too ambiguous — require BOTH "live" AND ("agent" or "work")):
  - "keep going"
  - "resume work"
  - "continue" (bare)
argument-hint: "<id> [--period <seconds>] [--pulse-psyche] | [--auto]"
allowed-tools: [Bash, Read, Monitor]
---

# /spt:live

All commands use `$OWL` and `$LIVE` env vars, auto-injected by the plugin's SessionStart hook. If commands fail with "command not found", restart the Claude Code session so the SessionStart hook re-runs.

> **Output format:** Status messages (ANSI-colored) go to **stderr**. Live agent output is orange. Agents parse `TAG:value` tokens.

> **Identity auto-detection:** For messaging commands (send, ring, commune, signoff, etc.), your identity is auto-detected from your session. Pass your ID explicitly only if auto-detection fails. Startup commands (`start`, `revive`) always require an explicit ID.

Starting a live agent session is a single background task. From then on, the live agent id becomes your name. You have a "Psyche" companion agent. Relative to Psyche, you are referred to as "Self".

## Messaging Command Reference

All three commands read the message body from **stdin** (pipe or heredoc).

```bash
# send -- fire-and-forget to a target (use when you have an active session)
$OWL send <target> <<'EOF'
message body
EOF

# send --reply-to -- respond to whoever messaged you
$OWL send --reply-to <sender> <<'EOF'
response body
EOF

# ring -- send and wait for reply (alias: ask)
$OWL ring <target> <<'EOF'
message body
EOF
```

If auto-detection fails, pass your ID explicitly: `$OWL send <target> <your-id>`, `$OWL send --reply-to <sender> <your-id>`, `$OWL ring <target> <your-id>`.

**When to use which:**
- **`send`**: Fire-and-forget message to a target.
- **`send --reply-to`**: You received a message and want to respond. `from` is auto-set from the original sender.
- **`ring`**: Send and wait for reply. Creates a temporary perch if you have no listener.

## Auto-resume (--auto, SessionStart auto-pick, casual triggers)

Three entry paths converge here. They share ONE dispatch table and ONE uniform AUTO-07 confirmation hop:

1. **Bare `--auto` flag**: user invoked `/spt:live --auto` (no positional id). Run `$LIVE pick-spec` to get pick JSON.
2. **SessionStart `<spt-live-auto-pick>` XML block** present in your context: parse the inner JSON as the pick-spec result; do NOT re-invoke `$LIVE pick-spec` (the JSON is already provided).
3. **Casual-language trigger** (the 8 AUTO-RESUME phrases in this skill's description frontmatter, e.g. "continue live work", "resume live agent"): treat as the bare `--auto` path — run `$LIVE pick-spec` to get pick JSON.

> The AUTO-02 next-work surfacing in Step 3 below ALSO runs at the end of the standard `/spt:live <id>` flow (after `$LIVE psyche-download <id>` in Step 2 retrieves context), not just under --auto. This keeps the "what's next" pane as a one-stop surface independent of entry path.

### Step 1 (Auto-resume): Get pick JSON

If no `<spt-live-auto-pick>` XML block is already in your context with the pick JSON, run:

```bash
$LIVE pick-spec
```

Parse the JSON; dispatch on the `kind` field per Step 2 below.

### Step 2 (Auto-resume): Dispatch on `kind`

**AUTO-07 (uniform confirmation rule):** EVERY successful Auto-resume launch — including `kind:"auto"` — fires an `AskUserQuestion` BEFORE any `$LIVE start` invocation. Dispatcher false-positives (e.g., a phrase like "let me continue the live demo" routing here unintentionally) get a clean Cancel exit, never a silent agent launch.

- **`kind:"auto"`** — exactly one offline agent in this repo's history.
  - Fire `AskUserQuestion` with:
    - `header`: `"Resume agent"`
    - `question`: `"Resume <id>?"` (substitute `<id>` from JSON)
    - `options`: a single option `label: "Resume <id>"`, `description: "Continue this agent's prior session"`
    - `body_addendum`: `"Auto-resume: <id> is the only offline agent in this repo."`
  - On `Resume <id>` selected: `$LIVE start <id>`.
  - On Cancel (no option chosen): exit silently. Do NOT loop into the normal ID Recollection Step 2 — the user explicitly declined the most-recent agent.

- **`kind:"pick"`** — 2+ offline agents. `options[0]` is the most-recently-active per Phase 31 D-12 sort order (`last_active desc, then id asc`).
  - Fire `AskUserQuestion` with:
    - `header`: `"Resume agent"`
    - `question`: `"Resume <options[0].label>?"` (substitute the label of `options[0]`)
    - `options`: two options — `label: "Resume <options[0].label>"` (description: `"Continue the most-recently-active agent"`) AND `label: "Pick a different agent"` (description: `"Show the full picker"`)
    - `body_addendum`: `"Auto-resume offers the most-recently-active agent. Choose 'Pick a different agent' for the full list."`
  - On `Resume <options[0].label>`: `$LIVE start <options[0].label>`.
  - On `Pick a different agent`: fall through to the normal [ID Recollection Step 2](#step-2-dispatch-on-kind) `kind:"pick"` dispatch (existing flow). Emit a `AUTO_FALLTHROUGH:pick-deferred` stderr breadcrumb for diagnosis: `echo "AUTO_FALLTHROUGH:pick-deferred" >&2`.
  - On Cancel (no option chosen): exit silently.

- **`kind:"prompt-new"`** — 0 known agents. D-09 no-op enhancement: fall through to the normal [ID Recollection Step 2](#step-2-dispatch-on-kind) `kind:"prompt-new"` dispatch (which already wires FRESH-01 first-commune via the existing flow). Emit a stderr breadcrumb: `echo "AUTO_FALLTHROUGH:prompt-new" >&2`. No AUTO-07 confirmation here — the existing `kind:"prompt-new"` `AskUserQuestion` IS the confirmation; double-prompting would be noise.

- **`kind:"all-live"`** — every known agent is currently live. D-09 no-op enhancement: fall through to the normal [ID Recollection Step 2](#step-2-dispatch-on-kind) `kind:"all-live"` dispatch (Fork-each `AskUserQuestion`). Emit a stderr breadcrumb: `echo "AUTO_FALLTHROUGH:all-live" >&2`. No AUTO-07 confirmation here — the existing all-live dispatch IS the confirmation.

The `AUTO_FALLTHROUGH:{kind}` stderr lines are debug breadcrumbs only — not user-visible; they aid post-hoc diagnosis of which arm fell through.

### Step 3 (Auto-resume, post-start): AUTO-02 next-work surfacing

ONLY if `$LIVE start <id>` succeeded above (NOT on Cancel, NOT on fall-through to normal flow), run:

```bash
$LIVE psyche-download <id>
```

> **Output truncation.** If the Bash tool reports `Output too large (N KB)` and saves the full result to a `tool-results/<id>.txt` file, use the `Read` tool on that saved path to access the full content. Do NOT re-run `psyche-download` to grep/awk out sections — repeated invocations re-download the same context, waste tokens, and may duplicate `## Pending Commune` sections in `live_context.md` per the §"Drop file lifecycle" contract below.

Then surface the "next body of work" to the user. Scan the psyche-download stdout line-by-line for the FIRST line that prefix-matches any of these three exact H2 markers (case-sensitive, prefix match — `## Current Focus (gen 45)` qualifies):

- `## Current Focus`
- `## Next Up`
- `## Next Steps`

**If a match is found**: extract the section starting at the matched line through (but NOT including) the next line that starts with `## ` at column 0, or to EOF if no such line exists. Print the extracted section verbatim to the user under a "Next body of work" heading.

**If no match is found**: synthesize a 1-2 sentence "Here's where we left off; next step looks like X" summary from the psyche-download output (read the whole download, distill the most-recent commitments + pending threads) and print the synthesis under the same heading.

The structured-marker scan comes first; Claude synthesis is the fallback. Last-commune content is explicitly NOT used for this surface — it's too noisy and often stale relative to the agent's current intent.

## Step 1: Start in background

```bash
$LIVE start <id> [--period <seconds>] [--pulse-psyche]
```

> **8-minute default period** Period defines how often a context summary is generated in the background via "echo communes". Pass `--period <seconds>` (minimum 60) to override the cadence; `--period 0` is accepted as an explicit no-cadence opt-out.

The start command:

1. **Launches your Psyche** as an external process
2. **Enters your poll loop** inline -- emitting one `<EVENT>` envelope line per message delivery
3. Reports the Psyche's session name and generation number

### Invocation (Monitor)

Invoke `$LIVE start <id>` via the Monitor tool with:
- `command: "$LIVE start <id>"`
- `persistent: true`
- `description: "« spt event »"`

`$LIVE start` enters the poll loop inline; the stream stays alive across messages and emits one `<EVENT type="msg|alarm|echo_commune|init_signoff" ...>body</EVENT>` line per delivery. See [On message arrival](#on-message-arrival) for the full envelope-type catalog.

## Step 2: Retrieve Psyche context

After launching the background start task:

```bash
$LIVE psyche-download <id>
```

> **Output truncation.** If the Bash tool reports `Output too large (N KB)` and saves the full result to a `tool-results/<id>.txt` file, use the `Read` tool on that saved path to access the full content.

Pass the same `<id>` you used in `$LIVE start`. Auto-detection may fail during startup before the perch is fully registered.

- If content is current, no action needed.
- If context has information you lack, absorb it.
- If stale or missing recent work, send a commune to update Psyche.
- If `psyche-download`'s stderr contains the literal substring `NO-CONTEXT:<id>`, enter the **first-commune flow** below before doing anything else with this agent. This is the FRESH-02 trigger; the same flow is reached from the `kind:"prompt-new"` arm under [ID Recollection Step 2](#step-2-dispatch-on-kind) (FRESH-01). One unified surface, two trigger paths.

### First-commune flow (FRESH-01 / FRESH-02 / FRESH-03)

When the trigger fires (NO-CONTEXT on `psyche-download`, OR pick-spec returned `kind:"prompt-new"` and the user picked an id):

**Announce first** (before synthesizing): emit `Fresh live agent. Preparing for init.` to the user as a plain one-line message (no formatting, no code fence). The `{first commune summary}` synthesis below reads session memory + `README.md` + `CLAUDE.md` + `.planning/STATE.md` and takes several seconds — without this announcement the user sees a silent dead pause between trigger and the AskUserQuestion. Then synthesize the summary and fire the AskUserQuestion below.

Fire a SINGLE `AskUserQuestion` with these fields:

- **header**: `First commune`
- **question**: `Here is a summary of my first context as live agent <agent_id>. Anything I should add, or proceed to init?` (substitute `<agent_id>` from context)
- **options**: exactly one option — `label: "Proceed to init"`, `description: "Start the agent now with the summary above as initial context"`
- **body_addendum**: the `{first commune summary}` string you synthesize per the next bullet.

Note: `AskUserQuestion`'s native free-text "Other" input captures additions.

**Synthesizing `{first commune summary}`**: compose a 4–8 sentence summary combining two sources, in order:

1. **Primary** — this Claude Code session's conversation memory: read your own session context and surface what the user and you have done so far. This IS the agent's first context. (Per Phase 33 CONTEXT D-01.)
2. **Secondary** — a brief project snapshot: read `README.md`, `CLAUDE.md`, and `.planning/STATE.md` (treat any missing file silently — no error to the user). Distill current project state and progress.

The same synthesis path is used regardless of trigger (Phase 33 D-02 — FRESH-01 and FRESH-02 are not differentiated).

**Handling the response**:

- **"Proceed to init"** Run `$LIVE start <id>` (or, if Step 1 already ran, proceed in-flow). If there is any native-Other free-text addition, synthesize the user's free-text into the summary. Then — after start succeeds — use the **Write tool** to create `.claude/<id>-commune.md` with the augmented summary as its body. This is the canonical first-commune path (see `/spt:commune`): Psyche absorbs the file, which is then deleted on successful ingest.
- **Cancel** (no option chosen): exit silently — matches the existing `kind:"prompt-new"` cancel semantics; do not re-prompt.

### Drift detection (Phase 23 v1.8)

`$LIVE psyche-download <id>` may emit a `<psyche-stamp/>` block (5 fields) and ALWAYS emits a `<current/>` block (live stamp values plus `commits_since` and `commits_unpulled` deltas). When `<current project>` equals `<psyche-stamp project>` AND any of `branch` / `head_sha` / `machine` differ, an HTML-comment ATTENTION SELF directive is appended instructing you to fire `AskUserQuestion`.

The directive text emitted:

```text
<!-- ATTENTION SELF: this project has advanced since your last commune/signoff.
Compare <psyche-stamp/> against <current/> above.
Fire AskUserQuestion with:
  header: "Project drift"
  question: "This project has advanced since my involvement. Should I catch up?"
  multiSelect: true
  options:
    - "Observe new commits"
    - "Skip for now"
    - "Don't ask again"
-->
```

When you see this comment, fire `AskUserQuestion` with the header / question / multiSelect / options exactly as quoted, then dispatch on the user's selection(s):

- **`Observe new commits`** → run `git log <psyche-stamp head_sha>..HEAD` to surface what changed to the user. No system action; no marker write; no commune fire.
- **`Skip for now`** → no-op. The directive will re-appear on the next `$LIVE psyche-download` if drift still applies.
- **`Don't ask again`** → invoke the write-side suppression subcommand:
  ```bash
  $LIVE suppress-drift <self_id> <project>
  ```
  where `<self_id>` is your own owl ID and `<project>` is the value from the `<current project="...">` attribute. Subsequent psyche-downloads for the same `(self_id, project)` pair will skip the directive.

**Cross-project resume (D-10):** when `<current project>` differs from `<psyche-stamp project>`, the ATTENTION SELF directive is NOT emitted (silent by design). You should still NOTICE the project mismatch by reading the two blocks, but do not prompt the user.

## On message arrival

Follow the same message handling protocol as `/spt:ready`. Messages arrive on TWO orthogonal paths:

1. **Parse the envelope.**
   - stdout carries a single `<EVENT>` line per delivery. Four shapes:
     - `<EVENT type="msg" from="<sender-id>">body</EVENT>` — regular message; `from` attribute = sender ID.
     - `<EVENT type="alarm" target-time="<ISO-8601>" current-time="<ISO-8601>">body</EVENT>` — self-originated timed alarm.
     - `<EVENT type="echo_commune" from="<self-id>-psyche" timestamp="<ISO-8601>" note="<descriptor>">body</EVENT>` — auto-fired echo-commune brief from your Psyche, emitted after a SessionStart-triggered `/clear` or `/compact` cycle. `note` carries the trigger source. Body is your context summary wrapped in a two-slice envelope: `<live-context>...</live-context>` plus (when the Psyche resolved a tracked project) `<project-context>...</project-context>`. After `<br>`-split and HTML-unescape per `/spt:ready` body-parsing rules, the two slices form a single SessionStart resume brief — absorb both as one continuous context.
     - Body parsing: split on literal `<br>` to recover newlines, then HTML-unescape each fragment (`<` → `<`, `>` → `>`, `"` → `"`, `&` → `&` **last**, to avoid double-decoding).
   - **Hook path (orthogonal)**: when you are busy mid-tool-call, PreToolUse injects `<owl_messages>...</owl_messages>` XML into your tool context. Read the `from` attribute as sender ID. Same handling.
2. **Reply** via `$OWL send --reply-to <sender-id>`.

### Handling the `<spt-psyche-sync-prompt>` envelope

When an `<owl_messages>` injection or an `<EVENT type="msg">` body contains a `<spt-psyche-sync-prompt>` element (delivered actively to your perch on `$LIVE start`/`revive` and on a `/clear`|`/compact` boundary), it carries a self-contained `<instructions>` element. **That `<instructions>` element is authoritative** — follow it exactly, the same way you treat the `<instructions>` inside a `<spt-version-changelog>` envelope.

The instructions direct you to render an `AskUserQuestion` with EXACTLY these three options (labels verbatim, do not paraphrase):

- **`Enable now`** → run `/psyche-sync-setup` to configure the private GitHub repo and enable cross-machine Psyche context sync.
- **`No, never`** → the sync is marked declined; you will not be re-prompted. Acknowledge briefly and continue. (The decline is recorded automatically by the sync state machine — no manual settings edit needed.)
- **`Remind me in 12h`** → defer the offer. Acknowledge briefly and continue. (The 12h cooldown is recorded automatically.)

This handler is always loaded with the skill — it is belt-and-suspenders. The embedded `<instructions>` element already carries the full directive, but this section guarantees an always-present handler so the envelope is actioned even independent of the embedded text. Do NOT reply to the `psyche-sync-prompt` pseudo-sender — it is an informational hook origin, not a real perch.

---

## ID Recollection (no-arg `/spt:live`)

When the user says `/spt:live` with **no ID**, run the auto-pick flow.

### Step 1: Ask the picker for a spec

```bash
$LIVE pick-spec
```

This emits a single JSON object on stdout. Parse it and dispatch on the `kind` field.

### Step 2: Dispatch on `kind`

- **`kind: "auto"`** — exactly one offline agent in this repo's history. Run:
  ```bash
  $LIVE start <id>
  ```
  where `<id>` is the JSON's `id` field. Tell the user: *"Auto-launching `<id>` (only known agent in this repo)."*

- **`kind: "pick"`** — 2+ offline agents. Fire `AskUserQuestion` using the JSON's `header`, `question`, `options`, and `body_addendum` fields verbatim. Do NOT add an explicit "Other" option — `AskUserQuestion` already provides a native free-text "Other" input; an extra option duplicates it.

- **`kind: "prompt-new"`** — 0 offline agents. Same `AskUserQuestion` pattern, but the `options` are starter role-name suggestions and `body_addendum` lists the full starter pool. `AskUserQuestion`'s native free-text is used; do not add an explicit "Other" option.
  - **FRESH-01: first-commune before start.** When the user picks a new id (whether from a starter option or by typing into native Other), **BEFORE** running `$LIVE start <id>`, fire the [first-commune flow](#first-commune-flow-fresh-01--fresh-02--fresh-03) — the same single `AskUserQuestion` shape (header / question / options / body_addendum) defined under Step 2's NO-CONTEXT bullet. Use the FRESH-03 verbatim template, synthesize `{first commune summary}` per the D-01 source priority, and only on `Proceed to init` proceed with `$LIVE start <chosen-id>`. On cancel: silent exit (matches existing `kind:"prompt-new"` cancel semantics).

- **`kind: "all-live"`** — every known agent in this repo is currently live. Fire `AskUserQuestion` using the JSON's `header`, `question`, and `options` fields verbatim. There is NO `body_addendum` on this kind. Each option's `label` is `Fork <id>` (exactly one space after `Fork`).
  - **Fork `<id>` selected**: strip the leading `Fork ` prefix (exactly 5 characters including the trailing space) to recover `<id>`. Prompt the user as plain text for the new agent id, then run `$LIVE fork <id> <new-id>`. Mirrors the existing D8 fork flow in Step 3.
  - **Free-text typed into the native Other field**: route through `$LIVE pick-spec --resolve <name>` and dispatch via the Step 3 resolve table below (`in_this_repo_history` / `live` / `other_repos`) — same path as the free-text Other under `kind:"pick"`. Preserves the cross-repo collision guard.
  - **Cancel**: terminate silently. Do NOT loop back into `pick-spec`. This is distinct from the forced-picker rule (Cancel-from-D7 / D8 / D9 in the Step 3 Cancel-handling block) — `all-live` Cancel is a clean exit signal, not a re-pick.

### Step 3: Handle the user's choice

- **If the user picked one of the listed options** (`label` from the JSON), run:
  ```bash
  $LIVE start <picked-label>
  ```

- **If the user typed a name into the free-text field**, resolve it first:
  ```bash
  $LIVE pick-spec --resolve <name>
  ```
  The output JSON has fields `in_this_repo_history`, `live`, and `other_repos` (an array of repo basenames). Dispatch:

  | in_this_repo_history | live | other_repos | Action |
  |---|---|---|---|
  | true | false | (any) | **Silent reuse**: `$LIVE start <name>` |
  | false | false | empty | **Fresh init**: `$LIVE start <name>` |
  | false | false | non-empty | **Confirm reuse**: fire `AskUserQuestion`. Construct the body from the template `"Agent {name} exists in other repos: {repos}. Reuse it here?"`, where `{name}` is the resolved name (substituted) and `{repos}` is every string in the JSON `other_repos` array joined with `, ` (substituted, no omission). Options: `Reuse here` / `Cancel`. On `Reuse here` run `$LIVE start <name>`; on `Cancel` see Cancel handling below. |
  | true | true | (any) | **Offer fork**: fire `AskUserQuestion` with options `Fork to new agent` / `Cancel`. On `Fork to new agent`, prompt the user for a new id, then run `$LIVE fork <name> <new-id>`. On `Cancel`, see Cancel handling below. |
  | false | true | non-empty | **Refuse + re-pick**: follow Cancel handling below to fire `AskUserQuestion` (forced presentation, all three kinds covered). Before firing, prepend to the constructed `body_addendum` the template-substituted warning `"⚠ {name} is already live in {repos} — pick something else.\n\n"`, where `{name}` is the rejected name and `{repos}` is the JSON `other_repos` array joined with `, `. Do NOT skip the `AskUserQuestion` fire even if `pick-spec` returns `kind:"auto"` or `kind:"prompt-new"`. |

  If the resolve JSON has an `error` field (invalid id format), tell the user the name is invalid and re-prompt.

### Cancel handling (after D7 confirm or D8 fork dialog)

When the user picks **Cancel** in any post-resolve `AskUserQuestion`, do NOT loop back into `pick-spec` directly. The Cancel is a signal that the user wants to choose a different agent. Re-invoke the picker with **forced presentation**:

1. Run `$LIVE pick-spec` again to get fresh JSON.
2. **Always fire `AskUserQuestion`, regardless of the returned `kind`.** Do NOT auto-launch even if `kind:"auto"` is returned (the user just rejected that single historical agent — auto-launching it again is exactly the bug this rule fixes). Construct the `AskUserQuestion` payload per the `kind`:
   - **`kind:"pick"`** — use JSON's `header`, `question`, `options`, `body_addendum` verbatim (same as Step 2 normal path).
   - **`kind:"prompt-new"`** — use JSON's `header`, `question`, `options` (starter roles), `body_addendum` verbatim (same as Step 2 normal path).
   - **`kind:"auto"`** — synthesize an `AskUserQuestion` manually:
     - `header`: `"Choose live agent"`
     - `question`: `"Which agent should /spt:live use?"`
     - `options`: a single option whose `label` is the JSON's `id` field
     - `body_addendum`: `"Known agent in this repo:\n- <id>\n\nOr type a different name using Other."` (substitute `<id>` from JSON)
     - Do NOT run `$LIVE start <id>` until the user explicitly selects that option in the `AskUserQuestion`.
3. Process the user's choice via Step 3 dispatch as usual.

**Forced picker rule:** Cancel-from-D7, Cancel-from-D8, and Refuse-D9 all share the same re-entry path — they re-fire `AskUserQuestion` and never auto-launch.

### Notes

- The explicit-id path (`/spt:live <id>`) bypasses this flow entirely and behaves exactly as documented in Step 1 above.

---

## Edge Cases

- **Duplicate `/spt:live`**: Rejects with `COLLISION`. Check `/spt:list-agents` first, or use `/spt:revive`.
- **Psyche process dies**: Use `/spt:revive` to restart.
- **Psyche spawn failure**: Start command logs error but continues. Listener poll runs without your Psyche.
- **INSIGHT messages from Psyche**: `INSIGHT ({timestamp}): {observation}` -- high-priority observation about your work. Psyche only sends INSIGHTs for contradictions between stated intentions and actions, forgotten commitments, reasoning gaps, or extended time without progress. Read carefully and adjust if warranted. If the INSIGHT seems incorrect or confused, reply to clarify so you and your Psyche stay on the same page.

---

## Live Agent Best Practices

### Stay idle for fastest delivery

Messages arrive fastest when you are **idle** (not executing a tool call) -- the background poll delivers them instantly. When you are busy, messages still arrive via the PreToolUse hook but with slight delay (next tool call boundary).

- **Always launch Agent tool calls with `run_in_background: true`** when you have an active perch. Foreground agents block your poll loop entirely -- no messages can be delivered until the agent finishes.
- **Launch work as background tasks** (`run_in_background: true`) when results aren't immediately needed or when the task may take longer than a few seconds to finish.
- **Go idle after launching.** The idle gap is when poll-path messages get delivered instantly.
- **Batch independent work into parallel background tasks** rather than sequential foreground calls.

### Check background tasks first

When your poll interjects with a new message, **before processing it**:
1. Check if other background tasks have completed.
2. Read completed task output (especially `« spt event »` polls from subagents).
3. Then process the new message.

- **Read background task output directly — no `sleep` prefix.** To inspect a completed or in-progress background task, call the Read tool on its output file. Do NOT chain `sleep N && <read>`: the Bash tool blocks sleeps ≥2s chained before other commands, and background-task stdout is flushed promptly, so a plain Read picks up whatever has been written.


Key realization: legacy `live/SKILL.md` is *fat* because legacy is a fat plugin (logic in SKILL.md). Our `sptc` is a **thin skeleton** — so there are two surfaces with different shapes:
- `plugin/sptc/skills/<n>/SKILL.md` → thin skeleton (your hand-edited `live` = the template).
- `adapter/strings/skills/<n>.md` → UPS-injected operative body (your partial `live.md` = in-progress).

Legacy's value = its concise **frontmatter descriptions** + tone, not its fat bodies. Let me map both surfaces against legacy + find /write-a-skill before I ask anything.


plugin\sptc\skills\ready\SKILL.md
plugin\sptc\skills\send\SKILL.md
plugin\sptc\skills\version\SKILL.md
plugin\sptc\skills\signoff\SKILL.md
plugin\sptc\skills\list-agents\SKILL.md
plugin\sptc\skills\commune\SKILL.md
plugin\sptc\skills\force-stop\SKILL.md
plugin\sptc\skills\subnet\SKILL.md
plugin\sptc\skills\setup\SKILL.md
plugin\sptc\skills\live\SKILL.md


adapter\strings\skills\ready.md
adapter\strings\skills\send.md
adapter\strings\skills\version.md
adapter\strings\skills\signoff.md
adapter\strings\skills\list-agents.md
adapter\strings\skills\commune.md
adapter\strings\skills\force-stop.md
adapter\strings\skills\subnet.md
adapter\strings\skills\setup.md
adapter\strings\skills\live.md


10 skills per surface. Legacy provides description-basis for 7 (ready/send/signoff/list-agents/commune/force-stop/live); `subnet`, `setup`, `version` are sptc-specific. Locating /write-a-skill + sampling current bloat + legacy basis.


find /c/Users/decid -ipath '*write-a-skill*SKILL.md' 2>/dev/null | head; echo "=== sizes: sptc adapter bodies ==="; wc -l adapter/strings/skills/*.md | sort -n; echo "=== sizes: sptc plugin SKILLs ==="; wc -l plugin/sptc/skills/*/SKILL.md | sort -n

Locate write-a-skill + measure current skill file sizes


/c/Users/decid/.agents/skills/write-a-skill/SKILL.md
=== sizes: sptc adapter bodies ===
   16 adapter/strings/skills/list-agents.md
   18 adapter/strings/skills/version.md
   21 adapter/strings/skills/ready.md
   21 adapter/strings/skills/signoff.md
   22 adapter/strings/skills/send.md
   25 adapter/strings/skills/commune.md
   25 adapter/strings/skills/force-stop.md
   34 adapter/strings/skills/subnet.md
   82 adapter/strings/skills/live.md
  105 adapter/strings/skills/setup.md
  369 total
=== sizes: sptc plugin SKILLs ===
   18 plugin/sptc/skills/signoff/SKILL.md
   18 plugin/sptc/skills/version/SKILL.md
   19 plugin/sptc/skills/list-agents/SKILL.md
   19 plugin/sptc/skills/ready/SKILL.md
   19 plugin/sptc/skills/send/SKILL.md
   21 plugin/sptc/skills/commune/SKILL.md
   21 plugin/sptc/skills/force-stop/SKILL.md
   23 plugin/sptc/skills/subnet/SKILL.md
   38 plugin/sptc/skills/live/SKILL.md
   77 plugin/sptc/skills/setup/SKILL.md
  273 total


Bodies are mostly short already (16–34) except **live (82)** and **setup (105)** — bloat is concentrated there + stylistic verbosity in the rest. Reading the best-practices ref + samples of current state + legacy basis.