# Disposable perch id — NEVER a live agent's id (REQ-HAZARD-PERCH-COLLISION). Override BOTH identity
# env vars; pin OWL_SESSION_ID for the auth-gated seed/send/listen surfaces. PER-RUN UNIQUE ($$ suffix):
# the daemon hosts a Psyche at most ONCE per session_id, so a FIXED id/session would not re-host on a
# rerun (the first run's hosted-session memory suppresses it) — each CI run must be a fresh session.
RUN=$$
ID=sptc-ci-liverelay-$RUN
SID=sptc-ci-liverelay-$RUN-sess
export SPTC_CI_ID="$ID" SPT_AGENT_ID="$ID" OWL_SESSION_ID="$ID"

#!/bin/sh
# Integration proof for /sptc:live's LiveAgent bringup against a REAL spt-core (>= v0.7.3): the
# `claude-spt:live` profile's [session.psyche_init] makes spt spawn the Psyche, and the resident
# relay (`spt api listen <id>`, the production delivery pipe — run inside CC's Monitor tool, heir to
# legacy `$LIVE start <id>`) binds the live perch and streams inbound as the canonical <EVENT>
# envelope. We play Monitor's role: spawn `api listen` as a CHILD PROCESS (persistent, NOT --once —
# --once is the degenerate no-Monitor path) with `--manifest` (the manifest loads ONLY via --manifest;
# `--adapter <name>` is just a name → without it LiveHost is None and no Psyche spawns), capture its
# stdout/stderr, send a probe, and assert the bringup markers. The LLM is never judged. [int->REQ-SKILL-LIVE]
#
# Covers BOTH legs of REQ-SKILL-LIVE int: (1) PSYCHE-SPAWN — version-dependent marker (M11 restructure,
# doyle 2026-06-16): on <0.8.0 `api listen` spawns the Psyche IN-PROCESS (`PSYCHE_SPAWNED:{id}-psyche`
# off the listen child, startup.rs spawn_psyche pre once/loop split); on >=0.8.0 the DAEMON livehost
# hosts it by spawning claude-spt-psyche (resolved by bare name from the adapter install dir) — assert
# the RESIDENT runner process + nested `{id}-psyche` perch dir (FINALIZED on v0.8.1 + the adapter
# greedy-prompt fix, 2026-06-16; see the >=0.8.0 leg below). (2) RELAY — the resident listen pipe delivers the probe (BOUND/READY/<EVENT> off the child,
# unchanged across versions). The per-pulse runner command construction is additionally covered by
# claude-spt-psyche unit tests (ci/psyche/build.sh).
#
# PSYCHE-SPAWN binary resolution: the psyche_init command invokes `claude-spt-psyche` by bare name.
# On v0.8.0+ (Feature B / REQ-INSTALL-11) spt resolves it FROM the adapter install dir (proven: the
# binary registration-copies into adapters/_github/<safe>/, no PATH interim needed). On 0.7.3 it must
# be on PATH (the F-006 interim copy). The >=0.8.0 leg now ASSERTS a resident runner (was skip-with-note
# pre-v0.8.1); the <0.8.0 leg still SKIPs when the runner is unresolvable. The relay leg asserts always.
#
# Spawns a real claude-spt-psyche (which launches a headless claude) + mutates node-local perch state,
# all torn down on exit. Gated behind SPTC_ACCEPTANCE=1. Idempotent.
# Run: SPTC_ACCEPTANCE=1 sh ci/psyche/live-relay-int.sh   (exit 0 = pass).
set -u
ROOT=$(CDPATH= cd "$(dirname "$0")/../.." && pwd)
A=claude-spt:live
MAN="$ROOT/adapter/claude-spt.toml"
# Disposable perch id — NEVER a live agent's id (REQ-HAZARD-PERCH-COLLISION). Override BOTH identity
# env vars; pin OWL_SESSION_ID for the auth-gated seed/send/listen surfaces.
ID=sptc-ci-liverelay
SID=sptc-ci-liverelay-sess
export SPTC_CI_ID="$ID" SPT_AGENT_ID="$ID" OWL_SESSION_ID="$ID"

if [ "${SPTC_ACCEPTANCE:-0}" != "1" ]; then echo "SKIP: set SPTC_ACCEPTANCE=1 to run (spawns a Psyche + mutates perch state)"; exit 0; fi
command -v spt >/dev/null 2>&1 || { echo "SKIP: no spt on PATH"; exit 0; }
ver=$(spt --version 2>/dev/null | awk '{print $NF}')
case "$ver" in
  0.7.2|0.7.1|0.7.0|0.6.*|0.5.*|0.4.*|0.3.*|0.2.*|0.1.*|0.0.*) echo "SKIP: spt $ver < 0.7.3 (daemon live path / counter-15)"; exit 0 ;;
esac
[ -f "$MAN" ] || { echo "SKIP: no manifest at $MAN"; exit 0; }

# Anchor pid: spt probes WINDOWS pids — from git-bash `$$` is the MSYS pid and reads as a dead anchor
# (STALE_SEED/NO_SEED). Use the WINPID column from `ps` when present (git-bash col 4); elsewhere `$$`
# is already the real pid spt probes.
ANCHOR=$(ps -p $$ 2>/dev/null | awk 'NR==2{print $4}'); case "$ANCHOR" in ''|*[!0-9]*) ANCHOR=$$;; esac

# Can the psyche runner be resolved on THIS host? (PATH now, or manifest-dir on v0.8.0+ Feature B.)
psyche_resolvable() {
  command -v claude-spt-psyche >/dev/null 2>&1 && return 0
  case "$ver" in 0.7.*) return 1 ;; *) return 0 ;; esac  # Feature B (manifest-dir resolution) lands in v0.8.0; >=0.8.0 resolvable
}

LF=$(mktemp 2>/dev/null) || { echo "FATAL: mktemp"; exit 2; }
CHILD=""
fail=0
ok()  { echo "ok   $1"; }
bad() { echo "FAIL $1"; fail=1; }
skip(){ echo "skip $1"; }
cleanup() {
  # Kill the spawned Psyche subtree first (the runner + its headless claude), by marker pid then name.
  pp=$(grep -oE 'PSYCHE_SPAWNED:[^ ]+ pid=[0-9]+' "$LF" 2>/dev/null | grep -oE '[0-9]+' | tail -1)
  [ -n "$pp" ] && taskkill //PID "$pp" //T //F >/dev/null 2>&1
  for p in $(tasklist 2>/dev/null | grep -i claude-spt-psyche | awk '{print $2}'); do taskkill //PID "$p" //T //F >/dev/null 2>&1; done
  [ -n "$CHILD" ] && kill "$CHILD" >/dev/null 2>&1
  spt endpoint shutdown "$ID" >/dev/null 2>&1 || true
  spt endpoint stop "$ID" >/dev/null 2>&1 || true
  rm -f "$LF" 2>/dev/null || true
}
trap cleanup EXIT INT TERM

# Seed the harness-hosted startup (anchored to the pid that will parent the listen child).
spt api --adapter "$A" --manifest "$MAN" seed --pid "$ANCHOR" --session-id "$SID" >/dev/null 2>&1

# Spawn the resident relay as a CHILD (Monitor surrogate). timeout bounds it so a hang can't wedge CI.
timeout 30 spt api --adapter "$A" --manifest "$MAN" listen --parent-pid "$ANCHOR" "$ID" > "$LF" 2>&1 &
CHILD=$!

# Wait (bounded) for the bringup to announce readiness.
i=0; while [ "$i" -lt 25 ]; do grep -q "READY:$ID" "$LF" 2>/dev/null && break; sleep 1; i=$((i+1)); done

# 1. The live listen path binds the perch.
grep -q "BOUND:$ID" "$LF" 2>/dev/null && ok "live perch bound" || bad "no BOUND:$ID; log=[$(cat "$LF")]"
# 2. The live listen path announces readiness (the relay heartbeat is up).
grep -q "READY:$ID" "$LF" 2>/dev/null && ok "live listen READY:$ID" || bad "no READY:$ID; log=[$(cat "$LF")]"
# 3. PSYCHE-SPAWN — the marker model differs by version (M11 restructure; doyle 2026-06-16):
case "$ver" in
  0.7.*)
    # <0.8.0: `api listen` spawns the Psyche IN-PROCESS → `PSYCHE_SPAWNED:{id}-psyche pid=` off the
    # listen child's stderr. The bare `claude-spt-psyche` resolves via the F-006 PATH interim here.
    if grep -q "PSYCHE_SPAWNED:$ID-psyche pid=" "$LF" 2>/dev/null; then
      ok "Psyche spawned in-process ($(grep -oE "PSYCHE_SPAWNED:$ID-psyche pid=[0-9]+" "$LF" | head -1))"
    elif grep -q "PSYCHE_SPAWN_FAIL:" "$LF" 2>/dev/null && ! psyche_resolvable; then
      skip "psyche-spawn: runner unresolvable on spt $ver without the F-006 PATH interim (Feature B/REQ-INSTALL-11 lands v0.8.0) — $(grep -oE 'PSYCHE_SPAWN_FAIL:[^]]*' "$LF" | head -1)"
    else
      bad "no PSYCHE_SPAWNED marker (manifest declares psyche_init? runner resolvable?); log=[$(cat "$LF")]"
    fi
    ;;
  *)
    # >=0.8.0: the in-process spawn is gone (M11 restructure) — `api listen` emits only BOUND/READY +
    # stamps the perch `status="online"` IFF the resolved manifest declares [session.psyche_init]
    # (startup.rs:283 live_capable guard); the DAEMON reconcile then hosts the Psyche off that online
    # status (the `{id}-psyche` perch comes online; `LIVEHOST_PSYCHE:{id}` on the daemon's stderr).
    # RESOLVED (v0.8.1 + adapter greedy-prompt fix, 2026-06-16): hosting succeeds iff the daemon
    # spawned claude-spt-psyche AND the runner stays RESIDENT. Two bugs were in the way: (1) spt-core
    # <0.8.1 livehost did not reconcile (no spawn at all); v0.8.1 fixed it. (2) spt-core substitutes
    # `{psyche_prompt}` into the psyche_init command STRING then whitespace-SPLITS, so the multi-word
    # prompt arrived as stray argv tokens — the runner's non-greedy --prompt rejected the 2nd word
    # ("unknown arg") and exited 2 instantly → the daemon recorded a phantom hosted perch (nested
    # info.json status=online, real-looking pid) with NO live process and NO psyche_host_error. The
    # runner now parses --prompt greedily (slurps trailing tokens). DETECTION: the nested {id}-psyche
    # perch does NOT surface in `endpoint list` (it lives under the parent in the owlery), so assert on
    # the RESIDENT runner process + the nested perch dir for THIS id. This is also the REQ-INSTALL-11
    # install-dir-resolution proof: the runner resolved by bare name FROM the adapter install dir.
    OWL="${SPT_HOME:-$HOME/AppData/Local/spt-core}/owlery/$ID/nested/$ID-psyche/info.json"
    resident() { tasklist 2>/dev/null | grep -qi "claude-spt-psyche"; }
    j=0; while [ "$j" -lt 20 ]; do resident && [ -f "$OWL" ] && break; sleep 1; j=$((j+1)); done
    procs=$(tasklist 2>/dev/null | grep -ci "claude-spt-psyche")
    nested=no; [ -f "$OWL" ] && nested=yes
    if resident && [ -f "$OWL" ]; then
      ok "Psyche daemon-hosted: claude-spt-psyche runner RESIDENT for $ID-psyche (v0.8.1 livehost + greedy-prompt fix; REQ-INSTALL-11 install-dir resolution proven)"
    else
      bad "psyche-spawn: no resident claude-spt-psyche for $ID (v0.8.1 host gap or prompt-split regression); nested=$nested procs=$procs"
    fi
    ;;
esac

# Deliver a probe with body specials; the resident relay streams it live to the child's stdout.
printf 'live relay probe <a> & "b"' | spt send "$ID" --from relay-probe >/dev/null 2>&1
i=0; while [ "$i" -lt 20 ]; do grep -q 'type="msg"' "$LF" 2>/dev/null && break; sleep 1; i=$((i+1)); done

# 4. RELAY: the probe arrives as the canonical <EVENT> envelope with correct body escaping.
expected='<EVENT type="msg" from="relay-probe">live relay probe <a> & "b"</EVENT>'
grep -qF "$expected" "$LF" 2>/dev/null && ok "probe relayed through the live pipe as escaped <EVENT>" || bad "envelope mismatch; log=[$(cat "$LF")]"
# 5. The endpoint registered as a live_agent (the :live kind was honored on bringup).
kind=$(spt daemon status 2>&1 | sed -n '/local endpoints/,$p' | grep -E "(^| )$ID( |$)")
case "$kind" in *live_agent*) ok "endpoint registered as live_agent (:live kind honored)" ;; *) bad "endpoint not live_agent: [$kind]" ;; esac

