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

# /sptc:live — operative instructions

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

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

**How a session becomes live (no "go-live" verb):** LiveAgent vs ReadyAgent is gated entirely by the
resolved manifest declaring `[session.psyche_init]`. Base `claude-spt` declares none (= ReadyAgent,
like `/sptc:ready`); the `claude-spt:live` profile overlays it (= LiveAgent). Bringing the perch up
under the `:live` composite is what tells the spt-core daemon to host this endpoint's Psyche. The
Psyche is **daemon-managed by contract** — do NOT try to start, poll, or tear down the Psyche
yourself; the daemon owns its whole lifecycle off the perch's online status (so the companion
survives a relay restart).

---

## Bringup — do this

1. **Ensure `spt` is available.** If `spt` is not on `PATH`, run `/sptc:setup` first, then continue.

2. **Pick the perch id.** Use a short lowercase id, or reuse this session's id from `spt whoami`. Call
   it `<id>`. Use this session's id from `spt whoami` for `<sid>` (the session-id).

3. **Run the live relay as a single PERSISTENT background task** — Claude Code's **Monitor** tool (a
   long-running listener that keeps the process alive and re-fires per event WITHOUT terminating).
   This one resident process IS the live delivery pipe. It seeds the `:live` composite and binds the
   relay in the SAME process so both share one parent-pid anchor (see the INTERIM note below). The
   task body:

   ```sh
   # Anchor pid: spt probes WINDOWS pids. From git-bash, $$ is the MSYS pid (reads as a dead anchor);
   # use the WINPID column from `ps` (col 4) when present, else $$ is already the real pid.
   ANCHOR=$(ps -p $$ 2>/dev/null | awk 'NR==2{print $4}'); case "$ANCHOR" in ''|*[!0-9]*) ANCHOR=$$;; esac
   spt api --adapter claude-spt:live seed   --pid        "$ANCHOR" --session-id "<sid>"
   spt api --adapter claude-spt:live listen --parent-pid "$ANCHOR" "<id>"
   ```

   - The `listen` line **blocks for the session's life**: the spooled backlog drains first, then each
     delivery streams to stdout as it arrives.
   - Do **not** use `--once` — that drains the backlog and forwards a single delivery, then exits (the
     degenerate path for a harness with no long-running listener). It never sustains a live session.
   - On a registered adapter, `--adapter claude-spt:live` resolves the registered manifest, so no
     `--manifest` is needed.

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

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

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

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

> **INTERIM (PREP-4 / spt-core v0.9.0).** The seed+listen-chained-in-one-process step exists only
> because today's seed and listen must share a parent-pid anchor. Once spt-core ships the
> adapter-agnostic seed (SessionStart seeds by pid; `api listen` resolves the owning adapter/profile
> by pid), this collapses to a bare `spt api listen <id>` under Monitor — no shared-pid chaining and
> no `--adapter`. Do not pre-build that path; it activates on doyle's v0.9.0 ship.

---

## OUTPUT DISCIPLINE — what the user sees

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

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

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

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

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

> Delivered file-backed via the `claude-spt` adapter `[strings]`

-> SKILL.md stays a thin skeleton (ADR-0001).

+> SKILL.md stays a thin skeleton (ADR-0001). **This injection is self-contained** — everything you

+> need to go live is below; you never need to run a `how-to` topic or any external lookup.

-**How a session becomes live (no "go-live" verb — doyle 2026-06-15, traced spt-core):** LiveAgent vs

-ReadyAgent is gated entirely by the resolved manifest declaring `[session.psyche_init]`. Base

-`claude-spt` declares none (= ReadyAgent, like `/sptc:ready`); the `claude-spt:live` profile overlays

-it (= LiveAgent). Selecting the `:live` composite at seed time is what tells the spt-core daemon to

-spawn this endpoint's Psyche. The Psyche is **daemon-managed by contract** — do NOT try to start,

-poll, or tear down the Psyche yourself; the daemon owns its whole lifecycle.

+**How a session becomes live (no "go-live" verb):** LiveAgent vs ReadyAgent is gated entirely by the

+resolved manifest declaring `[session.psyche_init]`. Base `claude-spt` declares none (= ReadyAgent,

+like `/sptc:ready`); the `claude-spt:live` profile overlays it (= LiveAgent). Bringing the perch up

+under the `:live` composite is what tells the spt-core daemon to host this endpoint's Psyche. The

+Psyche is **daemon-managed by contract** — do NOT try to start, poll, or tear down the Psyche

+yourself; the daemon owns its whole lifecycle off the perch's online status (so the companion

-1. If `spt` is not on `PATH`, run `/sptc:setup` first.

-2. Read the canonical, always-current guidance: run **`spt how-to live`** and follow it (the published

-   topic shipped in spt v0.8.0 — F-007 resolved). The operative summary below mirrors it as the floor.

-   - Pick a short lowercase perch id, or reuse this session's id from `spt whoami`. Call it `<id>`.

-   - Seed/select the LiveAgent profile so the daemon resolves `[session.psyche_init]` and spawns the

-     Psyche: bring the perch up under the **`claude-spt:live`** composite adapter (the `:live` overlay),

-     not the bare `claude-spt`. (The SessionStart seed uses the base adapter for a ReadyAgent;

-     `/sptc:live` is the one path that activates the `:live` composite.)

-   - Run the **delivery relay** as a long-running **background task** (CC's Monitor) and read its

-     stdout: `spt api --adapter claude-spt:live listen <id>`. It **blocks** for the session's life —

-     the spooled backlog drains first, then each delivery streams in as it arrives. This resident

-4. **Poll/relay reconcile (important — avoids double-delivery):** while the Monitor relay is up it is

-   the *single* delivery pipe. The `UserPromptSubmit` `api poll` hook must NOT also drain — the relay

-   already owns the stream. Treat a running relay as authoritative; the per-prompt poll no-ops while

-   it is live, and resumes only if the relay goes down.

-5. Delivery shape on the relay stream is the `<EVENT type="msg" from="<sender>">body</EVENT>` envelope

-   (body HTML-escaped, newlines as `<br>`). To reply, pipe the body to `spt send --reply-to <sender>`.

-6. **Commune across boundaries:** as a live agent you now have a Psyche — use `/sptc:commune` to push

-   a context delta before a `/clear` or compact so your resume is briefed. To go offline gracefully

-   (tears the Psyche down with the perch), use `/sptc:force-stop` (`spt endpoint shutdown`).

+1. **Ensure `spt` is available.** If `spt` is not on `PATH`, run `/sptc:setup` first, then continue.

+2. **Pick the perch id.** Use a short lowercase id, or reuse this session's id from `spt whoami`. Call

+   it `<id>`. Use this session's id from `spt whoami` for `<sid>` (the session-id).

+3. **Run the live relay as a single PERSISTENT background task** — Claude Code's **Monitor** tool (a

+   long-running listener that keeps the process alive and re-fires per event WITHOUT terminating).

+   This one resident process IS the live delivery pipe. It seeds the `:live` composite and binds the

+   relay in the SAME process so both share one parent-pid anchor (see the INTERIM note below). The

+   # Anchor pid: spt probes WINDOWS pids. From git-bash, $$ is the MSYS pid (reads as a dead anchor);

+   # use the WINPID column from `ps` (col 4) when present, else $$ is already the real pid.

+   ANCHOR=$(ps -p $$ 2>/dev/null | awk 'NR==2{print $4}'); case "$ANCHOR" in ''|*[!0-9]*) ANCHOR=$$;; esac

+   spt api --adapter claude-spt:live seed   --pid        "$ANCHOR" --session-id "<sid>"

+   spt api --adapter claude-spt:live listen --parent-pid "$ANCHOR" "<id>"

+   - The `listen` line **blocks for the session's life**: the spooled backlog drains first, then each

+     delivery streams to stdout as it arrives.

+   - Do **not** use `--once` — that drains the backlog and forwards a single delivery, then exits (the

+     degenerate path for a harness with no long-running listener). It never sustains a live session.

+   - On a registered adapter, `--adapter claude-spt:live` resolves the registered manifest, so no

+4. **Bind-before-send / readiness.** Watch the relay's output for the bringup markers (see OUTPUT

+   DISCIPLINE): `BOUND:<id>` (perch established) then `READY:<id>` (the relay is streaming). Only once

+   `READY:<id>` appears is the live pipe up — do not announce LIVE before then.

+5. **Poll/relay reconcile (avoids double-delivery).** While the Monitor relay is up it is the *single*

+   delivery pipe — treat it as authoritative. The `UserPromptSubmit` `api poll` hook must NOT also

+   drain; the per-prompt poll no-ops while the relay is live and resumes only if the relay goes down.

+6. **Delivery + reply shape.** Inbound arrives on the relay stream as the

+   `<EVENT type="msg" from="<sender>">body</EVENT>` envelope (body HTML-escaped, newlines as `<br>`).

+   To reply, pipe the body to `spt send --reply-to <sender>`.

+7. **Across boundaries.** As a live agent you now have a Psyche — use `/sptc:commune` to push a

+   context delta before a `/clear` or compact so your resume is briefed. On a session boundary,

+   re-fire the same relay (step 3) — the seed bridges the new session to the same perch and the relay

+   resumes. To go offline gracefully (tears the Psyche down with the perch), use `/sptc:force-stop`

+> **INTERIM (PREP-4 / spt-core v0.9.0).** The seed+listen-chained-in-one-process step exists only

+> because today's seed and listen must share a parent-pid anchor. Once spt-core ships the

+> adapter-agnostic seed (SessionStart seeds by pid; `api listen` resolves the owning adapter/profile

+> by pid), this collapses to a bare `spt api listen <id>` under Monitor — no shared-pid chaining and

+> no `--adapter`. Do not pre-build that path; it activates on doyle's v0.9.0 ship.

+## OUTPUT DISCIPLINE — what the user sees

+The relay and seed emit machine markers on stdout/stderr: `SEEDED:<pid>`, `NO_SEED:<pid>`,

+`STALE_SEED:<pid>`, `BOUND:<id>`, `READY:<id>`, plus any raw token / step lines. **These are an

+internal parse contract — you read them to drive bringup; you NEVER echo them to the user.** Do not

+**The ONLY user-facing surface for going live is the canonical LIVE block below.** Emit it verbatim

+(substituting `<id>`) once `READY:<id>` is observed — and nothing else from the bringup:

+**LIVE.** Session `<id>` is now a LiveAgent (Psyche-backed).

+- Perch `<id>` — status online; Psyche companion hosted by the daemon.

+- Reachable — other agents reach you with `/sptc:send <id>` (or `spt send <id>`).

+- Inbound — streams into this session live; the Monitor relay is your delivery pipe.

+- Reply — pipe a reply body to `spt send --reply-to <sender>`.

+- Across resets — `/sptc:commune` before a `/clear`/compact; `/sptc:force-stop` to go offline (tears down the Psyche).

+If bringup fails (e.g. `NO_SEED`/`STALE_SEED` and no `READY:<id>` within ~25s), do NOT show the LIVE

+block — report a short plain-language failure ("could not bring the live perch up") and the most

+likely cause (stale pid anchor, or run `/sptc:setup`), still without dumping the raw markers.

# /sptc:live — operative instructions

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

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

**How a session becomes live (no "go-live" verb — doyle 2026-06-15, traced spt-core):** LiveAgent vs
ReadyAgent is gated entirely by the resolved manifest declaring `[session.psyche_init]`. Base
`claude-spt` declares none (= ReadyAgent, like `/sptc:ready`); the `claude-spt:live` profile overlays
it (= LiveAgent). Selecting the `:live` composite at seed time is what tells the spt-core daemon to
spawn this endpoint's Psyche. The Psyche is **daemon-managed by contract** — do NOT try to start,
poll, or tear down the Psyche yourself; the daemon owns its whole lifecycle.

**Do this:**

1. If `spt` is not on `PATH`, run `/sptc:setup` first.
2. Read the canonical, always-current guidance: run **`spt how-to live`** and follow it (the published
   topic shipped in spt v0.8.0 — F-007 resolved). The operative summary below mirrors it as the floor.