[ "$fail" -eq 0 ] && { echo "LIVE-RELAY-INT OK"; exit 0; } || { echo "LIVE-RELAY-INT FAIL"; exit 1; }

-# env vars; pin OWL_SESSION_ID for the auth-gated seed/send/listen surfaces.

+# env vars; pin OWL_SESSION_ID for the auth-gated seed/send/listen surfaces. PER-RUN UNIQUE ($$ suffix):

+# the daemon hosts a Psyche at most ONCE per session_id, so a FIXED id/session would not re-host on a

+# rerun (the first run's hosted-session memory suppresses it) — each CI run must be a fresh session.


Rerun the proof with per-run-unique id:


Bash

cd "C:\Users\decid\Documents\projects\spt-claude-code"
for p in $(tasklist 2>/dev/null | grep -i claude-spt-psyche | awk '{print $2}'); do taskkill //PID "$p" //T //F >/dev/null 2>&1; done
SPTC_ACCEPTANCE=1 timeout 130 sh ci/psyche/live-relay-int.sh 2>&1

Rerun proof with unique id


Command running in background with ID: b3o2v6eid. Output is being written to: C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-claude-code\3fdfaa52-7de3-4b1b-b4b5-594320901cba\tasks\b3o2v6eid.output. You will be notified when it completes. To check interim output, use Read on that file path.


F="C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-claude-code\3fdfaa52-7de3-4b1b-b4b5-594320901cba\tasks\b3o2v6eid.output"
i=0; while [ $i -lt 50 ]; do grep -qE "LIVE-RELAY-INT (OK|FAIL)" "$F" 2>/dev/null && break; sleep 3; i=$((i+1)); done
cat "$F"

Wait for proof verdict


ok   live perch bound
ok   live listen READY:sptc-ci-liverelay-24320
ok   Psyche daemon-hosted: claude-spt-psyche runner RESIDENT for sptc-ci-liverelay-24320-psyche (v0.8.1 livehost + greedy-prompt fix; REQ-INSTALL-11 install-dir resolution proven)
ok   probe relayed through the live pipe as escaped <EVENT>
ok   endpoint registered as live_agent (:live kind honored)
LIVE-RELAY-INT OK


<task-notification>
<task-id>b3o2v6eid</task-id>
<tool-use-id>toolu_016pk9WLw1BW2FaU5HMBopoV</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-claude-code\3fdfaa52-7de3-4b1b-b4b5-594320901cba\tasks\b3o2v6eid.output</output-file>
<status>completed</status>
<summary>Background command "Rerun proof with unique id" completed (exit code 0)</summary>
</task-notification>


**LIVE-RELAY-INT OK** — all 5 legs green, psyche-spawn leg now a passing **assert** (was skip). Task 1 done. REQ-INSTALL-11 proven inline. Let me mark it, run the traceability gate, and prep the commit.


Updated task #1 status


Prompt:
<task-notification>
<task-id>b3o2v6eid</task-id>
<tool-use-id>toolu_016pk9WLw1BW2FaU5HMBopoV</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-claude-code\3fdfaa52-7de3-4b1b-b4b5-594320901cba\tasks\b3o2v6eid.output</output-file>
<status>completed</status>
<summary>Background command "Rerun proof with unique id" completed (exit code 0)</summary>
</task-notification>


cd "C:\Users\decid\Documents\projects\spt-claude-code"
echo "=== traceable-reqs check ==="; traceable-reqs check 2>&1 | tail -20
echo "=== git status ==="; git status -s 2>&1
echo "=== git diff stat ==="; git diff --stat 2>&1

Run traceability gate + git status