3. Operative summary:
   - Pick a short lowercase perch id, or reuse this session's id from `spt whoami`. Call it `<id>`.
   - Seed/select the LiveAgent profile so the daemon resolves `[session.psyche_init]` and spawns the
     Psyche: bring the perch up under the **`claude-spt:live`** composite adapter (the `:live` overlay),
     not the bare `claude-spt`. (The SessionStart seed uses the base adapter for a ReadyAgent;
     `/sptc:live` is the one path that activates the `:live` composite.)
   - Run the **delivery relay** as a long-running **background task** (CC's Monitor) and read its
     stdout: `spt api --adapter claude-spt:live listen <id>`. It **blocks** for the session's life —
     the spooled backlog drains first, then each delivery streams in as it arrives. This resident
     relay IS the live delivery pipe.
4. **Poll/relay reconcile (important — avoids double-delivery):** while the Monitor relay is up it is
   the *single* delivery pipe. The `UserPromptSubmit` `api poll` hook must NOT also drain — the relay
   already owns the stream. Treat a running relay as authoritative; the per-prompt poll no-ops while
   it is live, and resumes only if the relay goes down.
5. Delivery shape on the relay stream is the `<EVENT type="msg" from="<sender>">body</EVENT>` envelope
   (body HTML-escaped, newlines as `<br>`). To reply, pipe the body to `spt send --reply-to <sender>`.
6. **Commune across boundaries:** as a live agent you now have a Psyche — use `/sptc:commune` to push
   a context delta before a `/clear` or compact so your resume is briefed. To go offline gracefully
   (tears the Psyche down with the perch), use `/sptc:force-stop` (`spt endpoint shutdown`).

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


#1+#2 done. Now governance gate: `traceable-reqs check` + manifest schema test.


Bash

cd C:/Users/decid/Documents/projects/spt-claude-code && echo "=== traceable-reqs check ===" && traceable-reqs check 2>&1 | tail -30; echo "EXIT=$?"

Run traceable-reqs check


=== traceable-reqs check ===
  [OK] REQ-DIST-MANIFEST-SCHEMA  required: [doc, impl, unit, int]  stages: +doc +impl +unit +int
       CC adapter manifest validates against spt-core's published manifest.schema.json (from spt-releases)
  [OK] REQ-DIST-PLUGIN-SKELETON  required: [doc, impl, unit]  stages: +doc +impl +unit -int
       Marketplace artifact on cplugs is a thin skeleton: namespaced /sptc:* skill stubs + hooks.json + plugin.json, no embedded logic
  [OK] REQ-DIST-SHORTCUT-BASENAME  required: [doc, impl, unit]  stages: +doc +impl +unit -int
       The adapter manifest brands the `spt endpoint run` launcher shortcut as `cc-<id>` via adapter.shortcut_basename = "cc" (the M12 cc launcher; decoupled from the sptc plugin name, ADR-0001)
  [OK] REQ-DOCS-DRIFT  required: [doc, impl, unit]  stages: +doc +impl +unit -int
       Generated docs (llms.txt) are CI-gated against drift: a deterministic generator's output must match what's checked in, and the book must build
  [OK] REQ-DOCS-SITE  required: [doc, impl]  stages: +doc +impl -unit -int
       docs-site/ builds with mdBook from src/ (themed, Diátaxis-shaped, all-real-content — no placeholders)
  [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
EXIT=0


All green. Now confirm the manifest schema gate still passes with `host_binaries` added.


cd C:/Users/decid/Documents/projects/spt-claude-code && echo "=== manifest-schema test ===" && sh tests/manifest-schema.sh 2>&1 | tail -20; echo "EXIT=$?"; echo "=== manifest-shortcut test ==="; sh tests/manifest-shortcut.sh 2>&1 | tail -10; echo "EXIT=$?"

Run manifest schema + shortcut validation tests


=== manifest-schema test ===
ok   real manifest validates
ok   catches missing [adapter]
ok   catches missing required adapter.min_spt_core_version
ok   catches invalid adapter.kind enum
ok   catches hook missing required fires
ok   catches non-string shortcut_basename
MANIFEST-SCHEMA OK
EXIT=0
=== manifest-shortcut test ===
ok   shortcut_basename = "cc" (cc-<id> brand intact)
ok   single shortcut_basename assignment
MANIFEST-SHORTCUT OK
EXIT=0


All gates green (traceable-reqs, manifest-schema, shortcut). Commit with evidence + perri trailer.


cd C:/Users/decid/Documents/projects/spt-claude-code && git add adapter/claude-spt.toml adapter/strings/skills/live.md && git status --short && echo "=== diff stat ===" && git diff --cached --stat

Stage changes and show summary


M  adapter/claude-spt.toml
M  adapter/strings/skills/live.md
=== diff stat ===
 adapter/claude-spt.toml        |   7 +++
 adapter/strings/skills/live.md | 120 ++++++++++++++++++++++++++++++-----------
 2 files changed, 95 insertions(+), 32 deletions(-)


cd C:/Users/decid/Documents/projects/spt-claude-code && git commit -q -F - <<'EOF'
feat(live): self-contained /sptc:live injection + humanized output; stage host_binaries

doyle feedback (2026-06-16) on the v0.2.0 live bringup, DO-NOW + PREP items
independent of spt-core:

DO-NOW 1 — self-contained skill injection (kill how-to redirect):
- Rewrite adapter/strings/skills/live.md to fold the FULL bringup recipe inline.
  Deletes the `spt how-to live` redirect (step 2) entirely — the agent never needs
  an external topic to go live. Inlines the persistent-child Monitor relay recipe:
  WINPID anchor (ps col-4, not MSYS $$), seed+listen chained in one process to
  share the parent-pid anchor, bind-before-send (READY:<id> gate), relay-vs-poll
  reconcile (relay authoritative). The interim chain is tagged PREP-4: it collapses
  to a bare `spt api listen <id>` once spt-core's agnostic seed lands (v0.9.0).

DO-NOW 2 — humanize composed output:
- New OUTPUT DISCIPLINE block: SEEDED/NO_SEED/STALE_SEED/BOUND/READY + raw token
  lines are an internal parse contract, never echoed. Pins the canonical, sole
  user-facing LIVE block (id · status · reachability · reply-how), reproducible
  not improvised, emitted only once READY:<id> is observed.

PREP 3 (staged, not activated) — adapter.host_binaries = ["claude"]:
- Additive pid->binary match-key for spt-core's coming adapter-agnostic resolution
  (ADR-0021). VERIFIED against the live 0.8.2 parser via a throwaway probe
  registration (`spt adapter add` of a renamed copy): parses clean, serde ignores
  the unknown field (ADAPTER_ADD ... Copy registered, exit 0). Manifest-schema +
  shortcut gates still green (Adapter $def allows additional props).

PREP 4 (SessionStart agnostic seed, drop --adapter + the chain) HELD for doyle's
v0.9.0 ship-ping.

REQ-SKILL-LIVE: doc (live.md) + impl (host_binaries) evidence tagged in-commit;
traceable-reqs check green.

Co-authored by: perri
EOF
echo "EXIT=$?" && git log --oneline -1

Commit DO-NOW + PREP-3 work


EXIT=0
87dcda6 feat(live): self-contained /sptc:live injection + humanized output; stage host_binaries


Committed 87dcda6 (not pushed — no push ask). Report to doyle.


cd C:/Users/decid/Documents/projects/spt-claude-code && "$OWL" send --reply-to doyle doyle perri <<'EOF'
perri — DONE (commit 87dcda6, local on main; not pushed pending release call):

DO-NOW 1 ✅ — adapter/strings/skills/live.md rewritten self-contained. `spt how-to live` redirect DELETED. Full recipe inlined: persistent-child Monitor relay, WINPID anchor, seed+listen chained-in-one-process (shared parent-pid), READY:<id> bind-before-send gate, relay-authoritative poll reconcile. Interim chain tagged PREP-4 (collapses to bare `spt api listen <id>` on agnostic seed).

DO-NOW 2 ✅ — OUTPUT DISCIPLINE block added: SEEDED/NO_SEED/STALE_SEED/BOUND/READY + raw tokens = internal parse contract, never echoed. Canonical LIVE block pinned (id · status · reachability · reply-how), emitted only post-READY. Failure path reports plain-language, no raw markers.

PREP 3 ✅ STAGED — host_binaries = ["claude"] in [adapter]. PREP-3 caveat CLEARED: verified against the LIVE 0.8.2 parser (not just the JSON schema) via throwaway probe registration — `spt adapter add` of a renamed copy parsed CLEAN, serde silently ignored the unknown field (ADAPTER_ADD:...:Copy registered, exit 0; probe removed). 0.8.2 does NOT choke. No finding. Manifest-schema + shortcut gates green.

PREP 4 ⏸ HELD for your v0.9.0 ship-ping (SessionStart bare agnostic seed, drop --adapter + the chain, `spt adapter use claude-spt[:profile]` in /sptc:setup).

Gate: traceable-reqs check GREEN (REQ-SKILL-LIVE doc+impl tagged in-commit). No v0.2.1 needed — these are injection/manifest-staging changes; they ride the next adapter release (or sooner if you want a point bump). Your call on timing. Standing by for v0.9.0.
EOF

Report completion to doyle


➜ REPLIED:doyle


Work complete + reported. Brief the Psyche with a commune delta (advances state past last session wrap).


Write

DELTA (2026-06-16, post-wrap) — doyle feedback on v0.2.0 live bringup actioned.

doyle reconciled /sptc:live v0.2.0 with the operator (full grill vs CONTEXT.md). Bringup
diverges from intended LEGACY PARITY, but MOST root causes are spt-core gaps todlando is now
fixing (~v0.9.0) — NOT adapter faults. Split into NOW (adapter-independent) vs BLOCKED.

DONE this session — commit 87dcda6 (local on main, NOT pushed):
- DO-NOW 1: adapter/strings/skills/live.md rewritten SELF-CONTAINED. Deleted the `spt how-to
  live` redirect; inlined the full bringup recipe (persistent-child Monitor relay, WINPID
  anchor, seed+listen chained-one-process, READY:<id> bind-before-send, relay-authoritative
  poll reconcile). Interim chain tagged PREP-4.
- DO-NOW 2: OUTPUT DISCIPLINE block — SEEDED/NO_SEED/STALE_SEED/BOUND/READY + raw tokens are
  internal parse contract, NEVER echoed. Canonical LIVE block pinned (id·status·reach·reply),
  emitted only post-READY. My call, no doyle sign-off needed.
- PREP 3 STAGED: adapter.host_binaries = ["claude"] in [adapter]. Caveat CLEARED — verified
  against LIVE 0.8.2 parser (throwaway probe `spt adapter add` of a renamed copy parsed clean,
  serde ignored unknown field, exit 0). No finding. Schema + shortcut + traceable-reqs GREEN.

PENDING — PREP 4 HELD for doyle's v0.9.0 ship-ping:
- COMING in spt-core v0.9.0 (ADR-0021, CONTEXT §170-186): --adapter becomes OPTIONAL on api
  group; agnostic seed (drops --adapter from SessionStart seed); [adapter] host_binaries read
  as the pid->binary match-key; `spt adapter use <adapter>[:profile]`; humanized direct-user
  CLI output.
- On ship: switch SessionStart to bare `spt api seed --pid <pid> --session-id <sid>` (drop
  --adapter), drop the seed+listen chain (by-pid resolution removes shared-pid need), add
  `spt adapter use claude-spt[:profile]` once-per-host-binary to /sptc:setup. Then rewrite the
  PREP-4 interim note out of live.md. DO NOT pre-build.

Intended model (legacy parity): `$LIVE start <id>` -> `$SPT listen <id>` no --adapter;
SessionStart = adapter-agnostic `spt api seed --pid --session-id`; `api listen` self-resolves
owning adapter by parent pid (pid->exe basename->host_binaries->active-profile->registered_at_ms).

No v0.2.1 cut — injection/manifest-staging only; rides next adapter release (doyle's timing
call). Still on legacy spt plugin 1.11.25; succession flip still gated. Old open thread
unchanged: psyche runner calls `claude` by bare name, not on persistent PATH — untested on
fresh-logon (verify item, not yet bitten).


File created successfully at: C:\Users\decid\Documents\projects\spt-claude-code\.claude\perri-commune.md (file state is current in your context — no need to Read it back)

DELTA (2026-06-16, post-wrap) — doyle feedback on v0.2.0 live bringup actioned.

doyle reconciled /sptc:live v0.2.0 with the operator (full grill vs CONTEXT.md). Bringup
diverges from intended LEGACY PARITY, but MOST root causes are spt-core gaps todlando is now
fixing (~v0.9.0) — NOT adapter faults. Split into NOW (adapter-independent) vs BLOCKED.

DONE this session — commit 87dcda6 (local on main, NOT pushed):
- DO-NOW 1: adapter/strings/skills/live.md rewritten SELF-CONTAINED. Deleted the `spt how-to
  live` redirect; inlined the full bringup recipe (persistent-child Monitor relay, WINPID
  anchor, seed+listen chained-one-process, READY:<id> bind-before-send, relay-authoritative
  poll reconcile). Interim chain tagged PREP-4.
- DO-NOW 2: OUTPUT DISCIPLINE block — SEEDED/NO_SEED/STALE_SEED/BOUND/READY + raw tokens are
  internal parse contract, NEVER echoed. Canonical LIVE block pinned (id·status·reach·reply),
  emitted only post-READY. My call, no doyle sign-off needed.
- PREP 3 STAGED: adapter.host_binaries = ["claude"] in [adapter]. Caveat CLEARED — verified
  against LIVE 0.8.2 parser (throwaway probe `spt adapter add` of a renamed copy parsed clean,
  serde ignored unknown field, exit 0). No finding. Schema + shortcut + traceable-reqs GREEN.

PENDING — PREP 4 HELD for doyle's v0.9.0 ship-ping:
- COMING in spt-core v0.9.0 (ADR-0021, CONTEXT §170-186): --adapter becomes OPTIONAL on api
  group; agnostic seed (drops --adapter from SessionStart seed); [adapter] host_binaries read
  as the pid->binary match-key; `spt adapter use <adapter>[:profile]`; humanized direct-user
  CLI output.
- On ship: switch SessionStart to bare `spt api seed --pid <pid> --session-id <sid>` (drop
  --adapter), drop the seed+listen chain (by-pid resolution removes shared-pid need), add
  `spt adapter use claude-spt[:profile]` once-per-host-binary to /sptc:setup. Then rewrite the
  PREP-4 interim note out of live.md. DO NOT pre-build.

Intended model (legacy parity): `$LIVE start <id>` -> `$SPT listen <id>` no --adapter;
SessionStart = adapter-agnostic `spt api seed --pid --session-id`; `api listen` self-resolves
owning adapter by parent pid (pid->exe basename->host_binaries->active-profile->registered_at_ms).

No v0.2.1 cut — injection/manifest-staging only; rides next adapter release (doyle's timing
call). Still on legacy spt plugin 1.11.25; succession flip still gated. Old open thread
unchanged: psyche runner calls `claude` by bare name, not on persistent PATH — untested on
fresh-logon (verify item, not yet bitten).


Commune dropped (Psyche ingests + deletes it). Work complete.

## Done — doyle feedback actioned (commit 87dcda6, local on main, unpushed)

**DO-NOW 1** — `live.md` self-contained. Killed `spt how-to live` redirect; inlined full Monitor-relay recipe (WINPID anchor, seed+listen chained, READY gate, poll reconcile). Chain tagged PREP-4.

**DO-NOW 2** — OUTPUT DISCIPLINE block. SEEDED/NO_SEED/BOUND/READY + tokens = internal parse contract, never echoed. Canonical LIVE block pinned (id·status·reach·reply), post-READY only.

**PREP 3** — `host_binaries = ["claude"]` staged. Caveat cleared: verified live 0.8.2 parser via throwaway probe `adapter add` — parsed clean, serde ignored unknown field, exit 0. No finding.

**PREP 4** — HELD for doyle v0.9.0 ping (agnostic seed, drop --adapter + chain, `spt adapter use` in setup).

Gates green: traceable-reqs, manifest-schema, shortcut. REQ-SKILL-LIVE doc+impl tagged in-commit. No v0.2.1 — rides next release, doyle's timing call. Reported to doyle; standing by.


<task-notification>
<task-id>bje35dsqf</task-id>
Monitor event: "« spt event »"
<event><EVENT-PART seq="1/4" id="9f7cbc0c" type="msg" from="doyle">EXCELLENT — DO-NOW 1+2 + PREP-3 all green, clean execution. The live-parser probe for PREP-3 (renamed-copy adapter add, serde-ignores-unknown confirmed, probe removed) is exactly the right verification — no finding, host_binaries safe-staged. Canonical LIVE block + output-discipline pinned: that fixes the UX the ope</EVENT-PART>
<EVENT-PART seq="2/4" id="9f7cbc0c">rator flagged.

RELEASE TIMING RULING: ship these NOW as v0.2.1 (your adapter release process). DO-NOW 1+2 are independently valuable — they fix the bad bringup UX (how-to redirect + raw-token leak) the operator hit, and shouldn't wait on v0.9.0. PREP-3 rides along harmless (0.8.2 ignores it). PREP-4 stays held → a later bump aligned</EVENT-PART>
<EVENT-PART seq="3/4" id="9f7cbc0c"> with the v0.9.0 ship-ping. So: v0.2.1 now (DO-NOW 1+2 + PREP-3 staged), PREP-4 in the next bump after v0.9.0. Your call on the exact release mechanics.

Heads-up: operator is actively dogfooding and just hit a SEPARATE spt-core spawn bug on claude-spt:ccs (NUL-in-path + ccs extension resolution on Windows) — I'm diagnosing+fixing that</EVENT-PART>
<EVENT-PART seq="4/4" id="9f7cbc0c"> in a worktree now; unrelated to your adapter changes. Ship v0.2.1 when ready.
-- doyle</EVENT-PART></event>
</task-notification>


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


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


doyle ruling: ship **v0.2.1 now** (DO-NOW 1+2 + PREP-3), PREP-4 next bump post-v0.9.0. My call on mechanics. Separate ccs spawn bug is doyle's, unrelated. ACK + investigate release tooling.


Bash

cd C:/Users/decid/Documents/projects/spt-claude-code && "$OWL" send --reply-to doyle doyle perri <<'EOF'
perri — ACK ruling: cutting v0.2.1 now (DO-NOW 1+2 + PREP-3 staged), PREP-4 held for the post-v0.9.0 bump. Noted the separate ccs spawn bug (NUL-in-path + ccs extension resolution on Windows) is yours, in a worktree, unrelated to my changes — won't touch it. Building v0.2.1 (version bump + rebuild per-OS .spt with new manifest/strings, same binaries + CHANGELOG + tag + GH release). Will report when shipped.
EOF
echo "=== plan/version files ==="; ls *PLAN*.md; echo "---"; grep -n 'version' plugin/sptc/.claude-plugin/plugin.json; echo "=== CHANGELOG head ==="; head -30 CHANGELOG.md

ACK doyle + inspect version files and CHANGELOG


➜ REPLIED:doyle
=== plan/version files ===
CI-ACCEPTANCE-PLAN.md
CPLUGS-PREP-PLAN.md
MANIFEST-PARITY-PLAN.md
MDBOOK-PLAN.md
PARITY-PUBLISH-PLAN.md
PEROS-PLAN.md
PEROS-RERELEASE-PLAN.md
SETUP-SLICE-PLAN.md
SKELETON-PLAN.md
SKILLS-SLICE-PLAN.md
---
3:  "version": "0.1.2",
=== CHANGELOG head ===
# Changelog

All notable user-facing changes to the **sptc** plugin (Spacetime adapter for Claude Code).
The format follows [Keep a Changelog](https://keepachangelog.com/); each release section is the
public release body verbatim.

> Each release below is keyed to the **adapter version of truth** (the version you see in
> `/sptc:version` and the GitHub release tag). The cplugs *plugin skeleton* version (`plugin.json`)
> moves on its own slower schedule and may differ.

## [0.2.0] - 2026-06-16

### Fixed
- **Live agents now reliably start their background companion.** Previously a live agent could come
  up marked "online" while its persistent companion silently failed to start, leaving it with no
  running context. The companion now launches and stays resident.

### Changed
- **Simpler setup — no manual PATH step.** The adapter's helper tools are now found automatically
  from where the adapter is installed; `/sptc:setup` no longer asks you to copy anything onto your
  PATH.
- **Automatic adapter updates.** The adapter now updates itself from this project's GitHub releases
  (`spt adapter update`) — logic and instruction changes reach you without a reinstall.

### Added
- **Linux support.** The adapter ships native **Windows and Linux** builds; `/sptc:setup` detects
  your OS and installs the right one.
- **ccs integration.** If you use [ccs](https://github.com/kaitranntt/ccs), `/sptc:setup` wires the
  shipped `claude-spt:ccs` profile so live/ready agents can run on your ccs backends instead of
  `claude`.


1	# Per-OS re-release + cplugs v0.1.2 — JIT plan
2
3	> **Status: DONE (2026-06-16).** Shipped as adapter **v0.2.0** (operator chose 0.2.0 minor +
4	> full-send-incl-publish). GitHub release v0.2.0 with win+linux .spt; auto-update wiring proven
5	> (Copy→Pointer/GhReleaseManaged); cplugs sptc 0.1.2 pushed (8d9c222). See commit a11f545 + the
6	> v074-follow-ups memory. Retained as the worked release-runbook example.
7
8	## Why this release
9	The registered/published adapter is **v0.1.0** — it predates: the greedy-`--prompt` psyche fix
10	(ddf1965), the `[update] gh_release` block, the dropped F-006 interim, per-OS assets, ccs (#7) +
11	subnet (#3/#4) setup waves. End users on v0.1.0 still have the broken psyche + the interim step.
12	This release ships all of it.
13
14	## Scope / tasks
15
16	1. **Rebuild the tool binaries from source** (the psyche fix is in source; the install-dir exe was
17	   hand-deployed during diagnosis — NOT a packaged artifact):
18	   - `sh ci/digest/build.sh && sh ci/psyche/build.sh` (cargo test + release build, Windows native).
19	2. **Pack `adapter-windows-x86_64.spt`**: `sh ci/publish/package-adapter.sh --apply` → `dist/`.
20	3. **Cross-build + pack `adapter-linux-x86_64.spt`** (recipe in `docs/RELEASE-RUNBOOK.md` §Per-OS):
21	   - zig @ `~/.sptc-zig/...` on PATH; `cargo zigbuild --release --target x86_64-unknown-linux-gnu`
22	     for BOTH tool crates; then
23	     `SPTC_OS=linux SPTC_ARCH=x86_64 SPTC_TARGET=x86_64-unknown-linux-gnu sh ci/publish/package-adapter.sh --apply`.
24	   - Verify both .spt carry the RIGHT binaries (win=PE, linux=ELF) and validate the manifest.
25	4. **Bump + changelog**: decide version (adapter manifest version — distinct from plugin version).
26	   Add a `## [<ver>] - 2026-06-16` CHANGELOG section (user-facing: psyche live-agent now works; no
27	   more manual PATH-copy in setup; per-OS assets; ccs + subnet setup). Regenerate gated docs
28	   (`sh ci/docs/gen-llms.sh` if needed; `ci/docs/check-docs.sh` must stay green).
29	5. **[OUTWARD-FACING] Cut the GitHub release** on `SaberMage/spt-claude-code`, attach BOTH per-OS
30	   `.spt` assets. Tag triggers docs-publish. **← confirm with operator before this step.**
31	6. **Live gh_release auto-update test (TASK 4)**: the currently-registered adapter is v0.1.0 (no
32	   `[update]`), so first **re-acquire** the new one: `spt adapter add --release SaberMage/spt-claude-code
33	   --tag <newver> --asset adapter-windows-x86_64.spt`. Then confirm `spt adapter update` pulls a
34	   subsequent bump via the declared `[update] gh_release` avenue.
35	7. **cplugs republish v0.1.2 (TASK 5)** — coupled, AFTER the per-OS release (RELEASE-RUNBOOK ordering:
36	   assets first, skeleton bump second, else end-user setup 404s). Bump `plugin.json` version; copy the
37	   skeleton subset (skills/hooks/plugin.json) into the cplugs marketplace clone; `claude plugin install
38	   sptc@cplugs`. Ships the os-detecting setup floor + ccs + subnet + dropped interim.
39
40	## Gate
41	`sh ci/run-gates.sh` green + `traceable-reqs check` green + both .spt validate + (post-publish)
42	`spt adapter add --release …` re-acquires active with the fix.
43
44	## Known context
45	- doyle is OFFLINE — the F-009/F-010 findings (in `docs/SPT-CORE-FINDINGS.md` + commit ddf1965) are
46	  PENDING delivery; retry `spt send doyle --from perri`. The auto-update test (task 4) does NOT need
47	  doyle, but coordinating the spt-core findings does.
48	- The psyche runner calls `claude` by bare name; `claude` (`~/.local/bin`) is NOT on the persistent
49	  logon PATH, so a fresh-logon daemon's psyche seed/pulse turns will no-op (the runner stays resident
50	  but its claude turns fail). Separate from F-006; verify on a real fresh-logon live session — may need
51	  a setup step to put `claude` on the persistent PATH, or the psyche to resolve claude robustly.
52

# Per-OS re-release + cplugs v0.1.2 — JIT plan

> **Status: DONE (2026-06-16).** Shipped as adapter **v0.2.0** (operator chose 0.2.0 minor +
> full-send-incl-publish). GitHub release v0.2.0 with win+linux .spt; auto-update wiring proven
> (Copy→Pointer/GhReleaseManaged); cplugs sptc 0.1.2 pushed (8d9c222). See commit a11f545 + the
> v074-follow-ups memory. Retained as the worked release-runbook example.

## Why this release
The registered/published adapter is **v0.1.0** — it predates: the greedy-`--prompt` psyche fix
(ddf1965), the `[update] gh_release` block, the dropped F-006 interim, per-OS assets, ccs (#7) +
subnet (#3/#4) setup waves. End users on v0.1.0 still have the broken psyche + the interim step.
This release ships all of it.

## Scope / tasks

1. **Rebuild the tool binaries from source** (the psyche fix is in source; the install-dir exe was
   hand-deployed during diagnosis — NOT a packaged artifact):
   - `sh ci/digest/build.sh && sh ci/psyche/build.sh` (cargo test + release build, Windows native).
2. **Pack `adapter-windows-x86_64.spt`**: `sh ci/publish/package-adapter.sh --apply` → `dist/`.
3. **Cross-build + pack `adapter-linux-x86_64.spt`** (recipe in `docs/RELEASE-RUNBOOK.md` §Per-OS):
   - zig @ `~/.sptc-zig/...` on PATH; `cargo zigbuild --release --target x86_64-unknown-linux-gnu`
     for BOTH tool crates; then
     `SPTC_OS=linux SPTC_ARCH=x86_64 SPTC_TARGET=x86_64-unknown-linux-gnu sh ci/publish/package-adapter.sh --apply`.
   - Verify both .spt carry the RIGHT binaries (win=PE, linux=ELF) and validate the manifest.
4. **Bump + changelog**: decide version (adapter manifest version — distinct from plugin version).
   Add a `## [<ver>] - 2026-06-16` CHANGELOG section (user-facing: psyche live-agent now works; no
   more manual PATH-copy in setup; per-OS assets; ccs + subnet setup). Regenerate gated docs
   (`sh ci/docs/gen-llms.sh` if needed; `ci/docs/check-docs.sh` must stay green).
5. **[OUTWARD-FACING] Cut the GitHub release** on `SaberMage/spt-claude-code`, attach BOTH per-OS
   `.spt` assets. Tag triggers docs-publish. **← confirm with operator before this step.**
6. **Live gh_release auto-update test (TASK 4)**: the currently-registered adapter is v0.1.0 (no
   `[update]`), so first **re-acquire** the new one: `spt adapter add --release SaberMage/spt-claude-code
   --tag <newver> --asset adapter-windows-x86_64.spt`. Then confirm `spt adapter update` pulls a
   subsequent bump via the declared `[update] gh_release` avenue.
7. **cplugs republish v0.1.2 (TASK 5)** — coupled, AFTER the per-OS release (RELEASE-RUNBOOK ordering:
   assets first, skeleton bump second, else end-user setup 404s). Bump `plugin.json` version; copy the
   skeleton subset (skills/hooks/plugin.json) into the cplugs marketplace clone; `claude plugin install
   sptc@cplugs`. Ships the os-detecting setup floor + ccs + subnet + dropped interim.

## Gate
`sh ci/run-gates.sh` green + `traceable-reqs check` green + both .spt validate + (post-publish)
`spt adapter add --release …` re-acquires active with the fix.

## Known context
- doyle is OFFLINE — the F-009/F-010 findings (in `docs/SPT-CORE-FINDINGS.md` + commit ddf1965) are
  PENDING delivery; retry `spt send doyle --from perri`. The auto-update test (task 4) does NOT need
  doyle, but coordinating the spt-core findings does.
- The psyche runner calls `claude` by bare name; `claude` (`~/.local/bin`) is NOT on the persistent
  logon PATH, so a fresh-logon daemon's psyche seed/pulse turns will no-op (the runner stays resident
  but its claude turns fail). Separate from F-006; verify on a real fresh-logon live session — may need
  a setup step to put `claude` on the persistent PATH, or the psyche to resolve claude robustly.


Runbook-driven release. Only manifest + strings changed (binaries identical to v0.2.0), and the change is adapter-side not plugin skeleton → cplugs stays 0.1.2, no republish. Read the runbook + build scripts to nail mechanics.


cd C:/Users/decid/Documents/projects/spt-claude-code && echo "=== runbook exists? ==="; ls docs/RELEASE-RUNBOOK.md 2>&1; echo "=== publish scripts ==="; ls ci/publish/ 2>&1; echo "=== run-gates ==="; ls ci/run-gates.sh 2>&1; echo "=== dist current ==="; ls -la dist/

Locate runbook, publish scripts, gates, dist


=== runbook exists? ===
docs/RELEASE-RUNBOOK.md
=== publish scripts ===
package-adapter.sh
package-skeleton.sh
release-acquire-int.sh
validate-skeleton.sh
=== run-gates ===
ci/run-gates.sh
=== dist current ===
total 732
drwxr-xr-x 1 decid 197609      0 Jun 16 17:15 .
drwxr-xr-x 1 decid 197609      0 Jun 16 17:21 ..
-rw-r--r-- 1 decid 197609 468712 Jun 16 17:15 adapter-linux-x86_64.spt
-rw-r--r-- 1 decid 197609 266852 Jun 16 17:15 adapter-windows-x86_64.spt


1	# Release runbook
2
3	> How an spt-claude-code release ships. The spine is fixed (changelog · bump · regenerate
4	> docs · tag · publish · docs publish). **Release here is LIGHT: signing is DELEGATED to the
5	> `spt` binary — there is NO two-key signing ceremony in this project.** spt-claude-code is a
6	> thin adapter; the heavy signed-release machinery lives in spt-core, not here.
7
8	<!-- [<doc>->REQ-EXAMPLE-REL] (illustration; escaped per docs/TRACEABILITY.md) -->
9
10	## Publish targets
11
12	An spt-claude-code release lands in **two places**, by volatility:
13
14	1. **The `SaberMage/cplugs` marketplace** — the thin **skeleton plugin** (namespaced
15	   `/spt:*` skill skeletons, `hooks.json`, the SessionStart bootstrap, `plugin.json`). This
16	   is low-churn: it only changes on **structural** plugin changes, not on logic/instruction
17	   updates.
18	2. **The spt-core adapter registry** — the volatile bulk: the CC adapter **manifest**
19	   (`[digest]` extractor, profiles, strings, hints) **+ binary**. This publish is
20	   **spt-core-conducted** (the same framework that conducts adapter updates), not a plugin
21	   file push.
22
23	## One-time setup
24
25	No signing-key ceremony in this project. **Signing is delegated to the `spt` binary**, which
26	handles adapter manifest/binary integrity through spt-core's own signed-update framework. Keep
27	no release keys here. The only setup is marketplace/registry publish credentials for the two
28	targets above (a `cplugs` push token + whatever the spt-core adapter-registry publish step
29	requires).
30
31	## Per release
32
33	1. **Bump** the version (the plugin `plugin.json` version and/or the adapter manifest version —
34	   note these are distinct numbers; see Notes) if needed; **regenerate generated docs**
35	   (the mdBook `docs-site/` build + `llms.txt` / schema / CLI-help exports); land everything
36	   green.
37	2. **Write the user-facing changelog** — add a `## [<version>] - <date>` section at the top of
38	   `CHANGELOG.md` with **Added / Changed / Fixed** subsections. This section becomes the public
39	   release body verbatim, so it is the changelog every user reads. Rules:
40	   - **User-facing UX only.** What a person using the product notices or does differently. Name
41	     the actual commands / flags / surfaces they touch (`/spt:*` skills, `cc`, `/spt:setup`).
42	   - **No internal lingo** — no requirement ids, internal module names, commit hashes, or
43	     milestone / hazard codes. A reader who has never seen the source must understand every line.
44	   - **Flag breaking changes** prominently under Changed.
45	   - The release **fails loudly** if the tagged version has no `## [<version>]` section — the
46	     changelog is not optional.
47	3. **Tag**: `git tag <vX.Y.Z> && git push origin <vX.Y.Z>`. This triggers:
48	   - the **docs-publish workflow** — build `docs-site/` and publish to GitHub Pages (drift-gated;
49	     see `docs/DOCS-STRATEGY.md`).
50	4. **Publish** (light — signing delegated to `spt`):
51	   - **Skeleton plugin** → push to the `SaberMage/cplugs` marketplace **only when the plugin
52	     skeleton structurally changed** (new/removed skill skeleton, hook wiring, bootstrap, or
53	     `plugin.json`). Most releases do not bump the marketplace.
54	   - **Manifest + binary** → publish through the **spt-core adapter registry**; the `spt`
55	     binary performs signing/integrity as part of spt-core's adapter-update framework. You do
56	     **not** run a separate signing step.
57
58	## cplugs skeleton publish — concrete mechanics
59
60	<!-- [doc->REQ-DIST-PLUGIN-SKELETON] -->
61	The concrete cplugs marketplace steps, captured from the sister project's
62	`claude_skill_owl/docs/DEPLOY.md`. **Take only the SKELETON SUBSET.** spt-claude-code's cplugs
63	target is the **thin skeleton** — `/spt:*` skill skeletons, `hooks.json`, the SessionStart
64	bootstrap, `plugin.json`. **No binary, no manifest in cplugs** — the binary + adapter manifest
65	ride the **spt-core adapter registry** (spt-conducted; the *other* publish target above), so
66	none of owl's binary-lifecycle machinery applies here.
67
68	> **Now scripted (`ci/publish/`).** The validate + stage mechanics below are codified:
69	> `ci/publish/validate-skeleton.sh` is a binary installability gate (valid `plugin.json` with
70	> `name=sptc`; valid `hooks.json` whose referenced wrappers all exist; every skill has a
71	> `SKILL.md`; **no runtime-state / binary / manifest leak in the published surface**) — it runs in
72	> `ci/run-gates.sh` (the `skeleton-validate` gate) and is unit-tested by `tests/skeleton-validate.sh`.
73	> `ci/publish/package-skeleton.sh` codifies the per-bump copy below — validates first, **dry-run by
74	> default**, stages only the skeleton subset, never pushes (the marketplace commit/push stays the
75	> operator's step).
76
77	**One-time marketplace setup:**
78
79	```bash
80	# Clone the marketplace repo
81	git clone https://github.com/SaberMage/cplugs.git ~/.claude/plugins/marketplaces/cplugs
82	# Register a "cplugs" entry in ~/.claude/plugins/known_marketplaces.json
83	#   source: { source: "github", repo: "SaberMage/cplugs" }
84	```
85
86	**Per skeleton bump** (only when the skeleton *structurally* changes — see "Per release"):
87
88	```bash
89	# 1. Bump plugin.json version. The plugin manager compares this to the cached copy and
90	#    SKIPS the update entirely if they match — a stale version = a silent no-update.
91	# 2. Copy skeleton files (NO binary) into the marketplace clone:
92	MARKET=~/.claude/plugins/marketplaces/cplugs/plugins/sptc
93	cp -r skills/*  "$MARKET/skills/"
94	cp -r hooks/*   "$MARKET/hooks/"
95	cp .claude-plugin/plugin.json "$MARKET/.claude-plugin/"
96	# 3. Commit + push the cplugs repo:
97	cd ~/.claude/plugins/marketplaces/cplugs && git add plugins/sptc/ \
98	  && git commit -m "sptc: <change>" && git push
99	```
100
101	**Pointer flip** (the authoritative install-state update):
102
103	```bash
104	claude plugin install sptc@cplugs   # un-orphans + rewrites installed_plugins.json atomically
105	# then, inside Claude Code:
106	/reload-plugins
107	```
108
109	**Gotchas (these DO apply to the skeleton):**
110	- **Never hand-patch `installed_plugins.json`** (`jq`/`sed` are brittle; CC may silently reject).
111	  Use the `claude plugin install` CLI — it's the atomic pointer flip + orphan-marker cleanup.
112	- **No legacy manual-install dir alongside the marketplace install.** A `~/.claude/plugins/<name>/`
113	  regular dir coexisting with the marketplace cache install makes `/plugin` report the plugin
114	  **not installed** (CC enumerates both; the untracked one wins the conflict). Keep the two exclusive.
115	- **Restart the Claude Code session after install** so the SessionStart hook re-runs and repopulates
116	  the plugin's env (`$OWL`/`$LIVE` equivalents) in Bash subprocesses.
117
118	**Explicitly NOT ours** (owl ships a live self-migrating binary; the thin skeleton has none, so
119	skip all of it): `owl.exe` binary sync · the cache targeted-prune + keep-PREVIOUS-version logic ·
120	the seamless binary handoff (owl Phase 18.4/18.5) · `DEPLOY.ps1`'s build/handoff orchestration.
121
122	> **RULED (operator, 2026-06-14) — cplugs plugin name = `sptc`.** CC ties the skill prefix to the
123	> `plugin.json` name (no override), so skills surface as `/sptc:*`. **Succession:** once parity is
124	> proven, flip `plugin.json` name `sptc`→`spt` (skills → `/spt:*`) and retire/rename legacy owl's
125	> cplugs `spt` plugin in the same coordinated move — two plugins cannot share the `spt` name. The
126	> flip is a single substitution `s/sptc/spt/` (plugin dir, `plugin.json` name, marketplace path).
127
128	## adapter manifest publish — the `adapter.spt` release asset
129
130	<!-- [doc->REQ-DIST-ADAPTER-RELEASE] -->
131	The CC adapter manifest (publish target #2) ships to end users as an **`adapter.spt`** GitHub
132	**release asset** on this monorepo, acquired with **`spt adapter add --release SaberMage/spt-claude-code`**
133	(doyle's `--release` source; needs **spt v0.7.3+ / counter 15** — not in 0.7.2). No dedicated
134	adapter repo: the asset is packed straight from `adapter/`.
135
136	- **Pack:** `sh ci/publish/package-adapter.sh` (DRY-RUN) → `--apply` writes
137	  `dist/adapter-<os>-<arch>.spt`. It validates the manifest, requires the built tool binaries (`sh
138	  ci/digest/build.sh && sh ci/psyche/build.sh`), and tars the archive **ROOT** = `manifest.toml`
139	  (renamed from `claude-spt.toml` — `adapter add` is root-only + exact-name), `strings/`, and the two
140	  binaries. Never uploads (operator's step).
141	- **Publish:** attach every per-OS `adapter-<os>-<arch>.spt` to the SAME GitHub release on
142	  `SaberMage/spt-claude-code`. End users `spt adapter add --release SaberMage/spt-claude-code --asset
143	  adapter-<os>-<arch>.spt` (or `--tag <ver>` to pin). `/sptc:setup` derives the host's os/arch and
144	  passes the matching `--asset` automatically.
145	<!-- [doc->REQ-DIST-ADAPTER-PEROS] -->
146	- **Per-OS (REQ-DIST-ADAPTER-PEROS) — the asset carries native binaries, so it is platform-specific.**
147	  v1 ships **windows + linux**. spt's `--release` takes a caller-named `--asset` (default
148	  `adapter.spt`) — it does NOT auto-pick per-OS, so we name + select. Naming: `adapter-<os>-<arch>.spt`
149	  (os ∈ windows|linux|macos, arch ∈ x86_64|aarch64), host-derived from `uname`, overridable with
150	  `SPTC_OS` / `SPTC_ARCH` (+ `SPTC_TARGET` = the cargo target triple for a cross build). Per-OS publish:
151	  - **Windows (native):** `sh ci/digest/build.sh && sh ci/psyche/build.sh && sh
152	    ci/publish/package-adapter.sh --apply` → `dist/adapter-windows-x86_64.spt`.
153	  - **Linux on a Linux host/runner (native):** the identical commands (the build scripts are portable
154	    — cargo, no `.exe`) → `dist/adapter-linux-x86_64.spt`.
155	  - **Linux cross-built FROM Windows (proven 2026-06-16):** bare `cargo build --target
156	    x86_64-unknown-linux-gnu` fails (`error: linker 'cc' not found` — the crate compiles, only the
157	    link needs a Linux linker), so use **`cargo-zigbuild`** (zig supplies the cross-linker):
158	    ```sh
159	    # one-time: install zig (a self-contained binary) + cargo-zigbuild
160	    cargo install cargo-zigbuild
161	    # download zig (e.g. 0.14.1) to a dir OUTSIDE the repo (do NOT keep it under tools/ — it's a
162	    # traceable-reqs scan root and zig's bundled libc C-headers trip the scanner), put zig.exe on PATH:
163	    #   e.g. ~/.sptc-zig/zig-x86_64-windows-0.14.1/zig.exe  →  export PATH="$HOME/.sptc-zig/...:$PATH"
164	    rustup target add x86_64-unknown-linux-gnu
165	    # cross-build both tool crates with zig as the linker
166	    cargo zigbuild --release --target x86_64-unknown-linux-gnu --manifest-path tools/claude-spt-digest/Cargo.toml
167	    cargo zigbuild --release --target x86_64-unknown-linux-gnu --manifest-path tools/claude-spt-psyche/Cargo.toml
168	    # pack the linux asset (SPTC_TARGET points the packer at target/<triple>/release)
169	    SPTC_OS=linux SPTC_ARCH=x86_64 SPTC_TARGET=x86_64-unknown-linux-gnu sh ci/publish/package-adapter.sh --apply
170	    ```
171	    → `dist/adapter-linux-x86_64.spt` carrying real `ELF x86-64 GNU/Linux` binaries (verified).
172	  - Attach BOTH assets to the one release.
173	  - **Coupling (do not skew):** the os-detecting `/sptc:setup` floor (cplugs skeleton + adapter
174	    strings) requests `--asset adapter-<os>-<arch>.spt`, so it must ship **with** a release that
175	    carries those per-OS assets — never before. Sequence: cut the per-OS-asset release FIRST, then
176	    republish the cplugs skeleton (next `plugin.json` bump) that points at it. A skeleton bump ahead
177	    of the assets would 404 end-user setup.
178	- **Binaries (install-dir resolution — REQ-INSTALL-11).** A `--release`/`--github` acquisition extracts
179	  the `.spt` archive's `manifest.toml` + `strings/` **+ both tool binaries** into the adapter install
180	  dir (`…/adapters/_github/<safe>/`). The command templates use **bare names** (`claude-spt-digest`,
181	  `claude-spt-psyche`), which spt-core resolves **from that install dir** (v0.8.0 Feature B /
182	  REQ-INSTALL-11) — **no PATH placement needed** (dogfood-proven on v0.8.1 for both binaries; F-006
183	  RESOLVED, interim retired). The pack therefore MUST carry both binaries (the resolution source). Note:
184	  a plain local-dev `spt adapter add <manifest.toml>` copies manifest + strings only (no binaries in the
185	  install dir), so local-dev runtime still relies on the built binary being on PATH (e.g. the CI ints
186	  prepend `target/release`); the install-dir path is the end-user `--release` story.
187	- **Acquisition only:** `--release` does **not** establish an `[update]` self-update route (our
188	  manifest declares no `[update]` → COPY-mode registration). Re-acquire a newer version by re-running
189	  `--release --tag <newer>`. The signed `file_pull` self-update channel is a separate, later concern.
190
191	## Update path (dual, kept in sync)
192
193	Users receive updates two ways, and both must stay consistent:
194	- **File-pull (the real channel)** — spt-core conducts manifest + binary updates seamlessly;
195	  this is how logic and instruction churn reaches users. Version-of-truth = the
196	  manifest/binary version spt-core tracks (`spt adapter list` / `/spt:version`).
197	- **`claude plugin update` (cautionary, skeleton sync)** — only resyncs the low-churn
198	  marketplace skeleton on the rare structural bump. It is NOT the version-of-truth.
199
200	## Notes
201
202	- **Distinct numbers — never conflate them:** the **plugin (marketplace) version** (in
203	  `plugin.json`, bumps rarely) and the **adapter manifest/binary version** (spt-core-tracked,
204	  the user-visible version-of-truth). They move on independent schedules — the plugin can sit
205	  static across many manifest updates.
206	- **Trust model:** adapter manifest/binary integrity is the `spt` binary's responsibility via
207	  spt-core's signed-update framework — spt-claude-code defines no separate trust ceremony.
208	  (Claude Code has no plugin-file integrity check, which is why the skeleton plugin is safe to
209	  in-place-edit; only old version dirs orphan on update and are GC'd after 7 days.)
210

# Release runbook

> How an spt-claude-code release ships. The spine is fixed (changelog · bump · regenerate
> docs · tag · publish · docs publish). **Release here is LIGHT: signing is DELEGATED to the
> `spt` binary — there is NO two-key signing ceremony in this project.** spt-claude-code is a
> thin adapter; the heavy signed-release machinery lives in spt-core, not here.

<!-- [<doc>->REQ-EXAMPLE-REL] (illustration; escaped per docs/TRACEABILITY.md) -->

## Publish targets

An spt-claude-code release lands in **two places**, by volatility:

1. **The `SaberMage/cplugs` marketplace** — the thin **skeleton plugin** (namespaced
   `/spt:*` skill skeletons, `hooks.json`, the SessionStart bootstrap, `plugin.json`). This
   is low-churn: it only changes on **structural** plugin changes, not on logic/instruction
   updates.
2. **The spt-core adapter registry** — the volatile bulk: the CC adapter **manifest**
   (`[digest]` extractor, profiles, strings, hints) **+ binary**. This publish is
   **spt-core-conducted** (the same framework that conducts adapter updates), not a plugin
   file push.

## One-time setup

No signing-key ceremony in this project. **Signing is delegated to the `spt` binary**, which
handles adapter manifest/binary integrity through spt-core's own signed-update framework. Keep
no release keys here. The only setup is marketplace/registry publish credentials for the two
targets above (a `cplugs` push token + whatever the spt-core adapter-registry publish step
requires).

## Per release

1. **Bump** the version (the plugin `plugin.json` version and/or the adapter manifest version —
   note these are distinct numbers; see Notes) if needed; **regenerate generated docs**
   (the mdBook `docs-site/` build + `llms.txt` / schema / CLI-help exports); land everything
   green.
2. **Write the user-facing changelog** — add a `## [<version>] - <date>` section at the top of
   `CHANGELOG.md` with **Added / Changed / Fixed** subsections. This section becomes the public
   release body verbatim, so it is the changelog every user reads. Rules:
   - **User-facing UX only.** What a person using the product notices or does differently. Name
     the actual commands / flags / surfaces they touch (`/spt:*` skills, `cc`, `/spt:setup`).
   - **No internal lingo** — no requirement ids, internal module names, commit hashes, or
     milestone / hazard codes. A reader who has never seen the source must understand every line.
   - **Flag breaking changes** prominently under Changed.
   - The release **fails loudly** if the tagged version has no `## [<version>]` section — the
     changelog is not optional.
3. **Tag**: `git tag <vX.Y.Z> && git push origin <vX.Y.Z>`. This triggers:
   - the **docs-publish workflow** — build `docs-site/` and publish to GitHub Pages (drift-gated;
     see `docs/DOCS-STRATEGY.md`).
4. **Publish** (light — signing delegated to `spt`):
   - **Skeleton plugin** → push to the `SaberMage/cplugs` marketplace **only when the plugin
     skeleton structurally changed** (new/removed skill skeleton, hook wiring, bootstrap, or
     `plugin.json`). Most releases do not bump the marketplace.
   - **Manifest + binary** → publish through the **spt-core adapter registry**; the `spt`
     binary performs signing/integrity as part of spt-core's adapter-update framework. You do
     **not** run a separate signing step.

## cplugs skeleton publish — concrete mechanics

<!-- [doc->REQ-DIST-PLUGIN-SKELETON] -->
The concrete cplugs marketplace steps, captured from the sister project's
`claude_skill_owl/docs/DEPLOY.md`. **Take only the SKELETON SUBSET.** spt-claude-code's cplugs
target is the **thin skeleton** — `/spt:*` skill skeletons, `hooks.json`, the SessionStart
bootstrap, `plugin.json`. **No binary, no manifest in cplugs** — the binary + adapter manifest
ride the **spt-core adapter registry** (spt-conducted; the *other* publish target above), so
none of owl's binary-lifecycle machinery applies here.

> **Now scripted (`ci/publish/`).** The validate + stage mechanics below are codified:
> `ci/publish/validate-skeleton.sh` is a binary installability gate (valid `plugin.json` with
> `name=sptc`; valid `hooks.json` whose referenced wrappers all exist; every skill has a
> `SKILL.md`; **no runtime-state / binary / manifest leak in the published surface**) — it runs in
> `ci/run-gates.sh` (the `skeleton-validate` gate) and is unit-tested by `tests/skeleton-validate.sh`.
> `ci/publish/package-skeleton.sh` codifies the per-bump copy below — validates first, **dry-run by
> default**, stages only the skeleton subset, never pushes (the marketplace commit/push stays the
> operator's step).

**One-time marketplace setup:**

```bash
# Clone the marketplace repo
git clone https://github.com/SaberMage/cplugs.git ~/.claude/plugins/marketplaces/cplugs
# Register a "cplugs" entry in ~/.claude/plugins/known_marketplaces.json
#   source: { source: "github", repo: "SaberMage/cplugs" }
```

**Per skeleton bump** (only when the skeleton *structurally* changes — see "Per release"):

```bash
# 1. Bump plugin.json version. The plugin manager compares this to the cached copy and
#    SKIPS the update entirely if they match — a stale version = a silent no-update.
# 2. Copy skeleton files (NO binary) into the marketplace clone:
MARKET=~/.claude/plugins/marketplaces/cplugs/plugins/sptc
cp -r skills/*  "$MARKET/skills/"
cp -r hooks/*   "$MARKET/hooks/"
cp .claude-plugin/plugin.json "$MARKET/.claude-plugin/"
# 3. Commit + push the cplugs repo:
cd ~/.claude/plugins/marketplaces/cplugs && git add plugins/sptc/ \
  && git commit -m "sptc: <change>" && git push
```

**Pointer flip** (the authoritative install-state update):

```bash
claude plugin install sptc@cplugs   # un-orphans + rewrites installed_plugins.json atomically
# then, inside Claude Code:
/reload-plugins
```

**Gotchas (these DO apply to the skeleton):**
- **Never hand-patch `installed_plugins.json`** (`jq`/`sed` are brittle; CC may silently reject).
  Use the `claude plugin install` CLI — it's the atomic pointer flip + orphan-marker cleanup.
- **No legacy manual-install dir alongside the marketplace install.** A `~/.claude/plugins/<name>/`
  regular dir coexisting with the marketplace cache install makes `/plugin` report the plugin
  **not installed** (CC enumerates both; the untracked one wins the conflict). Keep the two exclusive.
- **Restart the Claude Code session after install** so the SessionStart hook re-runs and repopulates
  the plugin's env (`$OWL`/`$LIVE` equivalents) in Bash subprocesses.

**Explicitly NOT ours** (owl ships a live self-migrating binary; the thin skeleton has none, so
skip all of it): `owl.exe` binary sync · the cache targeted-prune + keep-PREVIOUS-version logic ·
the seamless binary handoff (owl Phase 18.4/18.5) · `DEPLOY.ps1`'s build/handoff orchestration.

> **RULED (operator, 2026-06-14) — cplugs plugin name = `sptc`.** CC ties the skill prefix to the
> `plugin.json` name (no override), so skills surface as `/sptc:*`. **Succession:** once parity is
> proven, flip `plugin.json` name `sptc`→`spt` (skills → `/spt:*`) and retire/rename legacy owl's
> cplugs `spt` plugin in the same coordinated move — two plugins cannot share the `spt` name. The
> flip is a single substitution `s/sptc/spt/` (plugin dir, `plugin.json` name, marketplace path).

## adapter manifest publish — the `adapter.spt` release asset

<!-- [doc->REQ-DIST-ADAPTER-RELEASE] -->
The CC adapter manifest (publish target #2) ships to end users as an **`adapter.spt`** GitHub
**release asset** on this monorepo, acquired with **`spt adapter add --release SaberMage/spt-claude-code`**
(doyle's `--release` source; needs **spt v0.7.3+ / counter 15** — not in 0.7.2). No dedicated
adapter repo: the asset is packed straight from `adapter/`.

- **Pack:** `sh ci/publish/package-adapter.sh` (DRY-RUN) → `--apply` writes
  `dist/adapter-<os>-<arch>.spt`. It validates the manifest, requires the built tool binaries (`sh
  ci/digest/build.sh && sh ci/psyche/build.sh`), and tars the archive **ROOT** = `manifest.toml`
  (renamed from `claude-spt.toml` — `adapter add` is root-only + exact-name), `strings/`, and the two
  binaries. Never uploads (operator's step).
- **Publish:** attach every per-OS `adapter-<os>-<arch>.spt` to the SAME GitHub release on
  `SaberMage/spt-claude-code`. End users `spt adapter add --release SaberMage/spt-claude-code --asset
  adapter-<os>-<arch>.spt` (or `--tag <ver>` to pin). `/sptc:setup` derives the host's os/arch and
  passes the matching `--asset` automatically.
<!-- [doc->REQ-DIST-ADAPTER-PEROS] -->
- **Per-OS (REQ-DIST-ADAPTER-PEROS) — the asset carries native binaries, so it is platform-specific.**
  v1 ships **windows + linux**. spt's `--release` takes a caller-named `--asset` (default
  `adapter.spt`) — it does NOT auto-pick per-OS, so we name + select. Naming: `adapter-<os>-<arch>.spt`
  (os ∈ windows|linux|macos, arch ∈ x86_64|aarch64), host-derived from `uname`, overridable with
  `SPTC_OS` / `SPTC_ARCH` (+ `SPTC_TARGET` = the cargo target triple for a cross build). Per-OS publish:
  - **Windows (native):** `sh ci/digest/build.sh && sh ci/psyche/build.sh && sh
    ci/publish/package-adapter.sh --apply` → `dist/adapter-windows-x86_64.spt`.
  - **Linux on a Linux host/runner (native):** the identical commands (the build scripts are portable
    — cargo, no `.exe`) → `dist/adapter-linux-x86_64.spt`.
  - **Linux cross-built FROM Windows (proven 2026-06-16):** bare `cargo build --target
    x86_64-unknown-linux-gnu` fails (`error: linker 'cc' not found` — the crate compiles, only the
    link needs a Linux linker), so use **`cargo-zigbuild`** (zig supplies the cross-linker):
    ```sh
    # one-time: install zig (a self-contained binary) + cargo-zigbuild
    cargo install cargo-zigbuild
    # download zig (e.g. 0.14.1) to a dir OUTSIDE the repo (do NOT keep it under tools/ — it's a
    # traceable-reqs scan root and zig's bundled libc C-headers trip the scanner), put zig.exe on PATH:
    #   e.g. ~/.sptc-zig/zig-x86_64-windows-0.14.1/zig.exe  →  export PATH="$HOME/.sptc-zig/...:$PATH"
    rustup target add x86_64-unknown-linux-gnu
    # cross-build both tool crates with zig as the linker
    cargo zigbuild --release --target x86_64-unknown-linux-gnu --manifest-path tools/claude-spt-digest/Cargo.toml
    cargo zigbuild --release --target x86_64-unknown-linux-gnu --manifest-path tools/claude-spt-psyche/Cargo.toml
    # pack the linux asset (SPTC_TARGET points the packer at target/<triple>/release)
    SPTC_OS=linux SPTC_ARCH=x86_64 SPTC_TARGET=x86_64-unknown-linux-gnu sh ci/publish/package-adapter.sh --apply
    ```
    → `dist/adapter-linux-x86_64.spt` carrying real `ELF x86-64 GNU/Linux` binaries (verified).
  - Attach BOTH assets to the one release.
  - **Coupling (do not skew):** the os-detecting `/sptc:setup` floor (cplugs skeleton + adapter
    strings) requests `--asset adapter-<os>-<arch>.spt`, so it must ship **with** a release that
    carries those per-OS assets — never before. Sequence: cut the per-OS-asset release FIRST, then
    republish the cplugs skeleton (next `plugin.json` bump) that points at it. A skeleton bump ahead
    of the assets would 404 end-user setup.
- **Binaries (install-dir resolution — REQ-INSTALL-11).** A `--release`/`--github` acquisition extracts
  the `.spt` archive's `manifest.toml` + `strings/` **+ both tool binaries** into the adapter install
  dir (`…/adapters/_github/<safe>/`). The command templates use **bare names** (`claude-spt-digest`,
  `claude-spt-psyche`), which spt-core resolves **from that install dir** (v0.8.0 Feature B /
  REQ-INSTALL-11) — **no PATH placement needed** (dogfood-proven on v0.8.1 for both binaries; F-006
  RESOLVED, interim retired). The pack therefore MUST carry both binaries (the resolution source). Note:
  a plain local-dev `spt adapter add <manifest.toml>` copies manifest + strings only (no binaries in the
  install dir), so local-dev runtime still relies on the built binary being on PATH (e.g. the CI ints
  prepend `target/release`); the install-dir path is the end-user `--release` story.
- **Acquisition only:** `--release` does **not** establish an `[update]` self-update route (our
  manifest declares no `[update]` → COPY-mode registration). Re-acquire a newer version by re-running
  `--release --tag <newer>`. The signed `file_pull` self-update channel is a separate, later concern.

## Update path (dual, kept in sync)

Users receive updates two ways, and both must stay consistent:
- **File-pull (the real channel)** — spt-core conducts manifest + binary updates seamlessly;
  this is how logic and instruction churn reaches users. Version-of-truth = the
  manifest/binary version spt-core tracks (`spt adapter list` / `/spt:version`).
- **`claude plugin update` (cautionary, skeleton sync)** — only resyncs the low-churn
  marketplace skeleton on the rare structural bump. It is NOT the version-of-truth.

## Notes

- **Distinct numbers — never conflate them:** the **plugin (marketplace) version** (in
  `plugin.json`, bumps rarely) and the **adapter manifest/binary version** (spt-core-tracked,
  the user-visible version-of-truth). They move on independent schedules — the plugin can sit
  static across many manifest updates.
- **Trust model:** adapter manifest/binary integrity is the `spt` binary's responsibility via
  spt-core's signed-update framework — spt-claude-code defines no separate trust ceremony.
  (Claude Code has no plugin-file integrity check, which is why the skeleton plugin is safe to
  in-place-edit; only old version dirs orphan on update and are GC'd after 7 days.)


Clear: cplugs skeleton unchanged → no republish (plugin.json stays 0.1.2). Only repack both .spt + new GH release. Read packer + check binaries present.


cd C:/Users/decid/Documents/projects/spt-claude-code && echo "=== package-adapter.sh (head) ==="; head -80 ci/publish/package-adapter.sh; echo "=== built binaries present? ==="; ls -la target/release/claude-spt-digest* target/release/claude-spt-psyche* 2>&1 | head; echo "--- linux ---"; ls -la target/x86_64-unknown-linux-gnu/release/claude-spt-digest target/x86_64-unknown-linux-gnu/release/claude-spt-psyche 2>&1 | head

Read packer head + check built binaries


=== package-adapter.sh (head) ===
#!/bin/sh
# Pack the `adapter.spt` release asset — the end-user distribution acquired by
# `spt adapter add --release SaberMage/spt-claude-code` (doyle's --release source, spt v0.7.3+).
# The archive ROOT must hold `manifest.toml` (named EXACTLY that) + `strings/` + the tool binaries;
# spt-core fetches it from the repo's GitHub release, extracts to the durable home, registers the
# root. DRY-RUN by default. Never uploads — the release/tag/upload is the operator's step.
# [impl->REQ-DIST-ADAPTER-RELEASE]
#
# Usage:
#   package-adapter.sh            # dry-run: validate + print the archive plan, write nothing
#   package-adapter.sh --apply    # write dist/adapter.spt (validated)
set -u
HERE=$(CDPATH= cd "$(dirname "$0")" && pwd)
ROOT=$(CDPATH= cd "$HERE/../.." && pwd)
ADAPTER="$ROOT/adapter"
MANIFEST="$ADAPTER/claude-spt.toml"   # renamed to manifest.toml INSIDE the archive (root-only rule)
STRINGS="$ADAPTER/strings"
APPLY=0
[ "${1:-}" = "--apply" ] && APPLY=1

# PER-OS asset name: the .spt carries native binaries, so it is platform-specific and ships as
# `adapter-<os>-<arch>.spt`. /sptc:setup acquires the matching one via spt's caller-named `--asset`.
# Host-derived from uname; override SPTC_OS/SPTC_ARCH for a cross build / CI. [impl->REQ-DIST-ADAPTER-PEROS]
SPTC_OS="${SPTC_OS:-}"; SPTC_ARCH="${SPTC_ARCH:-}"
if [ -z "$SPTC_OS" ]; then case "$(uname -s 2>/dev/null)" in
  MINGW*|MSYS*|CYGWIN*|Windows*) SPTC_OS=windows ;;
  Linux) SPTC_OS=linux ;;
  Darwin) SPTC_OS=macos ;;
  *) SPTC_OS=unknown ;;
esac; fi
if [ -z "$SPTC_ARCH" ]; then case "$(uname -m 2>/dev/null)" in
  x86_64|amd64) SPTC_ARCH=x86_64 ;;
  arm64|aarch64) SPTC_ARCH=aarch64 ;;
  *) SPTC_ARCH="$(uname -m 2>/dev/null || echo unknown)" ;;
esac; fi
# Native executable suffix, keyed off the DECLARED os (windows → .exe, else bare) — the archive
# carries the binary under its native name so a bare-name template (`claude-spt-digest …`) resolves.
case "$SPTC_OS" in windows) EXE=".exe" ;; *) EXE="" ;; esac
# Binary location: a cross build sets SPTC_TARGET (e.g. x86_64-unknown-linux-gnu → cargo-zigbuild) and
# the binaries land under target/<triple>/release; a native build uses target/release.
if [ -n "${SPTC_TARGET:-}" ]; then RELSUB="$SPTC_TARGET/release"; else RELSUB="release"; fi
DIGEST="$ROOT/tools/claude-spt-digest/target/$RELSUB/claude-spt-digest$EXE"
PSYCHE="$ROOT/tools/claude-spt-psyche/target/$RELSUB/claude-spt-psyche$EXE"
ASSET="adapter-${SPTC_OS}-${SPTC_ARCH}.spt"
OUT="${ADAPTER_SPT_OUT:-$ROOT/dist/$ASSET}"   # overridable so the unit test writes to a tmp file

# Validate the manifest first — refuse to ship an invalid adapter.
echo "== validate manifest =="
if ! sh "$ROOT/ci/manifest/check-manifest.sh"; then
  echo "REFUSING to package: manifest failed schema validation (fix above, then retry)." >&2
  exit 1
fi

# Require the release binaries (NOT auto-copied by register — they must ride the archive; doyle).
echo
echo "== tool binaries =="
missing=0
for b in "$DIGEST" "$PSYCHE"; do
  if [ -f "$b" ]; then echo "  ok    $b"; else echo "  MISS  $b"; missing=1; fi
done
if [ "$missing" -ne 0 ]; then
  echo "REFUSING to package: build the release binaries first — sh ci/digest/build.sh && sh ci/psyche/build.sh" >&2
  exit 1
fi

echo
echo "== plan ($([ "$APPLY" -eq 1 ] && echo APPLY || echo DRY-RUN)) =="
echo "manifest : $MANIFEST  ->  (archive root) manifest.toml"
echo "strings  : $STRINGS/  ->  (archive root) strings/"
echo "binaries : claude-spt-digest$EXE, claude-spt-psyche$EXE  ->  (archive root)"
echo "os/arch  : $SPTC_OS/$SPTC_ARCH"
echo "asset    : $OUT  (-> $ASSET)"
echo "NOTE: the archive is PLATFORM-SPECIFIC (native binaries: '$EXE' build) — hence the per-OS name."
echo "      Ship one asset per OS on the same release; /sptc:setup picks the host's via --asset. Build"
echo "      each OS native, OR cross-build Linux from Windows via cargo-zigbuild + SPTC_TARGET (bare"
echo "      'cargo build --target' fails 'cc not found'; zig provides the linker). On v0.8.0+ Feature B"
echo "      resolves the bundled binaries from the install dir (no PATH copy); pre-0.8.0 they need PATH."

if [ "$APPLY" -ne 1 ]; then
  echo
=== built binaries present? ===
ls: cannot access 'target/release/claude-spt-digest*': No such file or directory
ls: cannot access 'target/release/claude-spt-psyche*': No such file or directory
--- linux ---
ls: cannot access 'target/x86_64-unknown-linux-gnu/release/claude-spt-digest': No such file or directory
ls: cannot access 'target/x86_64-unknown-linux-gnu/release/claude-spt-psyche': No such file or directory


Packer reads per-crate target dirs (`tools/<crate>/target/...`), not workspace root. Check those.


cd C:/Users/decid/Documents/projects/spt-claude-code && echo "=== win native ==="; ls -la tools/claude-spt-digest/target/release/claude-spt-digest.exe tools/claude-spt-psyche/target/release/claude-spt-psyche.exe 2>&1; echo "=== linux cross ==="; ls -la tools/claude-spt-digest/target/x86_64-unknown-linux-gnu/release/claude-spt-digest tools/claude-spt-psyche/target/x86_64-unknown-linux-gnu/release/claude-spt-psyche 2>&1; echo "=== zig on PATH? ==="; command -v zig 2>&1; ls ~/.sptc-zig/ 2>&1 | head

Check per-crate built binaries (win + linux) and zig toolchain


=== win native ===
-rwxr-xr-x 2 decid 197609 269824 Jun 15 20:05 tools/claude-spt-digest/target/release/claude-spt-digest.exe
-rwxr-xr-x 2 decid 197609 249344 Jun 16 18:53 tools/claude-spt-psyche/target/release/claude-spt-psyche.exe
=== linux cross ===
-rw-r--r-- 2 decid 197609 502272 Jun 16 09:46 tools/claude-spt-digest/target/x86_64-unknown-linux-gnu/release/claude-spt-digest
-rw-r--r-- 2 decid 197609 434016 Jun 16 17:15 tools/claude-spt-psyche/target/x86_64-unknown-linux-gnu/release/claude-spt-psyche
=== zig on PATH? ===
zig-x86_64-windows-0.14.1


All binaries present (win .exe + linux ELF, unchanged from v0.2.0 — exactly right, only manifest/strings change). Bump version + CHANGELOG.


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

# Local spt binary is 0.6.0; the published contract we build to is v0.7.0 (manifest.schema.json,

# shortcut_basename). 0.7.0 is the floor this manifest's fields require.


Edit

## [0.2.1] - 2026-06-16

### Fixed
- **Going live shows a clean status, not raw machine output.** Starting a live agent previously
  leaked internal setup markers and tokens into the chat. `/sptc:live` now reports a single tidy
  summary — your agent id, online status, how other agents reach you, and how to reply — and
  nothing else.

### Changed
- **Self-contained live setup.** Bringing a session live no longer bounces you to a separate help
  topic; `/sptc:live` carries the full bringup itself, so going live works in one step.

## [0.2.0] - 2026-06-16


<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	# Changelog
2
3	All notable user-facing changes to the **sptc** plugin (Spacetime adapter for Claude Code).
4	The format follows [Keep a Changelog](https://keepachangelog.com/); each release section is the
5	public release body verbatim.
6
7	> Each release below is keyed to the **adapter version of truth** (the version you see in
8	> `/sptc:version` and the GitHub release tag). The cplugs *plugin skeleton* version (`plugin.json`)
9	> moves on its own slower schedule and may differ.
10
11	## [0.2.0] - 2026-06-16
12
13	### Fixed
14	- **Live agents now reliably start their background companion.** Previously a live agent could come
15	  up marked "online" while its persistent companion silently failed to start, leaving it with no

# Changelog

All notable user-facing changes to the **sptc** plugin (Spacetime adapter for Claude Code).
The format follows [Keep a Changelog](https://keepachangelog.com/); each release section is the
public release body verbatim.

> Each release below is keyed to the **adapter version of truth** (the version you see in
> `/sptc:version` and the GitHub release tag). The cplugs *plugin skeleton* version (`plugin.json`)
> moves on its own slower schedule and may differ.

## [0.2.0] - 2026-06-16

### Fixed
- **Live agents now reliably start their background companion.** Previously a live agent could come
  up marked "online" while its persistent companion silently failed to start, leaving it with no


## [0.2.0] - 2026-06-16

### Fixed
- **Live agents now reliably start their background companion.**

## [0.2.1] - 2026-06-16

### Fixed
- **Going live shows a clean status, not raw machine output.** Starting a live agent previously
  leaked internal setup markers and tokens into the chat. `/sptc:live` now reports a single tidy
  summary — your agent id, online status, how other agents reach you, and how to reply — and
  nothing else.

### Changed
- **Self-contained live setup.** Bringing a session live no longer bounces you to a separate help
  topic; `/sptc:live` carries the full bringup itself, so going live works in one step.

## [0.2.0] - 2026-06-16

### Fixed
- **Live agents now reliably start their background companion.**


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

## [0.2.1] - 2026-06-16

### Fixed
- **Going live shows a clean status, not raw machine output.** Starting a live agent previously
  leaked internal setup markers and tokens into the chat. `/sptc:live` now reports a single tidy
  summary — your agent id, online status, how other agents reach you, and how to reply — and
  nothing else.

### Changed
- **Self-contained live setup.** Bringing a session live no longer bounces you to a separate help
  topic; `/sptc:live` carries the full bringup itself, so going live works in one step.

## [0.2.0] - 2026-06-16

### Fixed
- **Live agents now reliably start their background companion.**

# Changelog

All notable user-facing changes to the **sptc** plugin (Spacetime adapter for Claude Code).
The format follows [Keep a Changelog](https://keepachangelog.com/); each release section is the
public release body verbatim.

> Each release below is keyed to the **adapter version of truth** (the version you see in
> `/sptc:version` and the GitHub release tag). The cplugs *plugin skeleton* version (`plugin.json`)
> moves on its own slower schedule and may differ.

## [0.2.0] - 2026-06-16

### Fixed
- **Live agents now reliably start their background companion.** Previously a live agent could come
  up marked "online" while its persistent companion silently failed to start, leaving it with no
  running context. The companion now launches and stays resident.

### Changed
- **Simpler setup — no manual PATH step.** The adapter's helper tools are now found automatically
  from where the adapter is installed; `/sptc:setup` no longer asks you to copy anything onto your
  PATH.
- **Automatic adapter updates.** The adapter now updates itself from this project's GitHub releases
  (`spt adapter update`) — logic and instruction changes reach you without a reinstall.

### Added
- **Linux support.** The adapter ships native **Windows and Linux** builds; `/sptc:setup` detects
  your OS and installs the right one.
- **ccs integration.** If you use [ccs](https://github.com/kaitranntt/ccs), `/sptc:setup` wires the
  shipped `claude-spt:ccs` profile so live/ready agents can run on your ccs backends instead of
  `claude`.
- **Private-network onboarding.** `/sptc:setup` now offers to create or join a private network
  (subnet) so you can pair machines and reach agents across them.

## [0.1.0] - 2026-06-15

First public release.

### Added
- **One-step setup — `/sptc:setup`.** Sets the plugin up and installs the Spacetime (`spt`)
  engine for you if it isn't already present, so messaging and live agents just work. Also offers
  to create or join a private network and to register the always-on background service.
- **Agent messaging.** `/sptc:ready` turns on your inbox so other agents can reach this session;
  `/sptc:send` messages another agent; `/sptc:list-agents` shows who is currently active.
- **Live agents.** `/sptc:live` upgrades the current session into a live agent with a persistent
  companion that keeps its own running context. `/sptc:commune` pushes a context update to that
  companion, and `/sptc:signoff` ends a live session cleanly with a final summary.
- **`/sptc:force-stop`** immediately tears down a listening or live agent when you need it gone.
- **Cross-machine networks — `/sptc:subnet`.** Pair machines into a private network (create,
  show the join code, or join an existing one) so your agents can reach each other across nodes.
- **`/sptc:version`** reports the running engine version.
- **Alternate model backends (advanced).** Ships a ready-made `ccs` profile template you can
  select to launch sessions through [ccs](https://github.com/kaitranntt/ccs) — useful for routing
  an agent to a different model or billing backend. You supply your own ccs configuration.
- **Invisible engine install.** Starting a session automatically installs the `spt` engine the
  first time if it is missing — no separate install step.

+- **Going live shows a clean status, not raw machine output.** Starting a live agent previously

+  leaked internal setup markers and tokens into the chat. `/sptc:live` now reports a single tidy

+  summary — your agent id, online status, how other agents reach you, and how to reply — and

+- **Self-contained live setup.** Bringing a session live no longer bounces you to a separate help

+  topic; `/sptc:live` carries the full bringup itself, so going live works in one step.


Now repack both per-OS .spt with the new manifest/strings (binaries unchanged).


Bash

cd C:/Users/decid/Documents/projects/spt-claude-code
echo "=== pack windows ==="
sh ci/publish/package-adapter.sh --apply 2>&1 | tail -15
echo "=== pack linux (zig cross binaries already built) ==="
export PATH="$HOME/.sptc-zig/zig-x86_64-windows-0.14.1:$PATH"
SPTC_OS=linux SPTC_ARCH=x86_64 SPTC_TARGET=x86_64-unknown-linux-gnu sh ci/publish/package-adapter.sh --apply 2>&1 | tail -15

Repack both per-OS .spt assets with v0.2.1 manifest/strings


=== pack windows ===
binaries : claude-spt-digest.exe, claude-spt-psyche.exe  ->  (archive root)
os/arch  : windows/x86_64
asset    : /c/Users/decid/Documents/projects/spt-claude-code/dist/adapter-windows-x86_64.spt  (-> adapter-windows-x86_64.spt)
NOTE: the archive is PLATFORM-SPECIFIC (native binaries: '.exe' build) — hence the per-OS name.
      Ship one asset per OS on the same release; /sptc:setup picks the host's via --asset. Build
      each OS native, OR cross-build Linux from Windows via cargo-zigbuild + SPTC_TARGET (bare
      'cargo build --target' fails 'cc not found'; zig provides the linker). On v0.8.0+ Feature B
      resolves the bundled binaries from the install dir (no PATH copy); pre-0.8.0 they need PATH.

== validate archive ==
ok   manifest.toml at archive root

WROTE /c/Users/decid/Documents/projects/spt-claude-code/dist/adapter-windows-x86_64.spt. Next (operator): attach to a GitHub release on SaberMage/spt-claude-code (alongside
the other per-OS assets), then end users 'spt adapter add --release SaberMage/spt-claude-code
--asset adapter-windows-x86_64.spt' (needs spt v0.7.3+). /reload as needed.
=== pack linux (zig cross binaries already built) ===
binaries : claude-spt-digest, claude-spt-psyche  ->  (archive root)
os/arch  : linux/x86_64
asset    : /c/Users/decid/Documents/projects/spt-claude-code/dist/adapter-linux-x86_64.spt  (-> adapter-linux-x86_64.spt)
NOTE: the archive is PLATFORM-SPECIFIC (native binaries: '' build) — hence the per-OS name.
      Ship one asset per OS on the same release; /sptc:setup picks the host's via --asset. Build
      each OS native, OR cross-build Linux from Windows via cargo-zigbuild + SPTC_TARGET (bare
      'cargo build --target' fails 'cc not found'; zig provides the linker). On v0.8.0+ Feature B
      resolves the bundled binaries from the install dir (no PATH copy); pre-0.8.0 they need PATH.

== validate archive ==
ok   manifest.toml at archive root

WROTE /c/Users/decid/Documents/projects/spt-claude-code/dist/adapter-linux-x86_64.spt. Next (operator): attach to a GitHub release on SaberMage/spt-claude-code (alongside
the other per-OS assets), then end users 'spt adapter add --release SaberMage/spt-claude-code
--asset adapter-linux-x86_64.spt' (needs spt v0.7.3+). /reload as needed.


Both packed. Verify archives carry v0.2.1 manifest + new live.md + correct binary types, then run gates.


cd C:/Users/decid/Documents/projects/spt-claude-code
for os in windows linux; do
  echo "=== $os .spt contents ==="
  T=$(mktemp -d); tar -xf "dist/adapter-${os}-x86_64.spt" -C "$T"
  echo "version:   $(grep -m1 '^version' "$T/manifest.toml")"
  echo "hostbin:   $(grep -m1 'host_binaries =' "$T/manifest.toml")"
  echo "live.md self-contained (no how-to redirect)? $(grep -c 'spt how-to live' "$T/strings/skills/live.md") matches"
  echo "live.md OUTPUT DISCIPLINE present? $(grep -c 'OUTPUT DISCIPLINE' "$T/strings/skills/live.md")"
  echo "digest bin: $(file "$T/claude-spt-digest"* 2>/dev/null | sed 's/.*: //')"
  echo "psyche bin: $(file "$T/claude-spt-psyche"* 2>/dev/null | sed 's/.*: //')"
  rm -rf "$T"
done

Verify both .spt archive contents and binary types


=== windows .spt contents ===
version:   version = "0.2.1"
hostbin:   host_binaries = ["claude"]
live.md self-contained (no how-to redirect)? 0 matches
live.md OUTPUT DISCIPLINE present? 1
digest bin: PE32+ executable (console) x86-64, for MS Windows, 5 sections
psyche bin: PE32+ executable (console) x86-64, for MS Windows, 5 sections
=== linux .spt contents ===
version:   version = "0.2.1"
hostbin:   host_binaries = ["claude"]
live.md self-contained (no how-to redirect)? 0 matches
live.md OUTPUT DISCIPLINE present? 1
digest bin: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.0.0, stripped
psyche bin: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.0.0, stripped


Archives verified: v0.2.1, host_binaries, redirect gone (0 matches), OUTPUT DISCIPLINE present, win=PE / linux=ELF. Run full gates.


cd C:/Users/decid/Documents/projects/spt-claude-code && echo "=== run-gates ===" && sh ci/run-gates.sh 2>&1 | tail -40; echo "GATES_EXIT=${PIPESTATUS[0]}"

Run full CI gate suite


=== run-gates ===
ok  tests/adapter-archive.sh
ok  tests/ci-gates.sh
ok  tests/docs-gen.sh
ok  tests/hooks-parse.sh
ok  tests/manifest-schema.sh
ok  tests/manifest-shortcut.sh
ok  tests/msys-hazard.sh
ok  tests/skeleton-validate.sh

=== GATE: digest-extractor (cargo build + test) ===

running 12 tests
............
test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

ok  claude-spt-digest: cargo test + release build

=== GATE: psyche-runner (cargo build + test) ===

running 10 tests
..........
test result: ok. 10 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

ok  claude-spt-psyche: cargo test + release build

=== GATE: traceable-reqs check (requirement coverage) ===
ok  coverage green

=== GATE: skeleton-validate (cplugs installability) ===
ok  skeleton installable

=== GATE: manifest-schema ===
ok   C:/Users/decid/Documents/projects/spt-claude-code/adapter/claude-spt.toml
ok   manifest validates against published manifest.schema.json

=== GATE: docs-drift ===
ok   mdbook build
ok   llms.txt in sync

=== RESULT: PASS ===
GATES_EXIT=0


All gates PASS (incl docs-drift — no regen needed). Commit the release.


cd C:/Users/decid/Documents/projects/spt-claude-code && git add adapter/claude-spt.toml CHANGELOG.md dist/adapter-windows-x86_64.spt dist/adapter-linux-x86_64.spt && git status --short

Stage release artifacts


Error: Exit code 1
The following paths are ignored by one of your .gitignore files:
dist
hint: Use -f if you really want to add them.
hint: Turn this message off by running
hint: "git config advice.addIgnoredFile false"


dist/ is gitignored — .spt are release-only artifacts (attached to GH release, not tracked). Commit source bump only.


cd C:/Users/decid/Documents/projects/spt-claude-code && git add adapter/claude-spt.toml CHANGELOG.md && git commit -q -F - <<'EOF'
chore(release): v0.2.1 — self-contained /sptc:live injection + humanized output

Adapter version-of-truth 0.2.0 -> 0.2.1 (doyle release ruling 2026-06-16: ship
DO-NOW 1+2 + PREP-3 now, don't wait on spt-core v0.9.0; PREP-4 held).

User-facing (CHANGELOG [0.2.1]):
- Fixed: going live shows a clean status summary, not raw internal markers/tokens
  (the operator-flagged UX leak in /sptc:live bringup).
- Changed: self-contained live setup — /sptc:live no longer redirects to a help
  topic; it carries the full bringup itself.

Content delta vs 0.2.0 is manifest + strings only (adapter/strings/skills/live.md
rewrite + adapter.host_binaries stage, commit 87dcda6); tool binaries unchanged.
Both per-OS .spt repacked to dist/ (win=PE, linux=ELF; verified) carrying the
0.2.1 manifest + new live.md — attached to the GH release (dist/ is gitignored,
release-only). cplugs skeleton UNCHANGED -> plugin.json stays 0.1.2, no republish.

Gates: ci/run-gates.sh PASS, traceable-reqs green, both .spt validate, docs in sync.

Co-authored by: perri
EOF
echo "EXIT=$?" && git log --oneline -3

Commit v0.2.1 release


EXIT=0
670b01e chore(release): v0.2.1 — self-contained /sptc:live injection + humanized output
87dcda6 feat(live): self-contained /sptc:live injection + humanized output; stage host_binaries
005b4bb docs(findings): F-009 + F-010 RESOLVED-SHIPPED + RE-VALIDATED (spt v0.8.2)


Now the outward publish (doyle-authorized). Verify remote + gh auth + tag availability first.


cd C:/Users/decid/Documents/projects/spt-claude-code && echo "=== remote ==="; git remote -v | head -2; echo "=== branch/ahead ==="; git status -sb | head -1; echo "=== tag exists? ==="; git tag -l 'v0.2.1'; git ls-remote --tags origin v0.2.1 2>&1 | head; echo "=== gh auth ==="; gh auth status 2>&1 | head -5; echo "=== existing releases ==="; gh release list --limit 5 2>&1 | head

Check remote, gh auth, tag availability, existing releases


=== remote ===
origin	https://github.com/SaberMage/spt-claude-code.git (fetch)
origin	https://github.com/SaberMage/spt-claude-code.git (push)
=== branch/ahead ===
## main...origin/main [ahead 2]
=== tag exists? ===
=== gh auth ===
github.com
  ✓ Logged in to github.com account SaberMage (keyring)
  - Active account: true
  - Git operations protocol: https
  - Token: gho_************************************
=== existing releases ===
v0.2.0	Latest	v0.2.0	2026-06-17T00:17:06Z
claude-spt adapter v0.1.0		v0.1.0	2026-06-16T06:34:44Z


All green: gh authed as SaberMage, tag free, main ahead 2. Publish — push, tag, release with both assets.