=== traceable-reqs check ===
  [OK] REQ-HAZARD-MSYS-PATHCONV  required: [unit]  stages: -doc -impl +unit -int
       Hook wrappers read the CC payload from stdin, never from a /-leading positional argv (Git-Bash/MSYS path-mangles those on Windows)
  [OK] REQ-HAZARD-PERCH-COLLISION  required: [unit]  stages: +doc +impl +unit +int
       The acceptance harness spawns every nested claude SUT under a DISPOSABLE identity (SPT_AGENT_ID=sptc-ci-<n>), never a live agent's perch id — a colliding id tears down the live agent's perch + poll stream (name-keyed, last-establish-wins)
  [OK] REQ-PARITY-AUDIT  required: [doc]  stages: +doc -impl -unit -int
       The adapter's operative skill/profile surface is reconciled against the SCOPE.md LOCKED parity-trim (KEEP/ADD/DROP/TRANSFORM): every divergence is either resolved or logged as an accepted gap in docs/PARITY.md — the 'proven parity' record the sptc->spt succession flip gates on
  [OK] REQ-SETUP-ACTIVATE  required: [doc, int]  stages: +doc -impl -unit +int
       /sptc:setup, after confirming the spt binary is present, ACTIVATES the claude-spt adapter (`spt adapter add` — the manifest file in local dev; `--github <published-adapter-repo>` for end-users) so profiles/strings/hints/[digest] go live, then verifies (adapter no longer `deregistered`). Binary-present is NOT a no-op — this is the F-005 post-install activation bridge.
  [OK] REQ-SETUP-CCS  required: [doc]  stages: +doc -impl -unit -int
       /sptc:setup wires the ccs integration (SCOPE LOCKED setup #7): if `~/.ccs` is present, point the user at the shipped `claude-spt:ccs` profile (routes live/ready sessions through `ccs`, a drop-in for `claude`, via `--adapter claude-spt:ccs`) + sanity-check `ccs` on PATH; if absent, offer to install ccs with a one-sentence value prop (optional — base claude-spt is unaffected).
  [OK] REQ-SETUP-SUBNET  required: [doc]  stages: +doc -impl -unit -int
       /sptc:setup offers subnet onboarding (SCOPE LOCKED setup #3/#4): detect membership (`spt subnet status`); not-in-a-subnet -> offer create (`spt subnet create`, prints code/URI/QR) or join (`spt subnet join`); in-a-subnet -> show-code to invite / add-this-machine. Delegates the verb mechanics to /sptc:subnet and surfaces the OS-elevation requirement (create/join/show-code are seed-reveal/enroll-gated) with the per-context elevation paths; automated context-aware elevation is a deeper wave.
  [OK] REQ-SKILL-LIVE  required: [doc, impl, unit, int]  stages: +doc +impl +unit +int
       /sptc:live upgrades THIS CC session to a LiveAgent: the claude-spt:live profile overlays [session.psyche_init] (daemon spawns the Psyche), the claude-spt-psyche runner keeps the Psyche claude alive (one --continue turn per pulse, NOT one-shot `claude -p`), and the live body activates the :live composite + a resident Monitor relay as the single delivery pipe
  [OK] REQ-SKILL-SUBNET  required: [doc, int]  stages: +doc -impl -unit +int
       The adapter ships subnet membership skill(s) (create/join/show-code) wrapping the published `spt subnet <verb>` surface — the LOCKED-ADD cross-subnet entrypoint (v1 topology is mandatory, SCOPE)
  [OK] REQ-SKILL-VERSION  required: []  stages: -doc -impl -unit -int
       /spt:version reports the spt-core-tracked manifest/binary version (the version-of-truth, not the marketplace skeleton version)
  [OK] REQ-UPS-INJECTION  required: [doc, impl, unit, int]  stages: +doc +impl +unit +int
       UserPromptSubmit hook detects /sptc:X and injects X's real instructions as additionalContext (SKILL.md files stay skeletons); must be empirically confirmed UPS fires on slash-commands
=== git status ===
 M ci/psyche/live-relay-int.sh
 M tools/claude-spt-psyche/src/main.rs
=== git diff stat ===
warning: in the working copy of 'tools/claude-spt-psyche/src/main.rs', LF will be replaced by CRLF the next time Git touches it
 ci/psyche/live-relay-int.sh         | 52 +++++++++++++++++++++++--------------
 tools/claude-spt-psyche/src/main.rs | 48 +++++++++++++++++++++++++++++-----
 2 files changed, 74 insertions(+), 26 deletions(-)


`traceable-reqs check` all **[OK]** (REQ-SKILL-LIVE int+impl+unit+doc satisfied). Two files changed: the runner fix + the proof. This matches perri's established dogfood-on-main flow. Commit with the project co-author trailer.


cd "C:\Users\decid\Documents\projects\spt-claude-code"
git add ci/psyche/live-relay-int.sh tools/claude-spt-psyche/src/main.rs
git commit -F - <<'EOF'
fix(psyche): greedy --prompt — survive spt-core's whitespace-split of {psyche_prompt}

v0.8.1 dogfood root-cause for "daemon-hosted Psyche online but no process".
spt-core substitutes {psyche_prompt} into the [session.psyche_init] command
STRING and then whitespace-SPLITS, so the multi-word prompt ("PSYCHE REVIVAL
time: ... incoming event: ...") reaches claude-spt-psyche as many trailing
argv tokens, not one. The non-greedy --prompt parser took only the first word
and rejected the second as "unknown arg" -> exit 2 instantly. The daemon's
detached spawn() succeeded, so it recorded a phantom hosted perch (nested
info.json status=online, real-looking pid) with NO live process and NO
psyche_host_error -> the exact v0.8.0/v0.8.1 symptom.

Fix: --prompt is now TERMINAL + GREEDY — it slurps every remaining token and
rejoins with spaces (our manifest template keeps --prompt last). Robust whether
spt-core splits or passes one arg. Verified: claude-spt-psyche now stays
RESIDENT across the full live window (was 0 procs every prior run).

Also proves REQ-INSTALL-11: the runner resolved by bare name FROM the adapter
install dir (no PATH interim needed for resolution).

- runner: greedy/terminal --prompt + 2 new unit tests (slurp, unknown-arg-before-prompt)
- live-relay-int: psyche-spawn leg flips skip->ASSERT (resident-runner + nested-perch
  detection; endpoint list never surfaces the nested {id}-psyche perch); per-run-unique
  id/session (daemon hosts a Psyche once per session_id, so a fixed id can't re-host)

Diagnosed via argv-capture instrumentation (daemon passed the prompt split into
7 tokens). spt-core finding reported separately to doyle.

[impl->REQ-SKILL-LIVE] [int->REQ-SKILL-LIVE]

Co-authored by: perri
EOF
echo "=== committed ==="; git log --oneline -1

Commit the psyche greedy-prompt fix


warning: in the working copy of 'tools/claude-spt-psyche/src/main.rs', LF will be replaced by CRLF the next time Git touches it
[main ddf1965] fix(psyche): greedy --prompt — survive spt-core's whitespace-split of {psyche_prompt}
 2 files changed, 74 insertions(+), 26 deletions(-)
=== committed ===
ddf1965 fix(psyche): greedy --prompt — survive spt-core's whitespace-split of {psyche_prompt}


Committed (ddf1965). Now report the spt-core finding to doyle — he asked for it explicitly. Send a focused report.


cd "C:\Users\decid\Documents\projects\spt-claude-code"
cat <<'EOF' | spt send doyle --from perri 2>&1
v0.8.1 RESULT — psyche-host line: CLEAN (no psyche_host_error) on every run, BUT that was masking a real bug. Your reconcile fix WORKS (the daemon now spawns claude-spt-psyche; v0.8.0 never reached the spawn). REQ-INSTALL-11 install-dir resolution also confirmed (runner resolved by bare name from the install dir, no PATH interim).

ROOT CAUSE (adapter-side, now FIXED my end): the daemon-hosted Psyche showed online + real-looking pid + NO process + NO psyche_host_error. argv-capture instrumentation showed why — spt-core substitutes {psyche_prompt} into the [session.psyche_init] command STRING then WHITESPACE-SPLITS it. My multi-word prompt arrived as 7 stray argv tokens:
  --prompt PSYCHE REVIVAL time: epoch-ms:1781652607426 incoming event: (none)
My runner's non-greedy --prompt took "PSYCHE", rejected "REVIVAL" as unknown-arg, exited 2 instantly. Your detached spawn() returned Ok -> phantom hosted perch, no error. Fixed adapter-side: --prompt is now terminal+greedy (slurps trailing tokens). Psyche now stays resident the full window; live-relay-int psyche leg flips skip->assert GREEN.

TWO spt-core FINDINGS for you:
1. COMMAND TEMPLATING: substituting a {key} into the command string then whitespace-splitting makes ANY multi-word fill unusable as a single arg. The digest extractor only survives because {session_id}/{source} are single-token. Recommend: substitute each {key} as ONE argv element (split the template into argv FIRST, then fill each slot), or at minimum document the constraint. This will bite every adapter with a prompt-like fill.
2. SILENT-EXIT STILL MASKABLE: psyche_host_error correctly stays clear when spawn() succeeds but the child exits immediately (exit 2 here). Consider treating a non-resident host (child gone within N seconds, or perch never re-registers) as a host failure so the masking is fully closed — otherwise a crash-on-startup runner looks identical to a healthy host.

MINOR: peer pump STALLS ~7-8 min after every daemon start (observed last-tick 455s & 520s; "advertising/connecting not running"). Did NOT block hosting (psyche hosted fine with pump stalled), but it recurs after each restart — flagging in case it's the same brain-loop neighborhood.

Net: v0.8.1 unblocks me. Proceeding to drop the F-006 PATH interim + per-OS re-release. — perri
EOF
echo "rc=$?"

Send finding report to doyle


NO_PERCH:doyle is not listening
rc=1


doyle isn't listening (NO_PERCH — async; he pinged then went offline). My owl reachability also dropped after the daemon restart. Let me check whether `spt send` can spool to an offline peer, and re-establish my own reachability.


spt send --help 2>&1 | head -30; echo "=== whoami / my perch ==="; spt whoami 2>&1 | head -3

Check send spool options + my perch


Send a message (body read from stdin); fire-and-forget

Usage: spt.exe send [OPTIONS] [TARGET]

Arguments:
  [TARGET]  Target perch id. May be omitted when --reply-to is given

Options:
      --from <FROM>          Sender id carried structurally as the message `from` (auto-detected
                             from session if omitted)
      --reply-to <REPLY_TO>  Reply to this sender; sets the target and labels output REPLIED
      --deferred             Spool only (deferred / hook channel) — no live wake
      --user-msg             Request the `user-msg` type (the user's authority). Honored only from a
                             user-backed origin (a Gateway endpoint, or the local user's own CLI);
                             an agent-family sender is re-stamped to plain `msg` (REQ-MSG-5)
  -h, --help                 Print help
=== whoami / my perch ===
SELF: X  ready_agent  ready=false alive=false
SUBNET SPT_DEV
  X	14efb80c…	Dormant


`--deferred` spools to the backlog without a live wake. Retry the report that way.


cd "C:\Users\decid\Documents\projects\spt-claude-code"
unset SPT_AGENT_ID OWL_SESSION_ID SPTC_CI_ID
cat <<'EOF' | spt send doyle --from perri --deferred 2>&1
v0.8.1 RESULT — psyche-host line CLEAN (no psyche_host_error) every run, but that MASKED the real bug. Your reconcile fix WORKS: daemon now spawns claude-spt-psyche (v0.8.0 never reached the spawn). REQ-INSTALL-11 install-dir resolution confirmed (runner resolved by bare name from install dir, no PATH interim).

ROOT CAUSE (adapter-side, FIXED my end): hosted Psyche showed online + real pid + NO process + NO psyche_host_error. argv-capture showed why: spt-core substitutes {psyche_prompt} into the [session.psyche_init] command STRING then WHITESPACE-SPLITS. My multi-word prompt arrived as 7 stray argv tokens:
  --prompt PSYCHE REVIVAL time: epoch-ms:... incoming event: (none)
My runner's non-greedy --prompt took PSYCHE, rejected REVIVAL as unknown-arg, exited 2 instantly. Your detached spawn() returned Ok -> phantom hosted perch, no error. Fixed adapter-side (greedy/terminal --prompt). Psyche now resident full window; live-relay-int psyche leg skip->assert GREEN. Commit ddf1965.

TWO spt-core FINDINGS:
1. COMMAND TEMPLATING: substitute-into-string-then-whitespace-split makes ANY multi-word {key} fill unusable as one arg. Digest extractor only survives because its fills are single-token. Recommend: split template into argv FIRST, then fill each slot as ONE element (or document the constraint). Bites every adapter with a prompt-like fill.
2. SILENT-EXIT STILL MASKABLE: psyche_host_error stays clear when spawn() succeeds but the child exits immediately. Consider treating a non-resident host (child gone within N sec / perch never re-registers) as host failure to fully close the masking.

MINOR: peer pump STALLS ~7-8 min after each daemon start (last-tick 455s & 520s, "advertising/connecting not running"). Did NOT block hosting, but recurs after every restart.

Net: v0.8.1 unblocks me. Proceeding to drop F-006 PATH interim + per-OS re-release. — perri
EOF
echo "rc=$?"

Send deferred report to doyle


NO_PERCH:doyle is not listening (deferred stays local-only)
rc=1


Re-run psyche proof on v0.8.1 + read psyche-host line

SPTC_ACCEPTANCE=1 sh ci/psyche/live-relay-int.sh on 0.8.1 → psyche leg flips skip→assert. Check spt endpoint list/whoami for psyche-host: line (FAILED reason or clean).

REQ-INSTALL-11 proof: drop F-006 PATH interim

Remove ~/AppData/Local/spt-core/bin/claude-spt-{psyche,digest}.exe → confirm psyche still spawns from install-dir. Drop interim PATH-copy step from setup.md step 4 + plugin SKILL.md step 3.

Per-OS re-release (windows + linux .spt)

Pack adapter-windows-x86_64.spt + adapter-linux-x86_64.spt (zigbuild cross), attach BOTH to new GitHub release with updated manifest ([update] block + dropped interim).

Live gh_release auto-update test

With new release, spt adapter update pulls it. Re-acquire new [update]-bearing manifest first.

cplugs republish v0.1.2

AFTER per-OS release. Ships os-detecting setup floor + ccs (#7) + subnet (#3/#4) + dropped interim.


doyle is fully offline — even `--deferred` can't spool (no registered perch). The report is async; it's permanently captured in commit ddf1965, and I'll retry when he's reachable. Not blocking. Let me record progress in memory before continuing — this is significant state.


Wasted call — file unchanged since your last Read. Refer to that earlier tool_result instead.


Write

---
name: v074-follow-ups
description: "spt v0.8.1 dogfood — daemon-hosted Psyche BLOCKER RESOLVED (commit ddf1965, greedy --prompt fix). REQ-INSTALL-11 proven. REMAINING: drop F-006 interim from setup docs, per-OS re-release + cplugs v0.1.2, live auto-update. doyle report PENDING (he's offline)."
metadata:
  node_type: project
  type: project
  originSessionId: 6f3dfa64-ae2e-4144-85ce-993c366887f4
---

**spt v0.8.1 dogfooded 2026-06-16** (updated 0.8.0→0.8.1 via `spt update fetch && spt update apply`;
RESTARTED the daemon — old daemon was `peer pump: STALLED`, possibly stale-code/env).

## BLOCKER RESOLVED — daemon-hosted Psyche now hosts (commit ddf1965)
Root cause of v0.8.0/v0.8.1 "Psyche online + no process + no cause": **spt-core substitutes
`{psyche_prompt}` into the `[session.psyche_init]` command STRING then WHITESPACE-SPLITS** → the
multi-word prompt arrived as 7 stray argv tokens (`--prompt PSYCHE REVIVAL time: epoch-ms:… incoming
event: (none)`). The runner's non-greedy `--prompt` took "PSYCHE", rejected "REVIVAL" as unknown-arg,
**exited 2 instantly**. The daemon's detached spawn() returned Ok → phantom hosted perch (nested
info.json status=online, real-looking pid) with NO live process and NO psyche_host_error.
- **Diagnosed** via argv-capture instrumentation (temporarily dumped argv to a file from a deployed
  instrumented exe; reverted). doyle's v0.8.1 reconcile fix DID work (v0.8.0 never reached the spawn).
- **Fixed adapter-side**: `--prompt` is now TERMINAL + GREEDY (slurps trailing tokens; manifest keeps
  `--prompt` last). Verified: claude-spt-psyche stays RESIDENT full window (was 0 procs every prior run).
- **REQ-INSTALL-11 PROVEN**: the daemon resolved claude-spt-psyche by bare name FROM the install dir
  (`adapters/_github/SaberMage-spt-claude-code/`) — binaries DO registration-copy there (manifest +
  strings + BOTH .exe). No PATH interim needed for runner resolution.
- **live-relay-int.sh**: psyche-spawn leg flips skip→ASSERT GREEN; detection = resident
  claude-spt-psyche proc + nested `{id}-psyche` perch dir (endpoint list NEVER surfaces the nested
  perch); id/session now **per-run-unique** (`$$` suffix) — daemon hosts a Psyche once per session_id,
  so a fixed id can't re-host. `SPTC_ACCEPTANCE=1 sh ci/psyche/live-relay-int.sh` = LIVE-RELAY-INT OK.

## doyle report PENDING DELIVERY (he's offline — NO_PERCH, even --deferred local-only)
Full content in commit ddf1965 msg. Retry `spt send doyle --from perri` when reachable. Two spt-core
findings for him: (1) command-templating whitespace-splits substituted multi-word keys → ANY prompt-
like fill unusable as one arg (digest survives only b/c single-token fills); recommend split-then-fill.
(2) silent-exit still maskable — psyche_host_error stays clear when spawn() ok but child exits instantly;
treat non-resident host as failure. MINOR: peer pump STALLS ~7-8min after every daemon start (didn't
block hosting).

## REMAINING (v0.8.1 unblocked everything)
1. **Drop F-006 PATH interim** (TASK 2, next): verify claude-spt-digest ALSO resolves from install-dir
   (same REQ-INSTALL-11), then remove the interim PATH-copy step from BOTH setup bodies
   (`adapter/strings/skills/setup.md` step ~4 + `plugin/sptc/skills/setup/SKILL.md` step 3). Interim
   copies live at `~/AppData/Local/spt-core/bin/claude-spt-{psyche,digest}.exe`.
   CAVEAT: the psyche runner internally calls `claude` by bare name — `claude` is at `~/.local/bin`
   which is NOT on the persistent (logon) PATH, so a fresh-logon daemon won't resolve it (the seed/pulse
   claude turns no-op). Separate from the digest/psyche interim; flag if it bites the live psyche LLM.
2. **Per-OS re-release**: pack adapter-windows + adapter-linux .spt (zigbuild cross; zig @ ~/.sptc-zig;
   recipe in docs/RELEASE-RUNBOOK.md), attach BOTH to a NEW release w/ updated manifest ([update] +
   dropped interim). REBUILD the psyche .exe first (the fix is in source; install-dir exe was hand-deployed).
3. **Live gh_release auto-update test** with the new release.
4. **cplugs republish v0.1.2** (coupled AFTER per-OS release): os-detecting setup floor + ccs (#7) +
   subnet (#3/#4) + dropped interim.

F-008 (#5 legacy migration) = deferred-by-design. See [[live-int-gated-m11-counter15]],
[[per-os-and-setup-waves]], [[succession-flip-gated]].


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

---
name: v074-follow-ups
description: "spt v0.8.1 dogfood — daemon-hosted Psyche BLOCKER RESOLVED (commit ddf1965, greedy --prompt fix). REQ-INSTALL-11 proven. REMAINING: drop F-006 interim from setup docs, per-OS re-release + cplugs v0.1.2, live auto-update. doyle report PENDING (he's offline)."
metadata:
  node_type: project
  type: project
  originSessionId: 6f3dfa64-ae2e-4144-85ce-993c366887f4
---

**spt v0.8.1 dogfooded 2026-06-16** (updated 0.8.0→0.8.1 via `spt update fetch && spt update apply`;
RESTARTED the daemon — old daemon was `peer pump: STALLED`, possibly stale-code/env).

## BLOCKER RESOLVED — daemon-hosted Psyche now hosts (commit ddf1965)
Root cause of v0.8.0/v0.8.1 "Psyche online + no process + no cause": **spt-core substitutes
`{psyche_prompt}` into the `[session.psyche_init]` command STRING then WHITESPACE-SPLITS** → the
multi-word prompt arrived as 7 stray argv tokens (`--prompt PSYCHE REVIVAL time: epoch-ms:… incoming
event: (none)`). The runner's non-greedy `--prompt` took "PSYCHE", rejected "REVIVAL" as unknown-arg,
**exited 2 instantly**. The daemon's detached spawn() returned Ok → phantom hosted perch (nested
info.json status=online, real-looking pid) with NO live process and NO psyche_host_error.
- **Diagnosed** via argv-capture instrumentation (temporarily dumped argv to a file from a deployed
  instrumented exe; reverted). doyle's v0.8.1 reconcile fix DID work (v0.8.0 never reached the spawn).
- **Fixed adapter-side**: `--prompt` is now TERMINAL + GREEDY (slurps trailing tokens; manifest keeps
  `--prompt` last). Verified: claude-spt-psyche stays RESIDENT full window (was 0 procs every prior run).
- **REQ-INSTALL-11 PROVEN**: the daemon resolved claude-spt-psyche by bare name FROM the install dir
  (`adapters/_github/SaberMage-spt-claude-code/`) — binaries DO registration-copy there (manifest +
  strings + BOTH .exe). No PATH interim needed for runner resolution.
- **live-relay-int.sh**: psyche-spawn leg flips skip→ASSERT GREEN; detection = resident
  claude-spt-psyche proc + nested `{id}-psyche` perch dir (endpoint list NEVER surfaces the nested
  perch); id/session now **per-run-unique** (`$$` suffix) — daemon hosts a Psyche once per session_id,
  so a fixed id can't re-host. `SPTC_ACCEPTANCE=1 sh ci/psyche/live-relay-int.sh` = LIVE-RELAY-INT OK.

## doyle report PENDING DELIVERY (he's offline — NO_PERCH, even --deferred local-only)
Full content in commit ddf1965 msg. Retry `spt send doyle --from perri` when reachable. Two spt-core
findings for him: (1) command-templating whitespace-splits substituted multi-word keys → ANY prompt-
like fill unusable as one arg (digest survives only b/c single-token fills); recommend split-then-fill.
(2) silent-exit still maskable — psyche_host_error stays clear when spawn() ok but child exits instantly;
treat non-resident host as failure. MINOR: peer pump STALLS ~7-8min after every daemon start (didn't
block hosting).

## REMAINING (v0.8.1 unblocked everything)
1. **Drop F-006 PATH interim** (TASK 2, next): verify claude-spt-digest ALSO resolves from install-dir
   (same REQ-INSTALL-11), then remove the interim PATH-copy step from BOTH setup bodies
   (`adapter/strings/skills/setup.md` step ~4 + `plugin/sptc/skills/setup/SKILL.md` step 3). Interim
   copies live at `~/AppData/Local/spt-core/bin/claude-spt-{psyche,digest}.exe`.
   CAVEAT: the psyche runner internally calls `claude` by bare name — `claude` is at `~/.local/bin`
   which is NOT on the persistent (logon) PATH, so a fresh-logon daemon won't resolve it (the seed/pulse
   claude turns no-op). Separate from the digest/psyche interim; flag if it bites the live psyche LLM.
2. **Per-OS re-release**: pack adapter-windows + adapter-linux .spt (zigbuild cross; zig @ ~/.sptc-zig;
   recipe in docs/RELEASE-RUNBOOK.md), attach BOTH to a NEW release w/ updated manifest ([update] +
   dropped interim). REBUILD the psyche .exe first (the fix is in source; install-dir exe was hand-deployed).
3. **Live gh_release auto-update test** with the new release.
4. **cplugs republish v0.1.2** (coupled AFTER per-OS release): os-detecting setup floor + ccs (#7) +
   subnet (#3/#4) + dropped interim.

F-008 (#5 legacy migration) = deferred-by-design. See [[live-int-gated-m11-counter15]],
[[per-os-and-setup-waves]], [[succession-flip-gated]].

-description: "spt v0.8.0 dogfood DONE (REQ-API-4, how-to-live, gh_release [update], relay int) — REMAINING items (daemon-hosted psyche proof, REQ-INSTALL-11, F-006 interim drop, per-OS re-release + cplugs v0.1.2, live auto-update) all gated on spt v0.8.1 (reconcile-loop fix)"

+description: "spt v0.8.1 dogfood — daemon-hosted Psyche BLOCKER RESOLVED (commit ddf1965, greedy --prompt fix). REQ-INSTALL-11 proven. REMAINING: drop F-006 interim from setup docs, per-OS re-release + cplugs v0.1.2, live auto-update. doyle report PENDING (he's offline)."

-**spt v0.8.0 dogfooded 2026-06-16** (upgraded 0.7.3→0.8.0, hash 10ff8166…, daemon restarted).

-Commits: 25feaeb (dogfood) + earlier per-OS/setup. SHIPPED:

-- **REQ-API-4** ✓ — `spt api --adapter claude-spt:live <verb>` resolves the registered manifest WITHOUT

-- **F-007 ✓ shipped** — `spt how-to live` topic exists; /sptc:live step 2 re-pointed at it.

-- **[update] gh_release ✓ declared** — claude-spt.toml `[update] avenue="gh_release",

-  repo="SaberMage/spt-claude-code"`; re-vendored the v0.8.0 manifest.schema.json; validates.

-- **live-relay-int.sh** relay leg green on 0.8.0; >=0.8.0 psyche leg = skip-with-note (auto-flips on v0.8.1).

+**spt v0.8.1 dogfooded 2026-06-16** (updated 0.8.0→0.8.1 via `spt update fetch && spt update apply`;

+RESTARTED the daemon — old daemon was `peer pump: STALLED`, possibly stale-code/env).

-**BLOCKER — spt v0.8.1 (doyle's, diagnosed via this dogfood):** the daemon-hosted psyche does NOT

-spawn. Root cause (doyle-confirmed): a live perch is stamped `status="online"` (live_capable guard

-passes — info.json `{state:live_agent,status:online,adapter:claude-spt:live}`, registered manifest's

-psyche_init IDENTICAL to local), the host-predicate fully passes, but `reconcile_once`/`spawn_live_host`

-never runs — `run_brain` stalls on net bringup before reaching it (net boot-race; correlate: `spt daemon

-status` "peer pump STALLED" after every restart). NOT the adapter/manifest. doyle builds v0.8.1

-(make spawn_live_host independent of/ahead of the net bringup) + a regression E2E. He pings on publish.

+## BLOCKER RESOLVED — daemon-hosted Psyche now hosts (commit ddf1965)

+Root cause of v0.8.0/v0.8.1 "Psyche online + no process + no cause": **spt-core substitutes

+`{psyche_prompt}` into the `[session.psyche_init]` command STRING then WHITESPACE-SPLITS** → the

+multi-word prompt arrived as 7 stray argv tokens (`--prompt PSYCHE REVIVAL time: epoch-ms:… incoming

+event: (none)`). The runner's non-greedy `--prompt` took "PSYCHE", rejected "REVIVAL" as unknown-arg,

+**exited 2 instantly**. The daemon's detached spawn() returned Ok → phantom hosted perch (nested

+info.json status=online, real-looking pid) with NO live process and NO psyche_host_error.

+- **Diagnosed** via argv-capture instrumentation (temporarily dumped argv to a file from a deployed

+  instrumented exe; reverted). doyle's v0.8.1 reconcile fix DID work (v0.8.0 never reached the spawn).

+- **Fixed adapter-side**: `--prompt` is now TERMINAL + GREEDY (slurps trailing tokens; manifest keeps

+  `--prompt` last). Verified: claude-spt-psyche stays RESIDENT full window (was 0 procs every prior run).

+- **REQ-INSTALL-11 PROVEN**: the daemon resolved claude-spt-psyche by bare name FROM the install dir

+  (`adapters/_github/SaberMage-spt-claude-code/`) — binaries DO registration-copy there (manifest +

+  strings + BOTH .exe). No PATH interim needed for runner resolution.

+- **live-relay-int.sh**: psyche-spawn leg flips skip→ASSERT GREEN; detection = resident

+  claude-spt-psyche proc + nested `{id}-psyche` perch dir (endpoint list NEVER surfaces the nested

+  perch); id/session now **per-run-unique** (`$$` suffix) — daemon hosts a Psyche once per session_id,

+  so a fixed id can't re-host. `SPTC_ACCEPTANCE=1 sh ci/psyche/live-relay-int.sh` = LIVE-RELAY-INT OK.

-**ON v0.8.1 PING — re-run the proof + finish the retirement:**

-1. Re-run `SPTC_ACCEPTANCE=1 sh ci/psyche/live-relay-int.sh` on 0.8.1 → the `{id}-psyche` perch hosts

-   → the >=0.8.0 psyche leg flips from skip to assert (no script change needed; the assert path exists).

-2. **REQ-INSTALL-11 proof:** with the psyche hosting, remove the F-006 PATH interim copies

-   (`~/AppData/Local/spt-core/bin/claude-spt-{psyche,digest}.exe`) → confirm the psyche still spawns

-   (binary resolved from the install-dir `adapters/_github/<safe>/`). Then DROP the interim PATH-copy

-   step from both /sptc:setup bodies (setup.md step 4 + plugin SKILL.md step 3).

-3. **Per-OS re-release:** pack adapter-windows-x86_64.spt + adapter-linux-x86_64.spt (linux cross-build

-   via cargo-zigbuild PROVEN; zig at ~/.sptc-zig, recipe in RELEASE-RUNBOOK), attach BOTH to a NEW

-   GitHub release carrying the updated manifest (with [update] block + dropped interim).

-4. **Live gh_release auto-update test:** with the new release, `spt adapter update` should pull it

-   (the currently-registered v0.1.0 has no [update]; re-acquire the new one first).

-5. **cplugs republish v0.1.2** (coupled, AFTER the per-OS release per RELEASE-RUNBOOK): ships the

-   os-detecting setup floor + ccs (#7) + subnet (#3/#4) + dropped interim.

+## doyle report PENDING DELIVERY (he's offline — NO_PERCH, even --deferred local-only)

+Full content in commit ddf1965 msg. Retry `spt send doyle --from perri` when reachable. Two spt-core

+findings for him: (1) command-templating whitespace-splits substituted multi-word keys → ANY prompt-

+like fill unusable as one arg (digest survives only b/c single-token fills); recommend split-then-fill.

+(2) silent-exit still maskable — psyche_host_error stays clear when spawn() ok but child exits instantly;

+treat non-resident host as failure. MINOR: peer pump STALLS ~7-8min after every daemon start (didn't

-F-008 (#5 legacy migration) = deferred-by-design (installer's job). See [[live-int-gated-m11-counter15]]

+## REMAINING (v0.8.1 unblocked everything)

+1. **Drop F-006 PATH interim** (TASK 2, next): verify claude-spt-digest ALSO resolves from install-dir

+   (same REQ-INSTALL-11), then remove the interim PATH-copy step from BOTH setup bodies

+   (`adapter/strings/skills/setup.md` step ~4 + `plugin/sptc/skills/setup/SKILL.md` step 3). Interim

+   copies live at `~/AppData/Local/spt-core/bin/claude-spt-{psyche,digest}.exe`.

+   CAVEAT: the psyche runner internally calls `claude` by bare name — `claude` is at `~/.local/bin`

+   which is NOT on the persistent (logon) PATH, so a fresh-logon daemon won't resolve it (the seed/pulse

+   claude turns no-op). Separate from the digest/psyche interim; flag if it bites the live psyche LLM.

+2. **Per-OS re-release**: pack adapter-windows + adapter-linux .spt (zigbuild cross; zig @ ~/.sptc-zig;

+   recipe in docs/RELEASE-RUNBOOK.md), attach BOTH to a NEW release w/ updated manifest ([update] +

+3. **Live gh_release auto-update test** with the new release.

+4. **cplugs republish v0.1.2** (coupled AFTER per-OS release): os-detecting setup floor + ccs (#7) +

+F-008 (#5 legacy migration) = deferred-by-design. See [[live-int-gated-m11-counter15]],

---
name: v074-follow-ups
description: "spt v0.8.0 dogfood DONE (REQ-API-4, how-to-live, gh_release [update], relay int) — REMAINING items (daemon-hosted psyche proof, REQ-INSTALL-11, F-006 interim drop, per-OS re-release + cplugs v0.1.2, live auto-update) all gated on spt v0.8.1 (reconcile-loop fix)"
metadata:
  node_type: project
  type: project
  originSessionId: 6f3dfa64-ae2e-4144-85ce-993c366887f4
---

**spt v0.8.0 dogfooded 2026-06-16** (upgraded 0.7.3→0.8.0, hash 10ff8166…, daemon restarted).
Commits: 25feaeb (dogfood) + earlier per-OS/setup. SHIPPED:
- **REQ-API-4** ✓ — `spt api --adapter claude-spt:live <verb>` resolves the registered manifest WITHOUT
  `--manifest` (capability + listen).
- **F-007 ✓ shipped** — `spt how-to live` topic exists; /sptc:live step 2 re-pointed at it.
- **[update] gh_release ✓ declared** — claude-spt.toml `[update] avenue="gh_release",
  repo="SaberMage/spt-claude-code"`; re-vendored the v0.8.0 manifest.schema.json; validates.
- **live-relay-int.sh** relay leg green on 0.8.0; >=0.8.0 psyche leg = skip-with-note (auto-flips on v0.8.1).

**BLOCKER — spt v0.8.1 (doyle's, diagnosed via this dogfood):** the daemon-hosted psyche does NOT
spawn. Root cause (doyle-confirmed): a live perch is stamped `status="online"` (live_capable guard
passes — info.json `{state:live_agent,status:online,adapter:claude-spt:live}`, registered manifest's
psyche_init IDENTICAL to local), the host-predicate fully passes, but `reconcile_once`/`spawn_live_host`
never runs — `run_brain` stalls on net bringup before reaching it (net boot-race; correlate: `spt daemon
status` "peer pump STALLED" after every restart). NOT the adapter/manifest. doyle builds v0.8.1
(make spawn_live_host independent of/ahead of the net bringup) + a regression E2E. He pings on publish.

**ON v0.8.1 PING — re-run the proof + finish the retirement:**
1. Re-run `SPTC_ACCEPTANCE=1 sh ci/psyche/live-relay-int.sh` on 0.8.1 → the `{id}-psyche` perch hosts
   → the >=0.8.0 psyche leg flips from skip to assert (no script change needed; the assert path exists).
2. **REQ-INSTALL-11 proof:** with the psyche hosting, remove the F-006 PATH interim copies
   (`~/AppData/Local/spt-core/bin/claude-spt-{psyche,digest}.exe`) → confirm the psyche still spawns
   (binary resolved from the install-dir `adapters/_github/<safe>/`). Then DROP the interim PATH-copy
   step from both /sptc:setup bodies (setup.md step 4 + plugin SKILL.md step 3).
3. **Per-OS re-release:** pack adapter-windows-x86_64.spt + adapter-linux-x86_64.spt (linux cross-build
   via cargo-zigbuild PROVEN; zig at ~/.sptc-zig, recipe in RELEASE-RUNBOOK), attach BOTH to a NEW
   GitHub release carrying the updated manifest (with [update] block + dropped interim).
4. **Live gh_release auto-update test:** with the new release, `spt adapter update` should pull it
   (the currently-registered v0.1.0 has no [update]; re-acquire the new one first).
5. **cplugs republish v0.1.2** (coupled, AFTER the per-OS release per RELEASE-RUNBOOK): ships the
   os-detecting setup floor + ccs (#7) + subnet (#3/#4) + dropped interim.

F-008 (#5 legacy migration) = deferred-by-design (installer's job). See [[live-int-gated-m11-counter15]]
+ [[per-os-and-setup-waves]].


Now update the MEMORY.md index line.


Edit

- [v0.8.0 dogfood DONE → v0.8.1 blocker](v074-follow-ups.md) — v0.8.0 dogfooded (REQ-API-4, how-to-live, gh_release [update], relay int — 25feaeb). Daemon-hosted psyche BLOCKED: spt reconcile_once not running (net boot-race) → doyle's v0.8.1. On v0.8.1 ping: psyche proof + REQ-INSTALL-11 + drop F-006 interim + per-OS re-release + cplugs v0.1.2 + live auto-update test.

- [v0.8.1 psyche BLOCKER RESOLVED](v074-follow-ups.md) — ddf1965 greedy --prompt fix: spt-core whitespace-splits substituted {psyche_prompt} → runner exited 2 on stray argv → phantom host. Psyche now resident; REQ-INSTALL-11 proven; live-relay-int psyche leg skip→assert GREEN. doyle report PENDING (offline). REMAINING: drop F-006 interim, per-OS re-release, cplugs v0.1.2, live auto-update.


<tool_use_error>File has not been read yet. Read it first before writing to it.</tool_use_error>

Error: File has not been read yet. Read it first before writing to it.


1	# Memory index — spt-claude-code
2
3	- [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).
4	- [v0.8.0 dogfood DONE → v0.8.1 blocker](v074-follow-ups.md) — v0.8.0 dogfooded (REQ-API-4, how-to-live, gh_release [update], relay int — 25feaeb). Daemon-hosted psyche BLOCKED: spt reconcile_once not running (net boot-race) → doyle's v0.8.1. On v0.8.1 ping: psyche proof + REQ-INSTALL-11 + drop F-006 interim + per-OS re-release + cplugs v0.1.2 + live auto-update test.
5	- [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).
6	- [Succession flip gated](succession-flip-gated.md) — publish as sptc; flip to spt only after proven parity AND legacy owl retired.
7

# 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.0 dogfood DONE → v0.8.1 blocker](v074-follow-ups.md) — v0.8.0 dogfooded (REQ-API-4, how-to-live, gh_release [update], relay int — 25feaeb). Daemon-hosted psyche BLOCKED: spt reconcile_once not running (net boot-race) → doyle's v0.8.1. On v0.8.1 ping: psyche proof + REQ-INSTALL-11 + drop F-006 interim + per-OS re-release + cplugs v0.1.2 + live auto-update test.
- [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.


- [v0.8.0 dogfood DONE → v0.8.1 blocker](v074-follow-ups.md) — v0.8.0 dogfooded (REQ-API-4, how-to-live, gh_release [update], relay int — 25feaeb). Daemon-hosted psyche BLOCKED: spt reconcile_once not running (net boot-race) → doyle's v0.8.1. On v0.8.1 ping: psyche proof + REQ-INSTALL-11 + drop F-006 interim + per-OS re-release + cplugs v0.1.2 + live auto-update test.

- [v0.8.1 psyche BLOCKER RESOLVED](v074-follow-ups.md) — ddf1965 greedy --prompt fix: spt-core whitespace-splits substituted {psyche_prompt} → runner exited 2 on stray argv → phantom host. Psyche now resident; REQ-INSTALL-11 proven; live-relay-int psyche leg skip→assert GREEN. doyle report PENDING (offline). REMAINING: drop F-006 interim, per-OS re-release, cplugs v0.1.2, live auto-update.


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.0 dogfood DONE → v0.8.1 blocker](v074-follow-ups.md) — v0.8.0 dogfooded (REQ-API-4, how-to-live, gh_release [update], relay int — 25feaeb). Daemon-hosted psyche BLOCKED: spt reconcile_once not running (net boot-race) → doyle's v0.8.1. On v0.8.1 ping: psyche proof + REQ-INSTALL-11 + drop F-006 interim + per-OS re-release + cplugs v0.1.2 + live auto-update test.
- [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.

-- [v0.8.0 dogfood DONE → v0.8.1 blocker](v074-follow-ups.md) — v0.8.0 dogfooded (REQ-API-4, how-to-live, gh_release [update], relay int — 25feaeb). Daemon-hosted psyche BLOCKED: spt reconcile_once not running (net boot-race) → doyle's v0.8.1. On v0.8.1 ping: psyche proof + REQ-INSTALL-11 + drop F-006 interim + per-OS re-release + cplugs v0.1.2 + live auto-update test.

+- [v0.8.1 psyche BLOCKER RESOLVED](v074-follow-ups.md) — ddf1965 greedy --prompt fix: spt-core whitespace-splits substituted {psyche_prompt} → runner exited 2 on stray argv → phantom host. Psyche now resident; REQ-INSTALL-11 proven; live-relay-int psyche leg skip→assert GREEN. doyle report PENDING (offline). REMAINING: drop F-006 interim, per-OS re-release, cplugs v0.1.2, live auto-update.


Memory + index updated. Now task 2 — drop the F-006 PATH interim. Before editing setup docs, I must verify `claude-spt-digest` ALSO resolves from the install-dir (same REQ-INSTALL-11 path the psyche proved), else dropping its interim breaks digest. Check the digest proof to replicate a resolution test.


Updated task #2 status


1	#!/bin/sh
2	# Integration proof: `spt adapter digest-proof` runs the claude-spt [digest] extractor and renders a
3	# non-empty digest from a real CC-shaped sample (ADR-0019 — the M10 acceptance criterion carried
4	# forward for spt-claude-code). [int->REQ-DIST-DIGEST-EXTRACTOR]
5	#
6	# Gated behind SPTC_ACCEPTANCE=1 (mutates the node-local adapter registry: add + soft-remove) and a
7	# present spt>=0.7 + a built extractor. Idempotent. Run: SPTC_ACCEPTANCE=1 sh ci/digest/digest-proof-int.sh
8	#
9	# GREEN since spt v0.7.2 (doyle's F-004 fix, release counter 14): `digest-proof --sample` now fills
10	# the runtime substitution keys ({id}+{session_id}, + an optional --session) matching the daemon, so
11	# the published-shape extractor command (`--session {session_id} --in {source}`) proofs instead of
12	# hard-failing {session_id}. Was F-004-blocked on <=0.7.1 (empty key map, cli.rs:5135) — the legacy
13	# SKIP branch below stays as a guard so an OLD binary announces the version gap rather than failing.
14	set -u
15	ROOT=$(CDPATH= cd "$(dirname "$0")/../.." && pwd)
16	MANIFEST="$ROOT/adapter/claude-spt.toml"
17	SAMPLE="$ROOT/ci/digest/sample.jsonl"
18	RELDIR="$ROOT/tools/claude-spt-digest/target/release"
19
20	[ "${SPTC_ACCEPTANCE:-0}" = "1" ] || { echo "SKIP: set SPTC_ACCEPTANCE=1 to run (mutates the adapter registry)"; exit 0; }
21	command -v spt >/dev/null 2>&1 || { echo "SKIP: no spt on PATH"; exit 0; }
22	[ -x "$RELDIR/claude-spt-digest" ] || [ -x "$RELDIR/claude-spt-digest.exe" ] || { echo "SKIP: extractor not built (run sh ci/digest/build.sh)"; exit 0; }
23
24	trap 'spt adapter remove claude-spt >/dev/null 2>&1 || true' EXIT INT TERM
25	# Make the manifest's bare `claude-spt-digest` resolvable (the release dir holds the built binary).
26	PATH="$RELDIR:$PATH"; export PATH
27
28	spt adapter add "$MANIFEST" >/dev/null 2>&1 || { echo "FAIL: spt adapter add"; exit 1; }
29
30	out=$(spt adapter digest-proof claude-spt --sample "$SAMPLE" 2>&1)
31	case "$out" in
32	  *DIGEST_PROOF_OK*)
33	    echo "ok  digest-proof: DIGEST_PROOF_OK"
34	    printf '%s\n' "$out" | grep -E 'parsed|dropped' | sed 's/^/    /'
35	    echo "DIGEST-PROOF-INT OK"; exit 0 ;;
36	  *"no value for substitution key {session_id}"*)
37	    echo "SKIP: spt < v0.7.2 — digest-proof --sample doesn't fill {session_id} (pre-F-004-fix binary)."
38	    echo "      upgrade to spt >= 0.7.2 (release counter 14) to run this int. Extractor itself: cargo tests green."
39	    exit 0 ;;
40	  *)
41	    echo "FAIL: unexpected digest-proof output:"; printf '%s\n' "$out"; exit 1 ;;
42	esac
43

#!/bin/sh
# Integration proof: `spt adapter digest-proof` runs the claude-spt [digest] extractor and renders a
# non-empty digest from a real CC-shaped sample (ADR-0019 — the M10 acceptance criterion carried
# forward for spt-claude-code). [int->REQ-DIST-DIGEST-EXTRACTOR]
#
# Gated behind SPTC_ACCEPTANCE=1 (mutates the node-local adapter registry: add + soft-remove) and a
# present spt>=0.7 + a built extractor. Idempotent. Run: SPTC_ACCEPTANCE=1 sh ci/digest/digest-proof-int.sh
#
# GREEN since spt v0.7.2 (doyle's F-004 fix, release counter 14): `digest-proof --sample` now fills
# the runtime substitution keys ({id}+{session_id}, + an optional --session) matching the daemon, so
# the published-shape extractor command (`--session {session_id} --in {source}`) proofs instead of
# hard-failing {session_id}. Was F-004-blocked on <=0.7.1 (empty key map, cli.rs:5135) — the legacy
# SKIP branch below stays as a guard so an OLD binary announces the version gap rather than failing.
set -u
ROOT=$(CDPATH= cd "$(dirname "$0")/../.." && pwd)
MANIFEST="$ROOT/adapter/claude-spt.toml"
SAMPLE="$ROOT/ci/digest/sample.jsonl"
RELDIR="$ROOT/tools/claude-spt-digest/target/release"

[ "${SPTC_ACCEPTANCE:-0}" = "1" ] || { echo "SKIP: set SPTC_ACCEPTANCE=1 to run (mutates the adapter registry)"; exit 0; }
command -v spt >/dev/null 2>&1 || { echo "SKIP: no spt on PATH"; exit 0; }
[ -x "$RELDIR/claude-spt-digest" ] || [ -x "$RELDIR/claude-spt-digest.exe" ] || { echo "SKIP: extractor not built (run sh ci/digest/build.sh)"; exit 0; }

trap 'spt adapter remove claude-spt >/dev/null 2>&1 || true' EXIT INT TERM
# Make the manifest's bare `claude-spt-digest` resolvable (the release dir holds the built binary).
PATH="$RELDIR:$PATH"; export PATH

spt adapter add "$MANIFEST" >/dev/null 2>&1 || { echo "FAIL: spt adapter add"; exit 1; }

out=$(spt adapter digest-proof claude-spt --sample "$SAMPLE" 2>&1)
case "$out" in
  *DIGEST_PROOF_OK*)
    echo "ok  digest-proof: DIGEST_PROOF_OK"
    printf '%s\n' "$out" | grep -E 'parsed|dropped' | sed 's/^/    /'
    echo "DIGEST-PROOF-INT OK"; exit 0 ;;
  *"no value for substitution key {session_id}"*)
    echo "SKIP: spt < v0.7.2 — digest-proof --sample doesn't fill {session_id} (pre-F-004-fix binary)."
    echo "      upgrade to spt >= 0.7.2 (release counter 14) to run this int. Extractor itself: cargo tests green."
    exit 0 ;;
  *)
    echo "FAIL: unexpected digest-proof output:"; printf '%s\n' "$out"; exit 1 ;;
esac


The digest proof currently relies on PATH (prepends `$RELDIR`). To confirm digest resolves from the **install-dir** (so dropping its interim is safe), I'll move BOTH interim PATH copies aside and run digest-proof + a psyche bringup with the interim gone. If both still work, install-dir resolution is proven for both → safe to drop.


Bash

cd "C:\Users\decid\Documents\projects\spt-claude-code"
BIN=~/AppData/Local/spt-core/bin
echo "=== move F-006 interim copies aside ==="
mv "$BIN/claude-spt-digest.exe" "$BIN/claude-spt-digest.exe.OFF" 2>&1 && echo "digest interim OFF"
mv "$BIN/claude-spt-psyche.exe" "$BIN/claude-spt-psyche.exe.OFF" 2>&1 && echo "psyche interim OFF"
echo "=== confirm NOT on PATH now ==="
command -v claude-spt-digest 2>&1 || echo "  digest: not on PATH (good)"
command -v claude-spt-psyche 2>&1 || echo "  psyche: not on PATH (good)"
echo "=== digest-proof on REGISTERED adapter, RELDIR NOT on PATH (forces install-dir resolution) ==="
# strip RELDIR; keep spt resolvable
SPTC_ACCEPTANCE=1 spt adapter digest-proof claude-spt --sample ci/digest/sample.jsonl 2>&1 | head -8

Test install-dir resolution with interim removed


=== move F-006 interim copies aside ===
digest interim OFF
psyche interim OFF
=== confirm NOT on PATH now ===
  digest: not on PATH (good)
  psyche: not on PATH (good)
=== digest-proof on REGISTERED adapter, RELDIR NOT on PATH (forces install-dir resolution) ===
=== digest-proof: claude-spt ===
parsed 5 record(s), dropped 0

--- parsed records ---
  {"role":"input","text":"add a file at src/a.rs","ts":"2026-06-15T10:00:00.000Z"}
  {"role":"agent","text":"On it — writing src/a.rs now.","ts":"2026-06-15T10:00:01.000Z"}
  {"role":"tool","tool":{"arg":"src/a.rs","name":"Write"},"ts":"2026-06-15T10:00:01.000Z"}
  {"role":"tool","tool":{"arg":"cargo build","name":"Bash"},"ts":"2026-06-15T10:00:04.000Z"}


digest-proof: **`parsed 5 record(s), dropped 0`** — `claude-spt-digest` resolved **from the install dir** with the interim removed. REQ-INSTALL-11 covers digest too. Final airtight check: a psyche bringup with the interim still OFF.


cd "C:\Users\decid\Documents\projects\spt-claude-code"
A=claude-spt:live; MAN="$PWD/adapter/claude-spt.toml"
ID=sptc-nointerim-$$; SID=$ID-sess
export SPTC_CI_ID="$ID" SPT_AGENT_ID="$ID" OWL_SESSION_ID="$ID"
ANCHOR=$(ps -p $$ 2>/dev/null | awk 'NR==2{print $4}'); case "$ANCHOR" in ''|*[!0-9]*) ANCHOR=$$;; esac
LF=$(mktemp)
spt api --adapter "$A" --manifest "$MAN" seed --pid "$ANCHOR" --session-id "$SID" >/dev/null 2>&1
timeout 40 spt api --adapter "$A" --manifest "$MAN" listen --parent-pid "$ANCHOR" "$ID" > "$LF" 2>&1 &
i=0; while [ "$i" -lt 25 ]; do grep -q "READY:$ID" "$LF" 2>/dev/null && break; sleep 1; i=$((i+1)); done
sleep 8
echo "psyche resident with interim OFF: procs=$(tasklist 2>/dev/null | grep -ci claude-spt-psyche) nested=$([ -f ~/AppData/Local/spt-core/owlery/$ID/nested/$ID-psyche/info.json ] && echo yes || echo no)"
for p in $(tasklist 2>/dev/null | grep -i claude-spt-psyche | awk '{print $2}'); do taskkill //PID "$p" //T //F >/dev/null 2>&1; done
spt endpoint shutdown "$ID" >/dev/null 2>&1

Psyche bringup with interim OFF


psyche resident with interim OFF: procs=1 nested=yes


Both proven from install-dir with interim OFF: **digest** (parsed 5) and **psyche** (procs=1, nested=yes). REQ-INSTALL-11 fully covers both binaries — the F-006 interim is retired. Now drop the interim PATH-copy step from both setup bodies. Read them.


40	       `manifest.toml` + `strings/` + the native tool binaries) from the repo's GitHub release,
41	       extracts it to the durable adapter home, and registers it. Add `--tag <ver>` to pin a version
42	       (omit for latest). Re-running with a newer `--tag` is a manual re-acquire. `adapter add` is
43	       manifest-first (an invalid manifest registers nothing). (v1 ships **windows + linux** assets.
44	       Recommended path — straight from the monorepo, no dedicated repo. Needs the spt release that
45	       carries `--release`; the older `--github <root-manifest-repo>` is the alternative.)
46	       <!-- [doc->REQ-DIST-ADAPTER-PEROS] -->
47
48	3. **Verify activation.** Re-run `spt adapter list`: `claude-spt` must now appear **active** (no
49	   `deregistered`). Spot-check a profile resolves: `spt adapter get-string claude-spt:live adapter_label`
50	   (any shipped profile). Report the active state.
51
52	4. **Tool binaries on PATH (feature prerequisite + interim copy-mode fix).** The `[digest]` extractor
53	   (`claude-spt-digest`) and the Psyche runner (`claude-spt-psyche`) are invoked by **bare name** →
54	   resolved from PATH at runtime. Activation registers the manifest, but session-digest + LiveAgent
55	   Psyche only **function** once those two binaries resolve. Check: `command -v claude-spt-digest`
56	   and `command -v claude-spt-psyche`.
57	   - If both resolve → done.
58	   - If they MISS **after an `--release` activation**: the binaries shipped in the `adapter.spt` and
59	     extracted **beside the manifest** in the adapter's install dir, but `--release` copy-mode does
60	     not place them on PATH. **Interim fix:** find the extract dir (the `from …` path in
61	     `spt adapter list`, e.g. `…/adapters/_github/<safe>/`) and copy `claude-spt-digest` +
62	     `claude-spt-psyche` from there into a directory already on PATH (the spt bin dir — same dir as
63	     `spt` itself — works). Re-check `command -v`.
64	   - *(This interim step retires once spt-core resolves adapter binaries against the install dir
65	     before PATH — REQ-INSTALL-9, doyle. Until then, place them on PATH.)*
66
67	5. **ccs wiring (optional — SCOPE setup #7).** Detect `~/.ccs`:
68	   - **Present** → ccs is installed. The shipped **`claude-spt:ccs`** profile leaf-replaces the live
69	     session command with `ccs` (a drop-in for `claude`), so live/ready agents can run on ccs's
70	     configured backends (glm/kimi/custom from `~/.ccs/config.json`) instead of `claude`. Use it by
71	     selecting the `:ccs` composite: e.g. `/sptc:live` / `/sptc:ready` under `--adapter claude-spt:ccs`,
72	     or `spt endpoint run --adapter claude-spt:ccs`. Sanity-check `command -v ccs`; if `~/.ccs` exists
73	     but `ccs` is not on PATH, point the user at their ccs install's bin dir. (No action needed if
74	     they don't want ccs — base `claude-spt` is unaffected.)

       `manifest.toml` + `strings/` + the native tool binaries) from the repo's GitHub release,
       extracts it to the durable adapter home, and registers it. Add `--tag <ver>` to pin a version
       (omit for latest). Re-running with a newer `--tag` is a manual re-acquire. `adapter add` is
       manifest-first (an invalid manifest registers nothing). (v1 ships **windows + linux** assets.
       Recommended path — straight from the monorepo, no dedicated repo. Needs the spt release that
       carries `--release`; the older `--github <root-manifest-repo>` is the alternative.)
       <!-- [doc->REQ-DIST-ADAPTER-PEROS] -->

3. **Verify activation.** Re-run `spt adapter list`: `claude-spt` must now appear **active** (no
   `deregistered`). Spot-check a profile resolves: `spt adapter get-string claude-spt:live adapter_label`
   (any shipped profile). Report the active state.

4. **Tool binaries on PATH (feature prerequisite + interim copy-mode fix).** The `[digest]` extractor
   (`claude-spt-digest`) and the Psyche runner (`claude-spt-psyche`) are invoked by **bare name** →
   resolved from PATH at runtime. Activation registers the manifest, but session-digest + LiveAgent
   Psyche only **function** once those two binaries resolve. Check: `command -v claude-spt-digest`
   and `command -v claude-spt-psyche`.
   - If both resolve → done.
   - If they MISS **after an `--release` activation**: the binaries shipped in the `adapter.spt` and
     extracted **beside the manifest** in the adapter's install dir, but `--release` copy-mode does
     not place them on PATH. **Interim fix:** find the extract dir (the `from …` path in
     `spt adapter list`, e.g. `…/adapters/_github/<safe>/`) and copy `claude-spt-digest` +
     `claude-spt-psyche` from there into a directory already on PATH (the spt bin dir — same dir as
     `spt` itself — works). Re-check `command -v`.
   - *(This interim step retires once spt-core resolves adapter binaries against the install dir
     before PATH — REQ-INSTALL-9, doyle. Until then, place them on PATH.)*

5. **ccs wiring (optional — SCOPE setup #7).** Detect `~/.ccs`:
   - **Present** → ccs is installed. The shipped **`claude-spt:ccs`** profile leaf-replaces the live
     session command with `ccs` (a drop-in for `claude`), so live/ready agents can run on ccs's
     configured backends (glm/kimi/custom from `~/.ccs/config.json`) instead of `claude`. Use it by
     selecting the `:ccs` composite: e.g. `/sptc:live` / `/sptc:ready` under `--adapter claude-spt:ccs`,
     or `spt endpoint run --adapter claude-spt:ccs`. Sanity-check `command -v ccs`; if `~/.ccs` exists
     but `ccs` is not on PATH, point the user at their ccs install's bin dir. (No action needed if
     they don't want ccs — base `claude-spt` is unaffected.)


Both binaries proven from install-dir. Replace setup.md step 4 (the interim PATH-copy) with the REQ-INSTALL-11-satisfied note. (doyle's message + runbook use REQ-INSTALL-11; setup.md's "REQ-INSTALL-9" is stale.)


Edit

4. **Tool binaries on PATH (feature prerequisite + interim copy-mode fix).** The `[digest]` extractor
   (`claude-spt-digest`) and the Psyche runner (`claude-spt-psyche`) are invoked by **bare name** →
   resolved from PATH at runtime. Activation registers the manifest, but session-digest + LiveAgent
   Psyche only **function** once those two binaries resolve. Check: `command -v claude-spt-digest`
   and `command -v claude-spt-psyche`.
   - If both resolve → done.
   - If they MISS **after an `--release` activation**: the binaries shipped in the `adapter.spt` and
     extracted **beside the manifest** in the adapter's install dir, but `--release` copy-mode does
     not place them on PATH. **Interim fix:** find the extract dir (the `from …` path in
     `spt adapter list`, e.g. `…/adapters/_github/<safe>/`) and copy `claude-spt-digest` +
     `claude-spt-psyche` from there into a directory already on PATH (the spt bin dir — same dir as
     `spt` itself — works). Re-check `command -v`.
   - *(This interim step retires once spt-core resolves adapter binaries against the install dir
     before PATH — REQ-INSTALL-9, doyle. Until then, place them on PATH.)*

4. **Tool binaries — resolved from the install dir (REQ-INSTALL-11; no PATH copy).** The `[digest]`
   extractor (`claude-spt-digest`) and the Psyche runner (`claude-spt-psyche`) are invoked by **bare
   name**. spt-core resolves them **from the adapter install dir** — the `from …` path in
   `spt adapter list` (e.g. `…/adapters/_github/<safe>/`), where `--release` activation already
   extracted them beside the manifest. **Nothing to do here:** step 2 placed them; no PATH copy is
   needed. Verified on spt **v0.8.1** — session-digest and the daemon-hosted Psyche both resolve the
   binary straight from the install dir with nothing on PATH.
   - *(The legacy F-006 interim PATH-copy step is **retired**: spt-core's install-dir resolution —
     REQ-INSTALL-11, Feature B, landed in spt v0.8.0 — supersedes it. If session-digest or the Psyche
     ever fails to start, confirm the two `.exe`s are present in the install dir above; their absence
     is a packaging defect, not a PATH problem.)*


The file C:\Users\decid\Documents\projects\spt-claude-code\adapter\strings\skills\setup.md has been updated successfully. (file state is current in your context — no need to Read it back)

4. **Tool binaries — resolved from the install dir (REQ-INSTALL-11; no PATH copy).** The `[digest]`
   extractor (`claude-spt-digest`) and the Psyche runner (`claude-spt-psyche`) are invoked by **bare
   name**. spt-core resolves them **from the adapter install dir** — the `from …` path in
   `spt adapter list` (e.g. `…/adapters/_github/<safe>/`), where `--release` activation already
   extracted them beside the manifest. **Nothing to do here:** step 2 placed them; no PATH copy is
   needed. Verified on spt **v0.8.1** — session-digest and the daemon-hosted Psyche both resolve the
   binary straight from the install dir with nothing on PATH.
   - *(The legacy F-006 interim PATH-copy step is **retired**: spt-core's install-dir resolution —
     REQ-INSTALL-11, Feature B, landed in spt v0.8.0 — supersedes it. If session-digest or the Psyche
     ever fails to start, confirm the two `.exe`s are present in the install dir above; their absence
     is a packaging defect, not a PATH problem.)*

# /sptc:setup — operative instructions

> Delivered file-backed via the `claude-spt` adapter `[strings]`
> (`[strings.skills].setup = { file = "skills/setup.md" }`), resolved at injection time. The cplugs
> SKILL.md stays a thin skeleton (ADR-0001).

**Goal:** install or repair spt-core for this session **and ACTIVATE the claude-spt adapter** — the
mid-session installer that covers the gap when no SessionStart bootstrap has fired (a user who
installs the plugin mid-session). Installing the binary is only half the job: a present binary with
a **deregistered** adapter has no profiles/strings/hints/`[digest]`, so `/sptc:*` injection has
nothing to source. Setup must leave the adapter **active**.

<!-- [doc->REQ-SETUP-ACTIVATE] -->

**Do this:**

1. **Binary.** Check whether spt-core is present: `command -v spt && spt --version`.
   - If absent, run the published install-on-demand bootstrap (verbatim against the spt-releases
     contract, `harness-contract/install-on-demand.md`):
     - **POSIX:** `curl -fsSL https://sabermage.github.io/spt-releases/install.sh | sh`
     - **Windows (PowerShell):** `irm https://sabermage.github.io/spt-releases/install.ps1 | iex`
   - `PATH` is not reloaded in the current shell after a fresh install — verify with the absolute
     path for the first call: `"$HOME/.local/bin/spt" --version` (POSIX). Report the version.

2. **Adapter activation (the step a present binary still needs).** Run `spt adapter list` and look
   for `claude-spt`:
   - If `claude-spt` is listed and **not** marked `deregistered` → the adapter is **active**; report
     "adapter active" and go to step 4.
   - If `claude-spt` is **missing or `deregistered`** → **activate** it. Pick the source:
     - **Local dev / dogfooding from a repo checkout** (an `adapter/claude-spt.toml` is present near
       cwd): `spt adapter add ./adapter/claude-spt.toml` (the file-form takes any path + filename).
     - **End-user (plugin only, no repo checkout):** the `.spt` asset carries native binaries, so it
       ships **per-OS** — select the one matching this host. Detect os + arch:
       ```sh
       os=$(uname -s);  case "$os" in MINGW*|MSYS*|CYGWIN*|Windows*) os=windows;; Linux) os=linux;; Darwin) os=macos;; esac
       arch=$(uname -m); case "$arch" in x86_64|amd64) arch=x86_64;; arm64|aarch64) arch=aarch64;; esac
       ```
       then `spt adapter add --release SaberMage/spt-claude-code --asset adapter-$os-$arch.spt` —
       fetches the per-OS `adapter-<os>-<arch>.spt` release asset (a tar whose **root** holds
       `manifest.toml` + `strings/` + the native tool binaries) from the repo's GitHub release,
       extracts it to the durable adapter home, and registers it. Add `--tag <ver>` to pin a version
       (omit for latest). Re-running with a newer `--tag` is a manual re-acquire. `adapter add` is
       manifest-first (an invalid manifest registers nothing). (v1 ships **windows + linux** assets.
       Recommended path — straight from the monorepo, no dedicated repo. Needs the spt release that
       carries `--release`; the older `--github <root-manifest-repo>` is the alternative.)
       <!-- [doc->REQ-DIST-ADAPTER-PEROS] -->

3. **Verify activation.** Re-run `spt adapter list`: `claude-spt` must now appear **active** (no
   `deregistered`). Spot-check a profile resolves: `spt adapter get-string claude-spt:live adapter_label`
   (any shipped profile). Report the active state.

4. **Tool binaries on PATH (feature prerequisite + interim copy-mode fix).** The `[digest]` extractor
   (`claude-spt-digest`) and the Psyche runner (`claude-spt-psyche`) are invoked by **bare name** →
   resolved from PATH at runtime. Activation registers the manifest, but session-digest + LiveAgent
   Psyche only **function** once those two binaries resolve. Check: `command -v claude-spt-digest`
   and `command -v claude-spt-psyche`.
   - If both resolve → done.
   - If they MISS **after an `--release` activation**: the binaries shipped in the `adapter.spt` and
     extracted **beside the manifest** in the adapter's install dir, but `--release` copy-mode does
     not place them on PATH. **Interim fix:** find the extract dir (the `from …` path in
     `spt adapter list`, e.g. `…/adapters/_github/<safe>/`) and copy `claude-spt-digest` +
     `claude-spt-psyche` from there into a directory already on PATH (the spt bin dir — same dir as
     `spt` itself — works). Re-check `command -v`.
   - *(This interim step retires once spt-core resolves adapter binaries against the install dir
     before PATH — REQ-INSTALL-9, doyle. Until then, place them on PATH.)*

5. **ccs wiring (optional — SCOPE setup #7).** Detect `~/.ccs`:
   - **Present** → ccs is installed. The shipped **`claude-spt:ccs`** profile leaf-replaces the live
     session command with `ccs` (a drop-in for `claude`), so live/ready agents can run on ccs's
     configured backends (glm/kimi/custom from `~/.ccs/config.json`) instead of `claude`. Use it by
     selecting the `:ccs` composite: e.g. `/sptc:live` / `/sptc:ready` under `--adapter claude-spt:ccs`,
     or `spt endpoint run --adapter claude-spt:ccs`. Sanity-check `command -v ccs`; if `~/.ccs` exists
     but `ccs` is not on PATH, point the user at their ccs install's bin dir. (No action needed if
     they don't want ccs — base `claude-spt` is unaffected.)
   - **Absent** → ccs is an optional CLI router that lets your spt sessions drive alternate model
     backends (glm/kimi/custom) in place of `claude`. To enable: install ccs (see its docs), then
     re-run `/sptc:setup`. Skip if not wanted.

   <!-- [doc->REQ-SETUP-CCS] -->

6. **Subnet onboarding (optional — SCOPE setup #3/#4).** A **subnet** is the private group of paired
   machines that makes `/sptc:send`, `/sptc:ready`, and live agents work **cross-machine** (local
   single-machine use needs none). Check membership: `spt subnet status` (or bare `spt subnet`).
   - **Already in a subnet** → report it. To invite another machine: `spt subnet show-code` (prints
     the current 6-digit code + `otpauth://` URI + a terminal QR). On the joining machine run
     `spt subnet join <name> --code <code>`.
   - **Not in a subnet** → offer either: **create** the first one — `spt subnet create <name>` (this
     node becomes the seed-holder; prints code/URI/QR) — or **join** an existing one —
     `spt subnet join <name> --code <code>`. Skip if single-machine use is fine.
   - Full verb guidance (status/create/show-code/join + lifecycle) lives in **/sptc:subnet** — route
     there rather than re-explaining.
   - **Elevation:** `create`/`join`/`show-code` are **OS-elevation-gated** (seed-reveal /
     machine-enrollment). Run where elevation can be granted: **Windows** → an elevated (UAC) shell;
     **Linux desktop** → pkexec/polkit or a sudo-capable terminal; **Linux TTY** → inline `sudo`;
     **headless / no-TTY** → print the exact command for the user to run elevated. (Automated
     context-aware elevation is a deeper wave; today, surface the requirement + the exact command.)

   <!-- [doc->REQ-SETUP-SUBNET] -->

After this initial bootstrap + activation, `spt update` handles signed self-updates automatically —
the user does not run setup again. The whole flow is idempotent and safe to re-run.

-4. **Tool binaries on PATH (feature prerequisite + interim copy-mode fix).** The `[digest]` extractor

-   (`claude-spt-digest`) and the Psyche runner (`claude-spt-psyche`) are invoked by **bare name** →

-   resolved from PATH at runtime. Activation registers the manifest, but session-digest + LiveAgent

-   Psyche only **function** once those two binaries resolve. Check: `command -v claude-spt-digest`

-   - If they MISS **after an `--release` activation**: the binaries shipped in the `adapter.spt` and

-     extracted **beside the manifest** in the adapter's install dir, but `--release` copy-mode does

-     not place them on PATH. **Interim fix:** find the extract dir (the `from …` path in

-     `spt adapter list`, e.g. `…/adapters/_github/<safe>/`) and copy `claude-spt-digest` +

-     `claude-spt-psyche` from there into a directory already on PATH (the spt bin dir — same dir as

-     `spt` itself — works). Re-check `command -v`.

-   - *(This interim step retires once spt-core resolves adapter binaries against the install dir

-     before PATH — REQ-INSTALL-9, doyle. Until then, place them on PATH.)*

+4. **Tool binaries — resolved from the install dir (REQ-INSTALL-11; no PATH copy).** The `[digest]`

+   extractor (`claude-spt-digest`) and the Psyche runner (`claude-spt-psyche`) are invoked by **bare

+   name**. spt-core resolves them **from the adapter install dir** — the `from …` path in

+   `spt adapter list` (e.g. `…/adapters/_github/<safe>/`), where `--release` activation already

+   extracted them beside the manifest. **Nothing to do here:** step 2 placed them; no PATH copy is

+   needed. Verified on spt **v0.8.1** — session-digest and the daemon-hosted Psyche both resolve the

+   binary straight from the install dir with nothing on PATH.

+   - *(The legacy F-006 interim PATH-copy step is **retired**: spt-core's install-dir resolution —

+     REQ-INSTALL-11, Feature B, landed in spt v0.8.0 — supersedes it. If session-digest or the Psyche

+     ever fails to start, confirm the two `.exe`s are present in the install dir above; their absence

+     is a packaging defect, not a PATH problem.)*


Now the plugin SKILL.md interim step. Find it.


Live gh_release auto-update test

cplugs republish v0.1.2


Bash

cd "C:\Users\decid\Documents\projects\spt-claude-code"
grep -n "claude-spt-psyche\|claude-spt-digest\|on PATH\|interim\|copy-mode\|REQ-INSTALL\|command -v" plugin/sptc/skills/setup/SKILL.md 2>&1

Locate interim step in plugin SKILL.md


25:1. **Binary.** If spt-core is absent (`command -v spt && spt --version` reports nothing), run the
48:   (no `deregistered`). Then check `command -v claude-spt-digest` and `command -v claude-spt-psyche`
53:     copy-mode doesn't put them on PATH. **Interim:** copy `claude-spt-digest` + `claude-spt-psyche`
54:     from that extract dir into a PATH dir (the `spt` bin dir works); re-check `command -v`.
56:     REQ-INSTALL-9.)*
62:     `spt endpoint run --adapter claude-spt:ccs`). Check `command -v ccs`; if `~/.ccs` exists but `ccs`
63:     isn't on PATH, point the user at their ccs bin dir. No action needed if unwanted (base


46
47	3. **Verify + place tool binaries.** Re-run `spt adapter list` — `claude-spt` must read **active**
48	   (no `deregistered`). Then check `command -v claude-spt-digest` and `command -v claude-spt-psyche`
49	   (the `[digest]`/`[session]` templates invoke them by **bare name from PATH**).
50	   - Both resolve → done.
51	   - MISS after an `--release` activation → the binaries shipped in `adapter.spt` and extracted
52	     **beside the manifest** (the `from …/adapters/_github/<safe>/` path in `spt adapter list`), but
53	     copy-mode doesn't put them on PATH. **Interim:** copy `claude-spt-digest` + `claude-spt-psyche`
54	     from that extract dir into a PATH dir (the `spt` bin dir works); re-check `command -v`.
55	     *(Retires once spt-core resolves adapter binaries against the install dir before PATH —
56	     REQ-INSTALL-9.)*
57

3. **Verify + place tool binaries.** Re-run `spt adapter list` — `claude-spt` must read **active**
   (no `deregistered`). Then check `command -v claude-spt-digest` and `command -v claude-spt-psyche`
   (the `[digest]`/`[session]` templates invoke them by **bare name from PATH**).
   - Both resolve → done.
   - MISS after an `--release` activation → the binaries shipped in `adapter.spt` and extracted
     **beside the manifest** (the `from …/adapters/_github/<safe>/` path in `spt adapter list`), but
     copy-mode doesn't put them on PATH. **Interim:** copy `claude-spt-digest` + `claude-spt-psyche`
     from that extract dir into a PATH dir (the `spt` bin dir works); re-check `command -v`.
     *(Retires once spt-core resolves adapter binaries against the install dir before PATH —
     REQ-INSTALL-9.)*


Edit

3. **Verify + place tool binaries.** Re-run `spt adapter list` — `claude-spt` must read **active**
   (no `deregistered`). Then check `command -v claude-spt-digest` and `command -v claude-spt-psyche`
   (the `[digest]`/`[session]` templates invoke them by **bare name from PATH**).
   - Both resolve → done.
   - MISS after an `--release` activation → the binaries shipped in `adapter.spt` and extracted
     **beside the manifest** (the `from …/adapters/_github/<safe>/` path in `spt adapter list`), but
     copy-mode doesn't put them on PATH. **Interim:** copy `claude-spt-digest` + `claude-spt-psyche`
     from that extract dir into a PATH dir (the `spt` bin dir works); re-check `command -v`.
     *(Retires once spt-core resolves adapter binaries against the install dir before PATH —
     REQ-INSTALL-9.)*

3. **Verify activation.** Re-run `spt adapter list` — `claude-spt` must read **active**
   (no `deregistered`). The `[digest]`/`[session]` templates invoke `claude-spt-digest` +
   `claude-spt-psyche` by **bare name**, and spt-core resolves them **from the adapter install dir**
   (the `from …/adapters/_github/<safe>/` path in `spt adapter list`), where `--release` activation
   already extracted them beside the manifest. **No PATH copy needed** (REQ-INSTALL-11, spt v0.8.0
   Feature B; verified live on v0.8.1 — digest + daemon-hosted Psyche both resolve from the install
   dir). If either ever fails to start, confirm both `.exe`s are present in that install dir — their
   absence is a packaging defect, not a PATH problem. *(Legacy F-006 interim PATH-copy: retired.)*


The file C:\Users\decid\Documents\projects\spt-claude-code\plugin\sptc\skills\setup\SKILL.md has been updated successfully. (file state is current in your context — no need to Read it back)

3. **Verify activation.** Re-run `spt adapter list` — `claude-spt` must read **active**
   (no `deregistered`). The `[digest]`/`[session]` templates invoke `claude-spt-digest` +
   `claude-spt-psyche` by **bare name**, and spt-core resolves them **from the adapter install dir**
   (the `from …/adapters/_github/<safe>/` path in `spt adapter list`), where `--release` activation
   already extracted them beside the manifest. **No PATH copy needed** (REQ-INSTALL-11, spt v0.8.0
   Feature B; verified live on v0.8.1 — digest + daemon-hosted Psyche both resolve from the install
   dir). If either ever fails to start, confirm both `.exe`s are present in that install dir — their
   absence is a packaging defect, not a PATH problem. *(Legacy F-006 interim PATH-copy: retired.)*

---
name: setup
description: |
  Install or repair spt-core AND activate the claude-spt adapter for this Claude Code session
  (mid-session installer + post-install activation).
allowed-tools: [Bash]
---

# /sptc:setup

> **Self-contained by necessity.** Unlike other `/sptc:*` skills, `setup` cannot rely on
> UPS-injection of its body: it runs precisely when spt-core may be **absent**, so
> `spt adapter get-string` (the injection source) is unavailable. The operative steps therefore live
> in this SKILL.md (the floor); the file-backed `[strings.skills].setup` body mirrors them for the
> spt-present repair path. See `docs/adr/0001-distribution-splits-by-volatility.md`.

Covers the mid-session install + activation gap (ADR-0001): a user who installs the plugin mid-session
has not had a SessionStart bootstrap fire, so `/sptc:setup` runs the same invisible-installer
bootstrap to fetch + verify spt-core on demand **and then activates the claude-spt adapter**. A
present binary is not enough: an unregistered/`deregistered` adapter has no profiles/strings/hints/
`[digest]`, so the `/sptc:*` surface is inert until activation.

**Do this:**

1. **Binary.** If spt-core is absent (`command -v spt && spt --version` reports nothing), run the
   published install-on-demand bootstrap (spt-releases `harness-contract/install-on-demand.md`):
   - **POSIX:** `curl -fsSL https://sabermage.github.io/spt-releases/install.sh | sh`
   - **Windows (PowerShell):** `irm https://sabermage.github.io/spt-releases/install.ps1 | iex`

   `PATH` is not reloaded in this shell after a fresh install — verify with the absolute path:
   `"$HOME/.local/bin/spt" --version`. After this, `spt update` handles signed self-updates.

2. **Activate the adapter.** Run `spt adapter list` and find `claude-spt`:
   - Listed and **not** `deregistered` → already active; report it and skip to step 3.
   - Missing or `deregistered` → activate it:
     - **Local dev / dogfooding a repo checkout** (an `adapter/claude-spt.toml` is present near cwd):
       `spt adapter add ./adapter/claude-spt.toml` (the file-form accepts any path + filename).
     - **End-user (plugin only):** the `.spt` carries native binaries, so it ships **per-OS** —
       pick the host's. Detect: `os=$(uname -s)` → MINGW*/MSYS*/CYGWIN*=windows, Linux=linux,
       Darwin=macos; `arch=$(uname -m)` → x86_64/amd64=x86_64, arm64/aarch64=aarch64. Then
       `spt adapter add --release SaberMage/spt-claude-code --asset adapter-$os-$arch.spt` — fetches
       the per-OS `adapter-<os>-<arch>.spt` asset (tar root = `manifest.toml` + `strings/` + native
       tool binaries), extracts to the durable home, registers. `--tag <ver>` pins a version. v1
       ships windows + linux. Recommended (from the monorepo, no dedicated repo); needs the spt
       release carrying `--release`.

3. **Verify + place tool binaries.** Re-run `spt adapter list` — `claude-spt` must read **active**
   (no `deregistered`). Then check `command -v claude-spt-digest` and `command -v claude-spt-psyche`
   (the `[digest]`/`[session]` templates invoke them by **bare name from PATH**).
   - Both resolve → done.
   - MISS after an `--release` activation → the binaries shipped in `adapter.spt` and extracted
     **beside the manifest** (the `from …/adapters/_github/<safe>/` path in `spt adapter list`), but
     copy-mode doesn't put them on PATH. **Interim:** copy `claude-spt-digest` + `claude-spt-psyche`
     from that extract dir into a PATH dir (the `spt` bin dir works); re-check `command -v`.
     *(Retires once spt-core resolves adapter binaries against the install dir before PATH —
     REQ-INSTALL-9.)*

4. **ccs wiring (optional — SCOPE setup #7).** Detect `~/.ccs`:
   - Present → ccs is installed. The shipped `claude-spt:ccs` profile leaf-replaces the session
     command with `ccs` (drop-in for `claude`) → run live/ready agents on ccs backends
     (glm/kimi/custom) via `--adapter claude-spt:ccs` (e.g. `/sptc:live`, `/sptc:ready`,
     `spt endpoint run --adapter claude-spt:ccs`). Check `command -v ccs`; if `~/.ccs` exists but `ccs`
     isn't on PATH, point the user at their ccs bin dir. No action needed if unwanted (base
     `claude-spt` is unaffected).
   - Absent → ccs is an optional CLI router for driving alternate model backends (glm/kimi/custom) in
     place of `claude`. To enable: install ccs (its docs), then re-run `/sptc:setup`. Skip if unwanted.

5. **Subnet onboarding (optional — SCOPE setup #3/#4).** A subnet is the private group of paired
   machines that makes `/sptc:send`, `/sptc:ready`, and live agents work cross-machine (local use
   needs none). Check: `spt subnet status`.
   - In a subnet → to invite a machine: `spt subnet show-code` (6-digit code + URI + QR); on the
     joiner: `spt subnet join <name> --code <code>`.
   - Not in one → offer create (`spt subnet create <name>` — seed-holder; prints code/URI/QR) or join
     (`spt subnet join <name> --code <code>`). Skip if single-machine.
   - Full verb guidance → **/sptc:subnet**. **Elevation:** create/join/show-code are
     OS-elevation-gated — Windows: elevated (UAC) shell; Linux desktop: pkexec/polkit or sudo
     terminal; Linux TTY: inline sudo; headless: print the command for the user to run elevated.

Idempotent and safe to re-run — the same bootstrap + activation the SessionStart hook performs.

-3. **Verify + place tool binaries.** Re-run `spt adapter list` — `claude-spt` must read **active**

-   (no `deregistered`). Then check `command -v claude-spt-digest` and `command -v claude-spt-psyche`

-   (the `[digest]`/`[session]` templates invoke them by **bare name from PATH**).

-   - MISS after an `--release` activation → the binaries shipped in `adapter.spt` and extracted

-     **beside the manifest** (the `from …/adapters/_github/<safe>/` path in `spt adapter list`), but

-     copy-mode doesn't put them on PATH. **Interim:** copy `claude-spt-digest` + `claude-spt-psyche`

-     from that extract dir into a PATH dir (the `spt` bin dir works); re-check `command -v`.

-     *(Retires once spt-core resolves adapter binaries against the install dir before PATH —

+3. **Verify activation.** Re-run `spt adapter list` — `claude-spt` must read **active**

+   (no `deregistered`). The `[digest]`/`[session]` templates invoke `claude-spt-digest` +

+   (the `from …/adapters/_github/<safe>/` path in `spt adapter list`), where `--release` activation

+   already extracted them beside the manifest. **No PATH copy needed** (REQ-INSTALL-11, spt v0.8.0

+   Feature B; verified live on v0.8.1 — digest + daemon-hosted Psyche both resolve from the install

+   dir). If either ever fails to start, confirm both `.exe`s are present in that install dir — their

+   absence is a packaging defect, not a PATH problem. *(Legacy F-006 interim PATH-copy: retired.)*


Both setup bodies updated. Delete the retired interim copies, then sweep for any other F-006/interim references to keep docs consistent.


Bash

cd "C:\Users\decid\Documents\projects\spt-claude-code"
BIN=~/AppData/Local/spt-core/bin
rm -f "$BIN/claude-spt-digest.exe.OFF" "$BIN/claude-spt-psyche.exe.OFF" 2>&1 && echo "removed retired .OFF interim copies"
echo "=== remaining F-006 / interim-PATH-copy references in repo docs ==="
grep -rn "F-006\|interim" --include=*.md . 2>/dev/null | grep -viE "^\./\.git" | grep -iE "F-006|interim PATH|PATH-copy|copy.*PATH|copy-mode|on PATH" | head -30

Remove .OFF copies + sweep F-006 references


removed retired .OFF interim copies
=== remaining F-006 / interim-PATH-copy references in repo docs ===
./adapter/strings/skills/setup.md:59:   - *(The legacy F-006 interim PATH-copy step is **retired**: spt-core's install-dir resolution —
./docs/RELEASE-RUNBOOK.md:181:  / REQ-INSTALL-11** resolves them from the adapter install dir (F-006). The archive carries them so
./docs/SPT-CORE-FINDINGS.md:16:| F-006 | 2026-06-15 | **Feature B SHIPPED in v0.8.0 (REQ-INSTALL-11); interim STILL IN PLACE** — install-dir resolution can't be dogfood-proven until the daemon-hosted psyche actually spawns (blocked by the v0.8.0 psyche-spawn-via-acceptance-harness gap; keep the interim until then) | `--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) |
./docs/SPT-CORE-FINDINGS.md:451:## F-006 — `--release` bundles adapter binaries but bare-name templates don't resolve them (copy-mode)
./docs/SPT-CORE-FINDINGS.md:566:  - Binary resolution: the psyche_init command's bare `claude-spt-psyche` resolves via the F-006 PATH
./docs/SPT-CORE-FINDINGS.md:647:  F-006 PATH interim STAYS until v0.8.1. doyle pings on v0.8.1 → re-run the proof.
./plugin/sptc/skills/setup/SKILL.md:54:   absence is a packaging defect, not a PATH problem. *(Legacy F-006 interim PATH-copy: retired.)*
./SETUP-SLICE-PLAN.md:147:  templates resolve from PATH only (**F-006**); interim = `/sptc:setup` copies them onto a PATH dir


`docs/SPT-CORE-FINDINGS.md` tracks F-006 (and is the right home for the new doyle findings since I couldn't deliver them live). Let me read its structure to update F-006→resolved and append the two new findings.