Edit

[[requirements]]
id = "REQ-HAZARD-MSYS-PATHCONV"
title = "Hook wrappers read the CC payload from stdin, never from a /-leading positional argv (Git-Bash/MSYS path-mangles those on Windows)"
required_stages = ["unit"]  # unit: tests/msys-hazard.sh. Confirmed live 2026-06-15 (UPS validation run A).

[[requirements]]
id = "REQ-HAZARD-MSYS-PATHCONV"
title = "Hook wrappers read the CC payload from stdin, never from a /-leading positional argv (Git-Bash/MSYS path-mangles those on Windows)"
required_stages = ["unit"]  # unit: tests/msys-hazard.sh. Confirmed live 2026-06-15 (UPS validation run A).

[[requirements]]
id = "REQ-HAZARD-PSYCHE-PERMS-DEADLOCK"
title = "Every CC process spt-core spawns NON-INTERACTIVELY carries --dangerously-skip-permissions: each claude-spt-psyche turn (seed + every pulse, detached/null-stdin) AND both [session.self] bringup commands (base claude + ccs profile, broker PTY). An interactive permission prompt with no operator deadlocks the turn (silently, for the detached Psyche). The Psyche additionally runs inside a Read/Edit/Write tool sandbox so auto-approve is bounded."
required_stages = ["doc", "unit"]  # doc: docs/KNOWN-HAZARDS.md §2.2 + docs/adr/0003-*. unit: tools/claude-spt-psyche/src/main.rs every_turn_is_sandboxed_to_legacy_owl_parity (psyche turns) + tests/manifest-shortcut.sh (both [session.self] commands carry the flag). Legacy parity: claude_skill_owl src/live/wrapper/claude.rs (init/resume/final all skip-permissions). Identified 2026-06-18 reaching psyche parity.


ADRs over 0002 can be ignored/should be wiped from docs. those are probably from comms doyle shared from his project, which is unrelated to here


Update Claude-spt adapter configuration and flags


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

[[requirements]]
id = "REQ-HAZARD-MSYS-PATHCONV"
title = "Hook wrappers read the CC payload from stdin, never from a /-leading positional argv (Git-Bash/MSYS path-mangles those on Windows)"
required_stages = ["unit"]  # unit: tests/msys-hazard.sh. Confirmed live 2026-06-15 (UPS validation run A).

[[requirements]]
id = "REQ-HAZARD-PSYCHE-PERMS-DEADLOCK"
title = "Every CC process spt-core spawns NON-INTERACTIVELY carries --dangerously-skip-permissions: each claude-spt-psyche turn (seed + every pulse, detached/null-stdin) AND both [session.self] bringup commands (base claude + ccs profile, broker PTY). An interactive permission prompt with no operator deadlocks the turn (silently, for the detached Psyche). The Psyche additionally runs inside a Read/Edit/Write tool sandbox so auto-approve is bounded."
required_stages = ["doc", "unit"]  # doc: docs/KNOWN-HAZARDS.md §2.2 + docs/adr/0003-*. unit: tools/claude-spt-psyche/src/main.rs every_turn_is_sandboxed_to_legacy_owl_parity (psyche turns) + tests/manifest-shortcut.sh (both [session.self] commands carry the flag). Legacy parity: claude_skill_owl src/live/wrapper/claude.rs (init/resume/final all skip-permissions). Identified 2026-06-18 reaching psyche parity.

+title = "Every CC process spt-core spawns NON-INTERACTIVELY carries --dangerously-skip-permissions: each claude-spt-psyche turn (seed + every pulse, detached/null-stdin) AND both [session.self] bringup commands (base claude + ccs profile, broker PTY). An interactive permission prompt with no operator deadlocks the turn (silently, for the detached Psyche). The Psyche additionally runs inside a Read/Edit/Write tool sandbox so auto-approve is bounded."

+required_stages = ["doc", "unit"]  # doc: docs/KNOWN-HAZARDS.md §2.2 + docs/adr/0003-*. unit: tools/claude-spt-psyche/src/main.rs every_turn_is_sandboxed_to_legacy_owl_parity (psyche turns) + tests/manifest-shortcut.sh (both [session.self] commands carry the flag). Legacy parity: claude_skill_owl src/live/wrapper/claude.rs (init/resume/final all skip-permissions). Identified 2026-06-18 reaching psyche parity.

# ── Milestone: DOCS-SITE (mdBook, drift-gated) — minted on-start. Dual-audience product docs

# in docs-site/, built with mdBook, gated against drift. Seeded from docs/DOCS-STRATEGY.md.


Prompt:
<task-notification>
<task-id>aca6cfcafbaaeb4f3</task-id>
<tool-use-id>toolu_01DLZDQWcuNTXa6pzq4s6vM8</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-claude-code\4b08b6c6-5f2a-42f7-a56d-cf3d9a866de7\tasks\aca6cfcafbaaeb4f3.output</output-file>
<status>completed</status>
<summary>Agent "Wipe leaked doyle ADR refs" came to rest</summary>
<note>A task-notification fires each time this agent comes to rest with no live background children of its own. The user can send it another message and resume it, so the same task-id may notify more than once.</note>
<result>Cleanup complete. All spurious ADR-0003..0021 citation tokens removed; the two whitelisted template dummies preserved; edited JSON still valid.

## Files changed (16)
- `adapter/claude-spt.toml` — 3 tokens (ADR-0021 x2, ADR-0019)
- `adapter/manifest.schema.json` — 6 tokens (ADR-0019 x4, ADR-0007, ADR-0004); JSON re-validated
- `ci/digest/digest-proof-int.sh` — 1 (ADR-0019)
- `ci/hooks/poll-int.sh` — 2 (ADR-0020 x2)
- `docs/adr/0002-hook-wiring-hand-written-hooks-json-shells-spt-api.md` — 5 (ADR-0020 x3, ADR-0009, ADR-0012)
- `docs/PARITY.md` — 1 (ADR-0018)
- `docs/SPT-CORE-FINDINGS.md` — 5 (ADR-0020 x3, ADR-0019 x2)
- `MANIFEST-PARITY-PLAN.md` — 2 (ADR-0020 x2)
- `PARITY-PUBLISH-PLAN.md` — 1 (ADR-0018)
- `SKELETON-PLAN.md` — 1 (ADR-0020)
- `plugin/sptc/hooks/user-prompt-submit.sh` — 2 (ADR-0009/0012, ADR-0020)
- `plugin/sptc/hooks/_common.sh` — 2 (ADR-0020 x2)
- `tests/hooks-parse.sh` — 1 (ADR-0020)
- `tools/claude-spt-digest/Cargo.toml` — 1 (ADR-0019)
- `tools/claude-spt-digest/src/main.rs` — 1 (ADR-0019)
- `traceable-reqs.toml` — 2 (ADR-0020 comment, ADR-0019 in title string)

## Total tokens removed
34 spurious `ADR-00NN` citation tokens across 16 files. (Note: `ADR-0009/0012` in user-prompt-submit.sh was a single combined token covering two refs; counted as one token.)

## Replacement approach
- Pure citation parentheticals deleted with leading space (e.g. `seam (ADR-0019).` → `seam.`).
- Mixed parentheticals kept other content (e.g. `(ADR-0021, CONTEXT §170-186)` → `(CONTEXT §170-186)`; `(REQ-UPD-5 adapter content signing, ADR-0004 §D)` → `(REQ-UPD-5 adapter content signing)`).
- Multi-ref parenthetical `(... ADR-0009, ... ADR-0012)` → kept the prose, dropped both tokens.
- Inline noun usages rephrased naturally: `ADR-0020 shipped` → "The/the canonical poll envelope shipped"; `the ADR-0019 engine` → "spt-core digest engine"; `(ADR-0019 §Decision)` → "(by design)".

## Final grep
Excluding `target/` and the two template dummies: **empty** (zero leaked refs). The only remaining matches without that exclusion are the two whitelisted illustrative placeholders in `docs/adr/0000-template.md:10` and `docs/formats/adr-format.md:22`, left untouched as instructed.

No git operations run; no protected files (CONTEXT.md, KNOWN-HAZARDS.md, SCOPE.md) touched; no new files created.</result>
<usage><subagent_tokens>64245</subagent_tokens><tool_uses>64</tool_uses><duration_ms>236519</duration_ms></usage>
</task-notification>


Wipe agent done (34 tokens, 16 files, JSON re-validated, dummies + protected files untouched). Running full gates.


Bash

command -v traceable-reqs >/dev/null 2>&1 && traceable-reqs check >/tmp/tr.txt 2>&1; echo "TR exit=$?"; grep -iE 'PSYCHE-PERMS|SKILL-LIVE|FAIL|error|missing|invalid' /tmp/tr.txt | head; echo "=== unit sweep ==="; for t in tests/*.sh; do sh "$t" >/dev/null 2>&1 && echo "ok   $t" || echo "FAIL $t"; done

traceable-reqs check + unit sweep


TR exit=0
       Deterministic gates (shell-syntax + unit tests + traceable-reqs check + manifest-schema + docs-drift), each a binary pass/fail, runnable as one command
  [OK] REQ-HAZARD-PSYCHE-PERMS-DEADLOCK  required: [doc, unit]  stages: +doc -impl +unit -int
  [OK] REQ-SKILL-LIVE  required: [doc, impl, unit, int]  stages: +doc +impl +unit +int
=== unit sweep ===
ok   tests/acceptance-harness.sh
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


All green: traceable-reqs exit 0, `REQ-HAZARD-PSYCHE-PERMS-DEADLOCK` [doc+unit] OK, 9/9 unit sweep (docs-drift clean). Committing as two logical commits (wipe / doc-recording). Checking status first.


Review working tree before staging


 M CONTEXT.md
 M MANIFEST-PARITY-PLAN.md
 M PARITY-PUBLISH-PLAN.md
 M SCOPE.md
 M SKELETON-PLAN.md
 M adapter/claude-spt.toml
 M adapter/manifest.schema.json
 M ci/digest/digest-proof-int.sh
 M ci/hooks/poll-int.sh
 M docs/KNOWN-HAZARDS.md
 M docs/PARITY.md
 M docs/SPT-CORE-FINDINGS.md
 M docs/adr/0002-hook-wiring-hand-written-hooks-json-shells-spt-api.md
 M plugin/sptc/hooks/_common.sh
 M plugin/sptc/hooks/user-prompt-submit.sh
 M tests/hooks-parse.sh
 M tests/manifest-shortcut.sh
 M tools/claude-spt-digest/Cargo.toml
 M tools/claude-spt-digest/src/main.rs
 M tools/claude-spt-psyche/src/main.rs
 M traceable-reqs.toml
?? docs/adr/0003-psyche-is-a-constrained-auto-approving-companion.md


git add adapter/claude-spt.toml adapter/manifest.schema.json ci/digest/digest-proof-int.sh ci/hooks/poll-int.sh docs/PARITY.md docs/SPT-CORE-FINDINGS.md "docs/adr/0002-hook-wiring-hand-written-hooks-json-shells-spt-api.md" MANIFEST-PARITY-PLAN.md PARITY-PUBLISH-PLAN.md SKELETON-PLAN.md plugin/sptc/hooks/user-prompt-submit.sh plugin/sptc/hooks/_common.sh tests/hooks-parse.sh tools/claude-spt-digest/Cargo.toml tools/claude-spt-digest/src/main.rs
git commit -q -F - <<'EOF'
chore(docs): wipe leaked spt-core ADR citations (foreign project numbering)

ADR-0003..ADR-0021 references scattered across this repo were never THIS project's
ADRs — they leaked in from doyle's spt-core comms, whose ADR numbering is unrelated
here. This repo's only real ADRs are 0001/0002. Removed all 34 spurious ADR-00NN
citation tokens across 15 files, preserving the surrounding explanation:

  * pure citation parentheticals dropped (`seam (ADR-0019).` -> `seam.`)
  * mixed parentheticals kept their other content (`(ADR-0021, CONTEXT §170-186)` ->
    `(CONTEXT §170-186)`)
  * inline noun uses rephrased (`the ADR-0019 engine` -> `spt-core digest engine`)

Untouched: ADR-0001/0002 refs; the ADR-format template's illustrative dummy
(`0003-old-decision.md`); vendored manifest.schema.json edited in-place (still valid
JSON — descriptions are non-validating, so the schema gate is unaffected).

traceable-reqs.toml's two leaked tokens are stripped in the companion docs commit.

Co-authored by: perri
EOF
echo "=== commit1 ===" && git log -1 --format='%h %s'

Commit 1: ADR-citation wipe


warning: in the working copy of 'tools/claude-spt-digest/src/main.rs', LF will be replaced by CRLF the next time Git touches it
=== commit1 ===
eab464b chore(docs): wipe leaked spt-core ADR citations (foreign project numbering)


git add CONTEXT.md docs/KNOWN-HAZARDS.md "docs/adr/0003-psyche-is-a-constrained-auto-approving-companion.md" SCOPE.md traceable-reqs.toml tests/manifest-shortcut.sh tools/claude-spt-psyche/src/main.rs
git commit -q -F - <<'EOF'
docs(psyche): record the psyche-sandbox + non-interactive-skip-perms decisions

Capture the docs for the three changes shipped this session (deep removal,
bringup --dangerously-skip-permissions, psyche sandbox) now that the code has
landed:

  * CONTEXT.md — glossary: Psyche, commune, psyche sandbox.
  * docs/adr/0003-* — the decision: Psyche is a constrained, auto-approving
    companion at legacy-owl parity (Read/Edit/Write, slash off, model pin,
    skip-perms). Records why skip-perms is required (detached/PTY spawn, no
    operator) and why it is safe (bounded by the tool cap).
  * docs/KNOWN-HAZARDS.md §2.2 + REQ-HAZARD-PSYCHE-PERMS-DEADLOCK — the
    cross-cutting invariant: every non-interactive spt-spawned CC (psyche turns
    + both [session.self] commands) must skip the permission gate or deadlock.
  * SCOPE.md — dated decision-ledger entries (deep removed; bringup skip-perms;
    psyche sandbox), all LOCKED.

Evidence: existing psyche unit test tagged for the hazard; new
tests/manifest-shortcut.sh assertion proves both [session.self] commands carry
the flag. (Also strips the 2 leaked ADR tokens in traceable-reqs.toml, companion
to the wipe commit.)

Gates: traceable-reqs check green (REQ-HAZARD-PSYCHE-PERMS-DEADLOCK doc+unit,
REQ-SKILL-LIVE all); 9/9 unit sweep.

Co-authored by: perri
EOF
echo "=== commit2 ===" && git log -1 --format='%h %s' && git push 2>&1 | tail -3

Commit 2: doc-recording + push both


=== commit2 ===
e23c666 docs(psyche): record the psyche-sandbox + non-interactive-skip-perms decisions
To https://github.com/SaberMage/spt-claude-code.git
   873bf3c..e23c666  main -> main


Both commits pushed (`eab464b` wipe, `e23c666` docs) → `873bf3c..e23c666`.

Now the experimplate finding. Let me record the durable facts to memory, then surface it.


Write

---
name: psyche-sandbox-and-adr-leak
description: Psyche sandboxed to legacy-owl parity; ADR>0002 refs were foreign-leak (only 0001/0002 real); release held
metadata:
  type: project
---

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

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

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

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


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

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

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

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

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

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


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

# Memory index — spt-claude-code

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


Edit

- [Succession flip gated](succession-flip-gated.md) — publish as sptc; flip to spt only after proven parity AND legacy owl retired.

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


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

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

# Memory index — spt-claude-code

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

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


Docs recorded + leaked ADRs wiped, both pushed. Memory updated.

## experimplate — finding contradicts the assumption

You asked me to wipe ADR refs from `../experimplate` and commit there. I checked: **experimplate has zero leaked doyle refs.** Its *only* ADR references are the template's own pedagogical dummy, in 2 files:
- `docs/adr/0000-template.md` — `supersedes [ADR-0003](0003-old-decision.md)`
- `docs/formats/adr-format.md` — `supersedes [ADR-0003](0003-….md)`

These are illustrative placeholders teaching the "supersedes" format — not leaked provenance. This repo has the **same** two dummies (the wipe agent left them intact by design).

So there's nothing foreign to wipe in experimplate. The only question is whether you want the *dummy example itself* neutralized so no concrete `ADR-0003` appears anywhere.


AskUserQuestion

Question: How to handle the ADR template-dummy example (`0003-old-decision.md`) in experimplate AND this repo?

Choices:
Change the example to an obvious placeholder (`supersedes [ADR-NNNN](NNNN-old-decision.md)`) in both repos. No concrete ADR number anywhere. Commit the experimplate change to experimplate, the this-repo change here. Honors 'wipe ADR refs' without breaking pedagogy.
They're legit format examples, not leaks. Nothing to change/commit in experimplate. Report it clean and move on.
Delete the 'supersedes …' illustrative clause from the template/format docs in both repos, commit each.


Your questions have been answered: "How to handle the ADR template-dummy example (`0003-old-decision.md`) in experimplate AND this repo?"="Neutralize to NNNN". You can now continue with these answers in mind.

Question: How to handle the ADR template-dummy example (`0003-old-decision.md`) in experimplate AND this repo?

Choices:
Change the example to an obvious placeholder (`supersedes [ADR-NNNN](NNNN-old-decision.md)`) in both repos. No concrete ADR number anywhere. Commit the experimplate change to experimplate, the this-repo change here. Honors 'wipe ADR refs' without breaking pedagogy.
They're legit format examples, not leaks. Nothing to change/commit in experimplate. Report it clean and move on.
Delete the 'supersedes …' illustrative clause from the template/format docs in both repos, commit each.


Neutralizing to `NNNN` in both repos, committing each separately. Reading exact lines.


8	<!-- proposed | accepted | superseded — plus a date, and links if it supersedes / is superseded. -->
9	proposed (`<YYYY-MM-DD>`)
10	<!-- e.g. accepted (2026-01-15) · supersedes [ADR-0003](0003-old-decision.md) -->
11
12	## Context

<!-- proposed | accepted | superseded — plus a date, and links if it supersedes / is superseded. -->
proposed (`<YYYY-MM-DD>`)
<!-- e.g. accepted (2026-01-15) · supersedes [ADR-0003](0003-old-decision.md) -->

## Context


Edit

<!-- e.g. accepted (2026-01-15) · supersedes [ADR-0003](0003-old-decision.md) -->

<!-- e.g. accepted (2026-01-15) · supersedes [ADR-NNNN](NNNN-old-decision.md) -->


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

# <Title — the decision stated as its outcome>

<!-- Title states the decision, not the question. e.g. "Sessions are pinned at first bind",
     not "How should sessions bind?". Number files sequentially: 0001-, 0002-, … -->

## Status

<!-- proposed | accepted | superseded — plus a date, and links if it supersedes / is superseded. -->
proposed (`<YYYY-MM-DD>`)
<!-- e.g. accepted (2026-01-15) · supersedes [ADR-0003](0003-old-decision.md) -->

## Context

<!-- The forces at play: what made this decision necessary, the constraints, the real
     problems (numbered if several). Enough that a reader who wasn't there understands WHY.
     Reference CONTEXT.md terms by their canonical names. -->

## Decision

<!-- What we decided, stated plainly and actively. The specifics: what is built / changed,
     and the rejected-but-tempting alternative noted so it isn't re-litigated. -->

## Consequences

<!-- What becomes true now — good and bad. Breaking changes, new obligations (e.g. new
     REQ-* ids to mint, docs to update), and anything this forecloses or forces later. -->

+<!-- e.g. accepted (2026-01-15) · supersedes [ADR-NNNN](NNNN-old-decision.md) -->


decision, link it: `supersedes [ADR-0003](0003-….md)`. When a later ADR overrides this one,

decision, link it: `supersedes [ADR-NNNN](NNNN-….md)`. When a later ADR overrides this one,


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

# How to write an ADR

> ADRs (`docs/adr/`) record **decisions** — what we chose and why — so they aren't
> re-litigated. They are the companion to `CONTEXT.md` (which records **meaning**). The
> *grill-with-docs* loop writes and supersedes ADRs inline as decisions crystallize. Start from
> `docs/adr/0000-template.md`.

## Conventions

- **One file per decision**, numbered sequentially: `0001-<slug>.md`, `0002-<slug>.md`, …
  Never renumber a published ADR — it's a stable anchor.
- **Title = the decision as its outcome**, not the question. "Sessions are pinned at first
  bind" — not "How should sessions bind?". A reader skimming filenames should see what was
  decided.
- **Four sections, always, in order:** `## Status`, `## Context`, `## Decision`,
  `## Consequences`. Add an optional `## Alternatives considered` when the rejected options carry
  real weight.

## The sections

- **Status** — `proposed` | `accepted` | `superseded`, plus a date. If it changes an earlier
  decision, link it: `supersedes [ADR-0003](0003-….md)`. When a later ADR overrides this one,
  come back and mark this one `superseded by …`. Be precise about *what* is superseded — a later
  ADR may reverse one mechanism while keeping another's framing.
- **Context** — the forces that made the decision necessary: constraints, the real problems
  (number them if several), what a reader who wasn't in the room needs to understand the *why*.
  Refer to terms by their canonical `CONTEXT.md` names.
- **Decision** — what was decided, stated plainly and **actively**. Include the specifics of what
  gets built / changed, and name the tempting alternative you rejected so it stays rejected.
- **Consequences** — what becomes true now, good *and* bad: breaking changes, new obligations
  (e.g. "new `REQ-*` ids to mint", "the integration checklist must be updated"), and what this
  forecloses or forces later.

## Tagging

If an ADR section is the `doc`-stage evidence for a requirement, tag it in place:
`<!-- [<doc>->REQ-…] -->` immediately above that section (see `docs/TRACEABILITY.md`).

-  decision, link it: `supersedes [ADR-0003](0003-….md)`. When a later ADR overrides this one,

+  decision, link it: `supersedes [ADR-NNNN](NNNN-….md)`. When a later ADR overrides this one,


This repo's dummies neutralized. Verifying nothing concrete remains, then committing.


Bash

echo "=== any concrete ADR-00NN (>0002) left? ==="; grep -rnE 'ADR-00(0[3-9]|1[0-9]|2[0-9])' . --include='*.md' --include='*.toml' --include='*.rs' --include='*.sh' --include='*.json' 2>/dev/null | grep -v '/target/' || echo "NONE"; echo "=== docs-drift gate ==="; sh tests/docs-gen.sh >/dev/null 2>&1 && echo "ok docs-gen" || echo "FAIL docs-gen"

Verify no concrete ADR numbers + docs drift gate


=== any concrete ADR-00NN (>0002) left? ===
NONE
=== docs-drift gate ===
ok docs-gen


git add docs/adr/0000-template.md docs/formats/adr-format.md
git commit -q -F - <<'EOF'
docs(adr): neutralize template-dummy ADR number to NNNN placeholder

The ADR template + format-guide illustrated `supersedes` with a concrete
`[ADR-0003](0003-old-decision.md)`. With the foreign ADR-leak now wiped, a bare
`0003` example reads as if it were a real ADR. Switch to an unmistakable `NNNN`
placeholder so no concrete ADR number appears outside genuine 0001/0002 refs.

Co-authored by: perri
EOF
git log -1 --format='%h %s' && git push 2>&1 | tail -2

Commit + push template-dummy neutralization


19c0709 docs(adr): neutralize template-dummy ADR number to NNNN placeholder
To https://github.com/SaberMage/spt-claude-code.git
   e23c666..19c0709  main -> main


This repo done (`19c0709`). Now experimplate — same neutralization + commit there.


cd ../experimplate && grep -nE 'ADR-0003' docs/adr/0000-template.md docs/formats/adr-format.md; echo "RESET"

Check experimplate dummy lines exact


docs/adr/0000-template.md:10:<!-- e.g. accepted (2026-01-15) · supersedes [ADR-0003](0003-old-decision.md) -->
docs/formats/adr-format.md:22:  decision, link it: `supersedes [ADR-0003](0003-….md)`. When a later ADR overrides this one,
RESET
Shell cwd was reset to C:\Users\decid\Documents\projects\spt-claude-code


Edit

<!-- e.g. accepted (2026-01-15) · supersedes [ADR-0003](0003-old-decision.md) -->

<!-- e.g. accepted (2026-01-15) · supersedes [ADR-NNNN](NNNN-old-decision.md) -->


<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.


8	<!-- proposed | accepted | superseded — plus a date, and links if it supersedes / is superseded. -->
9	proposed (`<YYYY-MM-DD>`)
10	<!-- e.g. accepted (2026-01-15) · supersedes [ADR-0003](0003-old-decision.md) -->
11

<!-- proposed | accepted | superseded — plus a date, and links if it supersedes / is superseded. -->
proposed (`<YYYY-MM-DD>`)
<!-- e.g. accepted (2026-01-15) · supersedes [ADR-0003](0003-old-decision.md) -->


20
21	- **Status** — `proposed` | `accepted` | `superseded`, plus a date. If it changes an earlier
22	  decision, link it: `supersedes [ADR-0003](0003-….md)`. When a later ADR overrides this one,
23	  come back and mark this one `superseded by …`. Be precise about *what* is superseded — a later

- **Status** — `proposed` | `accepted` | `superseded`, plus a date. If it changes an earlier
  decision, link it: `supersedes [ADR-0003](0003-….md)`. When a later ADR overrides this one,
  come back and mark this one `superseded by …`. Be precise about *what* is superseded — a later


<!-- e.g. accepted (2026-01-15) · supersedes [ADR-0003](0003-old-decision.md) -->

<!-- e.g. accepted (2026-01-15) · supersedes [ADR-NNNN](NNNN-old-decision.md) -->


The file C:\Users\decid\Documents\projects\experimplate\docs\adr\0000-template.md has been updated successfully. (file state is current in your context — no need to Read it back)


decision, link it: `supersedes [ADR-0003](0003-….md)`. When a later ADR overrides this one,

decision, link it: `supersedes [ADR-NNNN](NNNN-….md)`. When a later ADR overrides this one,


The file C:\Users\decid\Documents\projects\experimplate\docs\formats\adr-format.md has been updated successfully. (file state is current in your context — no need to Read it back)

# How to write an ADR

> ADRs (`docs/adr/`) record **decisions** — what we chose and why — so they aren't
> re-litigated. They are the companion to `CONTEXT.md` (which records **meaning**). The
> *grill-with-docs* loop writes and supersedes ADRs inline as decisions crystallize. Start from
> `docs/adr/0000-template.md`.

## Conventions

- **One file per decision**, numbered sequentially: `0001-<slug>.md`, `0002-<slug>.md`, …
  Never renumber a published ADR — it's a stable anchor.
- **Title = the decision as its outcome**, not the question. "Sessions are pinned at first
  bind" — not "How should sessions bind?". A reader skimming filenames should see what was
  decided.
- **Four sections, always, in order:** `## Status`, `## Context`, `## Decision`,
  `## Consequences`. Add an optional `## Alternatives considered` when the rejected options carry
  real weight.

## The sections

- **Status** — `proposed` | `accepted` | `superseded`, plus a date. If it changes an earlier
  decision, link it: `supersedes [ADR-0003](0003-….md)`. When a later ADR overrides this one,
  come back and mark this one `superseded by …`. Be precise about *what* is superseded — a later
  ADR may reverse one mechanism while keeping another's framing.
- **Context** — the forces that made the decision necessary: constraints, the real problems
  (number them if several), what a reader who wasn't in the room needs to understand the *why*.
  Refer to terms by their canonical `CONTEXT.md` names.
- **Decision** — what was decided, stated plainly and **actively**. Include the specifics of what
  gets built / changed, and name the tempting alternative you rejected so it stays rejected.
- **Consequences** — what becomes true now, good *and* bad: breaking changes, new obligations
  (e.g. "new `REQ-*` ids to mint", "the integration checklist must be updated"), and what this
  forecloses or forces later.

## Tagging

If an ADR section is the `doc`-stage evidence for a requirement, tag it in place:
`<!-- [doc->REQ-…] -->` immediately above that section (see `docs/TRACEABILITY.md`).


Both experimplate dummies neutralized. Committing there — checking its trailer convention + remote first.


Bash

cd ../experimplate && echo "=== status ==="; git status --short; echo "=== last commit body ==="; git log -1 --format='%b'; echo "=== remote ==="; git remote -v | head -2; echo "RESET"

experimplate status, trailer convention, remote


=== status ===
 M docs/adr/0000-template.md
 M docs/formats/adr-format.md
=== last commit body ===
Bakes the positive/must-do framing practice into the governing doc-style doc
that scaffolded adapters inherit. Principle 7 (voice) now requires framing
guidance as what the reader must DO rather than must not do (flip prohibitions
into prescriptions, lead with the must-do, reserve descriptive negatives for
genuine system facts). Adds the inverse — guidance framed as prohibitions — to
the anti-patterns list.

Co-authored by: doyle

=== remote ===
origin	https://github.com/SaberMage/experimplate.git (fetch)
origin	https://github.com/SaberMage/experimplate.git (push)
RESET
Shell cwd was reset to C:\Users\decid\Documents\projects\spt-claude-code


experimplate uses a co-author trailer (its maintainer is doyle); I'll attribute honestly to perri (I did this edit). Committing + pushing.


cd ../experimplate && git add docs/adr/0000-template.md docs/formats/adr-format.md && git commit -q -F - <<'EOF'
docs(adr): neutralize template-dummy ADR number to NNNN placeholder

The ADR template + format guide illustrated `supersedes` with a concrete
`[ADR-0003](0003-old-decision.md)`. A bare numeric example can read as a real
ADR reference when scaffolded into a consumer repo. Switch to an unmistakable
`NNNN` placeholder so the example is obviously a fill-in, not a live link.
(Mirrors the same change in the first consumer, spt-claude-code.)

Co-authored by: perri
EOF
git log -1 --format='%h %s' && git push 2>&1 | tail -2; echo "RESET"

Commit + push experimplate neutralization


warning: in the working copy of 'docs/adr/0000-template.md', LF will be replaced by CRLF the next time Git touches it
warning: in the working copy of 'docs/formats/adr-format.md', LF will be replaced by CRLF the next time Git touches it
fa140af docs(adr): neutralize template-dummy ADR number to NNNN placeholder
To https://github.com/SaberMage/experimplate.git
   2f44ed5..fa140af  main -> main
RESET
Shell cwd was reset to C:\Users\decid\Documents\projects\spt-claude-code


All done. Everything committed + pushed across both repos. Release held per your call.

## What landed

**Docs recorded** for the 3 code changes (no new release):
- `CONTEXT.md` — glossary: Psyche, commune, psyche sandbox.
- `docs/adr/0003-*` — decision: Psyche = constrained auto-approving companion (legacy parity).
- `docs/KNOWN-HAZARDS.md §2.2` + `REQ-HAZARD-PSYCHE-PERMS-DEADLOCK` — non-interactive spt-spawned CC must skip-perms or deadlock (covers psyche turns + both `[session.self]` commands).
- `SCOPE.md` — dated ledger: deep removed, bringup skip-perms, psyche sandbox (LOCKED).
- Evidence: psyche test tagged + new `manifest-shortcut.sh` assertion (both bringup commands carry the flag).

**Leaked foreign ADRs wiped** — 34 `ADR-0003..0021` tokens / 16 files (doyle's spt-core numbering; only 0001/0002 real here). Prose preserved. Vendored schema edited in-place (still valid). ADR-0001/0002 kept.

**Template dummy neutralized** → `[ADR-NNNN](NNNN-…)` in both repos (the `0003` example read as real post-wipe).

## experimplate
Was **clean** — no leaked refs, only the same template dummy. Neutralized + committed there per your call.

## Commits
- `spt-claude-code` → `eab464b` (wipe) · `e23c666` (docs) · `19c0709` (dummy) — pushed `main`.
- `experimplate` → `fa140af` — pushed `main` (attributed `perri`).

Gates green throughout: traceable-reqs check, 9/9 unit sweep, docs-drift, schema.

**Held:** `dist/*.spt` still embed pre-sandbox psyche binary → rebuild on next versioned release. Memory updated. Ready for the next changes.


<task-notification>
<task-id>bpcwxkxh7</task-id>
Monitor event: "« spt event »"
<event><EVENT-PART seq="1/7" id="2cfa32a0" type="msg" from="doyle">spt-core v0.12.0 is PUBLISHED (live now) — the lifecycle &amp; liveness milestone. This is the one that restores endpoint-run / live-agent reliability, which directly unblocks your /sptc:live dogfooding.

Release: https://github.com/SaberMage/spt-releases/releases/tag/v0.12.0
Hashes (signed rel-primary-2026):</EVENT-PART>
<EVENT-PART seq="2/7" id="2cfa32a0">
  linux  spt-x86_64-linux        0458b5ae94a16207a61fddcfb10d1f087c95ea129c253d2af57454b8ca4df785
  win    spt-x86_64-windows.exe  6699be3d4256ccc64ab34ecb51bae6fe56aa4e4fcc80019db969f6176de3b6cd

What v0.12.0 fixes that affect your live agents:
- Brain kill/restart no longer wedges everything or leaves a duplicate Psyche (the </EVENT-PART>
<EVENT-PART seq="3/7" id="2cfa32a0">scenario that looked like yours).
- Attaching (spt rc) no longer hangs on a dead/silent session — it fails fast with a message.
- `spt daemon stop` now actually stops: it releases its sockets before returning AND reaps the agent + Psyche processes it launched (no orphans).
- Restarting the daemon no longer revives stale &quot;onlin</EVENT-PART>
<EVENT-PART seq="4/7" id="2cfa32a0">e&quot; agents that aren't really running.
- An agent's status now reflects real reachability (a daemon-hosted agent whose session died is marked offline next check, no more permanent &quot;online&quot;). IMPORTANT for you: agents reached over a RELAY are UNAFFECTED — your /sptc:live relay-hosted agents will NOT be wrongly marked offline.</EVENT-PART>
<EVENT-PART seq="5/7" id="2cfa32a0">
- Bonus: `spt endpoint purge &lt;id&gt;` (clean up an offline endpoint in one step) + offline agents now appear in the `spt endpoint run` resume-from-history picker.

NOTE: the empty-[env]-inject / NO_PERCH fix you hard-repro'd (F-013) was NOT in this release — it already shipped in v0.11.0. So upgrading to v0.12.0 gets you that to</EVENT-PART>
<EVENT-PART seq="6/7" id="2cfa32a0">o if you were still on an older build.

Action: rebuild your adapter against v0.12.0 and re-run the lifecycle paths (attach, daemon stop, brain restart). Confirm the wedge/orphan/attach-hang behaviors are gone on your side. Your deferred non-blocking FINDING A (pointer-mode adapter un-extracted-manifest → ADAPTER_UNRESOLVED, registry.r</EVENT-PART>
<EVENT-PART seq="7/7" id="2cfa32a0">s) is still queued separately — not in this release. Ping me with results or anything new.</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.


Inter-agent event from doyle (background) — **spt-core v0.12.0 published**. Summary + relevance:

**v0.12.0 = lifecycle/liveness milestone.** Fixes that touch our `/sptc:live` dogfooding:
- Brain kill/restart no longer wedges or leaves duplicate Psyche (looked like our scenario).
- `spt rc` attach fails fast on dead session (no hang).
- `spt daemon stop` releases sockets + reaps launched agent+Psyche (no orphans).
- Daemon restart won't revive stale "online" ghosts; status reflects real reachability.
- **Key for us: relay-hosted live agents UNAFFECTED** by the new offline-marking → our `/sptc:live` relay perches won't get wrongly marked offline.
- Bonus: `spt endpoint purge <id>`; offline agents show in `endpoint run` resume picker.

**Notes:**
- F-013 (empty-env-inject/NO_PERCH) was **already in 0.11.0**, not new here — we're past it.
- **FINDING A = our F-011** (pointer-mode adapter un-extracted-manifest → ADAPTER_UNRESOLVED) **still queued, NOT in 0.12.0.**
- Nothing forces a `min_spt_core` bump (still 0.9.0; ready/live work on 0.9.0).

**No action taken** — you're holding for a versioned release with more changes coming, and this is a background ping, not your go. doyle's requested action is "rebuild adapter against 0.12.0, re-run lifecycle paths (attach, daemon stop, brain restart), confirm wedge/orphan/hang gone."

When you're ready, options:
- **Fold into the held release** — bump floor only if a 0.12.0-only path lands, rebuild `dist/*.spt` (already pending the psyche-sandbox binary), run lifecycle re-validation.
- **Quick dogfood now** on 0.12.0 to confirm the wedge/orphan/attach-hang fixes, separate from the release.
- **Reply to doyle** (commune/send) with status.

Want any of those, or keep holding?


go ahead and publish the held release


On it. Release is outward-facing + multi-step — following the documented runbook exactly. Reading it + current state first.


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.)


Publishing. This is the adapter manifest+binary release (skeleton unchanged → no cplugs bump). Plan: bump adapter 0.3.0→0.4.0, CHANGELOG, rebuild both `dist/*.spt` (new psyche binary), tag, GH release with assets. Gathering state first.


echo "=== adapter version ==="; grep -E '^version' adapter/claude-spt.toml; echo "=== last tags ==="; git tag --sort=-v:refname | head -5; echo "=== CHANGELOG top ==="; sed -n '1,20p' CHANGELOG.md 2>/dev/null; echo "=== dist tracked? ==="; git ls-files dist/ | head; echo "=== gh auth ==="; gh auth status 2>&1 | head -3; echo "=== zig/zigbuild ==="; command -v zig && command -v cargo-zigbuild || echo "no-zig-cross"; echo "=== build scripts ==="; ls ci/digest/build.sh ci/psyche/build.sh ci/publish/package-adapter.sh 2>&1

Gather release state: versions, tags, changelog, gh auth, zig, scripts


=== adapter version ===
version = "0.3.0"
version = { file = "skills/version.md" }
=== last tags ===
v0.3.0
v0.2.1
v0.2.0
v0.1.0
=== CHANGELOG top ===
# 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.3.0] - 2026-06-17

### Changed
- **Going live is now a single, seamless step.** A live agent comes up directly — no behind-the-scenes
  adapter selection, no chained setup commands. `/sptc:live` just brings your session up live, and
  `/sptc:ready` brings it up reachable-but-light; the difference is simply which one you run. This is
  full parity with the original live-agent experience.
- **Requires spt-core 0.9.0 or newer.** This release uses spt-core's newer automatic
  harness-resolution, so the adapter now needs spt-core **0.9.0+**. If you keep spt-core up to date
  (it self-updates), there's nothing to do; on an older spt-core the adapter will decline to install
=== dist tracked? ===
=== gh auth ===
github.com
  ✓ Logged in to github.com account SaberMage (keyring)
  - Active account: true
=== zig/zigbuild ===
no-zig-cross
=== build scripts ===
ci/digest/build.sh
ci/psyche/build.sh
ci/publish/package-adapter.sh


State clear: bump to 0.4.0, `gh` authed as SaberMage, `dist/` untracked (build artifacts → release assets, not git). **Blocker: no `zig`/`cargo-zigbuild` on PATH** — needed to cross-build the linux `.spt`. Probing off-PATH locations + checking version-string source.


echo "=== cargo bin ==="; ls ~/.cargo/bin/ 2>/dev/null | grep -i zig || echo "no cargo-zigbuild in ~/.cargo/bin"; echo "=== sptc-zig ==="; ls ~/.sptc-zig/ 2>/dev/null && find ~/.sptc-zig -iname 'zig.exe' 2>/dev/null | head || echo "no ~/.sptc-zig"; echo "=== rustup linux target ==="; rustup target list --installed 2>/dev/null | grep linux || echo "no linux target"; echo "=== version.md hardcodes? ==="; grep -n '0\.[0-9]' adapter/strings/skills/version.md 2>/dev/null || echo "no hardcoded version in version.md"

Probe zig install locations + rustup target + version string


=== cargo bin ===
cargo-zigbuild.exe
=== sptc-zig ===
zig-x86_64-windows-0.14.1
/c/Users/decid/.sptc-zig/zig-x86_64-windows-0.14.1/zig.exe
=== rustup linux target ===
x86_64-unknown-linux-gnu
=== version.md hardcodes? ===
no hardcoded version in version.md


All cross-build tooling present (off-PATH): `cargo-zigbuild` in `~/.cargo/bin`, `zig.exe` in `~/.sptc-zig`, linux target installed. version.md not hardcoded. Full win+linux release is doable. `min_spt_core` stays 0.9.0 (we don't require 0.12.0).

Bumping version + writing 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)

# Floor BUMPED to 0.9.0 (2026-06-17, PREP-4): the legacy-parity bringup requires spt-core's

# adapter-agnostic seed + bind-time resolution by [adapter] host_binaries (shipped v0.9.0).

# On <0.9.0 `api seed`/`listen` still mandate --adapter, so the bare flow this manifest now wires


Edit

## [0.4.0] - 2026-06-18

### Changed
- **Your live-agent companion now runs in a safe, limited mode.** When you go live with
  `/sptc:live`, the background companion that writes your context-resume notes works with a
  file-only toolset and a lighter, cheaper model. It is more contained and costs less to run,
  with no change to what you see or do.
- **Removed the experimental `:deep` profile.** `claude-spt:deep` was an unused placeholder. The
  one shipped profile overlay is `claude-spt:ccs` (routes sessions through `ccs`). If you ever
  selected `:deep`, use `:ccs` or the base adapter instead.

### Fixed
- **Sessions that spt starts for you no longer stall on a permission prompt.** When spt brings up
  a Claude Code session on your behalf (the live companion, and the spt-hosted launcher), it could
  hang waiting on an approval prompt that no one was there to answer. Those sessions now start
  cleanly.

## [0.3.0] - 2026-06-17


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


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.3.0] - 2026-06-17
12

# 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.3.0] - 2026-06-17


## [0.4.0] - 2026-06-18

### Changed
- **Your live-agent companion now runs in a safe, limited mode.** When you go live with
  `/sptc:live`, the background companion that writes your context-resume notes works with a
  file-only toolset and a lighter, cheaper model. It is more contained and costs less to run,
  with no change to what you see or do.
- **Removed the experimental `:deep` profile.** `claude-spt:deep` was an unused placeholder. The
  one shipped profile overlay is `claude-spt:ccs` (routes sessions through `ccs`). If you ever
  selected `:deep`, use `:ccs` or the base adapter instead.

### Fixed
- **Sessions that spt starts for you no longer stall on a permission prompt.** When spt brings up
  a Claude Code session on your behalf (the live companion, and the spt-hosted launcher), it could
  hang waiting on an approval prompt that no one was there to answer. Those sessions now start
  cleanly.

## [0.3.0] - 2026-06-17


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.4.0] - 2026-06-18

### Changed
- **Your live-agent companion now runs in a safe, limited mode.** When you go live with
  `/sptc:live`, the background companion that writes your context-resume notes works with a
  file-only toolset and a lighter, cheaper model. It is more contained and costs less to run,
  with no change to what you see or do.
- **Removed the experimental `:deep` profile.** `claude-spt:deep` was an unused placeholder. The
  one shipped profile overlay is `claude-spt:ccs` (routes sessions through `ccs`). If you ever
  selected `:deep`, use `:ccs` or the base adapter instead.

### Fixed
- **Sessions that spt starts for you no longer stall on a permission prompt.** When spt brings up
  a Claude Code session on your behalf (the live companion, and the spt-hosted launcher), it could
  hang waiting on an approval prompt that no one was there to answer. Those sessions now start
  cleanly.

## [0.3.0] - 2026-06-17

# 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.3.0] - 2026-06-17

### Changed
- **Going live is now a single, seamless step.** A live agent comes up directly — no behind-the-scenes
  adapter selection, no chained setup commands. `/sptc:live` just brings your session up live, and
  `/sptc:ready` brings it up reachable-but-light; the difference is simply which one you run. This is
  full parity with the original live-agent experience.
- **Requires spt-core 0.9.0 or newer.** This release uses spt-core's newer automatic
  harness-resolution, so the adapter now needs spt-core **0.9.0+**. If you keep spt-core up to date
  (it self-updates), there's nothing to do; on an older spt-core the adapter will decline to install
  until you update.

### Fixed
- **Setup pins this adapter as your default.** `/sptc:setup` now records `claude-spt` as the active
  adapter for Claude Code, so going live or ready needs no extra flags.

## [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.** 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.

+- **Your live-agent companion now runs in a safe, limited mode.** When you go live with

+  `/sptc:live`, the background companion that writes your context-resume notes works with a

+  file-only toolset and a lighter, cheaper model. It is more contained and costs less to run,

+  with no change to what you see or do.

+- **Removed the experimental `:deep` profile.** `claude-spt:deep` was an unused placeholder. The

+  one shipped profile overlay is `claude-spt:ccs` (routes sessions through `ccs`). If you ever

+  selected `:deep`, use `:ccs` or the base adapter instead.

+- **Sessions that spt starts for you no longer stall on a permission prompt.** When spt brings up

+  a Claude Code session on your behalf (the live companion, and the spt-hosted launcher), it could

+  hang waiting on an approval prompt that no one was there to answer. Those sessions now start


Version + changelog done. Running full gates before committing the release commit.


Bash

command -v traceable-reqs >/dev/null 2>&1 && { traceable-reqs check >/tmp/tr.txt 2>&1; echo "traceable exit=$?"; }; echo "=== unit sweep ==="; pass=0; fail=0; for t in tests/*.sh; do if sh "$t" >/dev/null 2>&1; then pass=$((pass+1)); else fail=$((fail+1)); echo "FAIL $t"; fi; done; echo "unit: $pass ok, $fail fail"; echo "=== manifest still validates (0.4.0) ==="; sh ci/manifest/check-manifest.sh 2>&1 | tail -1

Run gates after version bump


traceable exit=0
=== unit sweep ===
unit: 9 ok, 0 fail
=== manifest still validates (0.4.0) ===
ok   manifest validates against published manifest.schema.json


Gates green (traceable exit 0, 9/9 unit, manifest 0.4.0 valid). Committing release prep, then building artifacts.


git add adapter/claude-spt.toml CHANGELOG.md
git commit -q -F - <<'EOF'
chore(release): v0.4.0 — psyche sandbox, skip-perms bringup, :deep removal

Adapter version-of-truth 0.3.0 -> 0.4.0. min_spt_core stays 0.9.0 (no 0.12.0-only
path; lifecycle reliability is spt-core's, transparent to the adapter).

User-facing CHANGELOG [0.4.0]: live companion runs sandboxed (file-only tools,
lighter model); `:deep` placeholder profile removed (use `:ccs`); spt-hosted
sessions no longer stall on an unanswerable permission prompt.

Skeleton unchanged this release -> NO cplugs bump (plugin.json stays 0.1.3); ships
to the spt-core adapter registry as rebuilt dist/*.spt assets (new psyche binary).

Co-authored by: perri
EOF
git log -1 --format='%h %s'

Commit v0.4.0 release prep


ba43a89 chore(release): v0.4.0 — psyche sandbox, skip-perms bringup, :deep removal


Building **windows** asset (native): digest + psyche release binaries, then pack.


sh ci/digest/build.sh 2>&1 | tail -3 && echo "--- psyche ---" && sh ci/psyche/build.sh 2>&1 | tail -3

Build digest + psyche release binaries (windows native)


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
--- psyche ---
test result: ok. 11 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

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


Binaries built (psyche 11/11 incl sandbox test). Packing windows asset — dry-run then apply.


echo "=== DRY RUN ==="; sh ci/publish/package-adapter.sh 2>&1 | tail -20

Dry-run windows adapter pack


=== DRY RUN ===

== tool binaries ==
  ok    /c/Users/decid/Documents/projects/spt-claude-code/tools/claude-spt-digest/target/release/claude-spt-digest.exe
  ok    /c/Users/decid/Documents/projects/spt-claude-code/tools/claude-spt-psyche/target/release/claude-spt-psyche.exe

== plan (DRY-RUN) ==
manifest : /c/Users/decid/Documents/projects/spt-claude-code/adapter/claude-spt.toml  ->  (archive root) manifest.toml
strings  : /c/Users/decid/Documents/projects/spt-claude-code/adapter/strings/  ->  (archive root) strings/
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.

DRY-RUN: nothing written. Re-run with --apply to write /c/Users/decid/Documents/projects/spt-claude-code/dist/adapter-windows-x86_64.spt, then attach it to a GitHub
release on the monorepo. End users acquire it with 'spt adapter add --release
SaberMage/spt-claude-code --asset adapter-windows-x86_64.spt' (see docs/RELEASE-RUNBOOK.md). Needs spt v0.7.3+.


sh ci/publish/package-adapter.sh --apply 2>&1 | tail -5; echo "=== verify ==="; ls -la dist/adapter-windows-x86_64.spt

Write windows adapter asset


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.
=== verify ===
-rw-r--r-- 1 decid 197609 270299 Jun 18 16:01 dist/adapter-windows-x86_64.spt


Windows asset written (270KB). Now **linux** cross-build via zigbuild (zig on PATH).


export PATH="$HOME/.sptc-zig/zig-x86_64-windows-0.14.1:$PATH"
command -v zig && zig version
echo "=== zigbuild digest ==="
cargo zigbuild --release --target x86_64-unknown-linux-gnu --manifest-path tools/claude-spt-digest/Cargo.toml 2>&1 | tail -4
echo "=== zigbuild psyche ==="
cargo zigbuild --release --target x86_64-unknown-linux-gnu --manifest-path tools/claude-spt-psyche/Cargo.toml 2>&1 | tail -4

Cross-build both crates for linux via zigbuild


/c/Users/decid/.sptc-zig/zig-x86_64-windows-0.14.1/zig
0.14.1
=== zigbuild digest ===
   Compiling claude-spt-digest v0.1.0 (C:\Users\decid\Documents\projects\spt-claude-code\tools\claude-spt-digest)
    Finished `release` profile [optimized] target(s) in 9.97s
=== zigbuild psyche ===
   Compiling claude-spt-psyche v0.1.0 (C:\Users\decid\Documents\projects\spt-claude-code\tools\claude-spt-psyche)
    Finished `release` profile [optimized] target(s) in 0.94s


Both cross-built. Packing linux asset.


echo "=== verify ELF binaries ==="; file tools/claude-spt-psyche/target/x86_64-unknown-linux-gnu/release/claude-spt-psyche 2>/dev/null; file tools/claude-spt-digest/target/x86_64-unknown-linux-gnu/release/claude-spt-digest 2>/dev/null
echo "=== pack linux ==="
SPTC_OS=linux SPTC_ARCH=x86_64 SPTC_TARGET=x86_64-unknown-linux-gnu sh ci/publish/package-adapter.sh --apply 2>&1 | tail -4
echo "=== dist ==="; ls -la dist/*.spt

Verify ELF + pack linux adapter asset


=== verify ELF binaries ===
tools/claude-spt-psyche/target/x86_64-unknown-linux-gnu/release/claude-spt-psyche: 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
tools/claude-spt-digest/target/x86_64-unknown-linux-gnu/release/claude-spt-digest: 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
=== pack linux ===

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.
=== dist ===
-rw-r--r-- 1 decid 197609 471778 Jun 18 16:01 dist/adapter-linux-x86_64.spt
-rw-r--r-- 1 decid 197609 270299 Jun 18 16:01 dist/adapter-windows-x86_64.spt


Both assets built — windows (270KB, .exe), linux (471KB, verified ELF). Pushing release commit, tagging, then GH release.


git push 2>&1 | tail -2
echo "=== tag ==="
git tag v0.4.0 && git push origin v0.4.0 2>&1 | tail -2
echo "=== current ==="; git log -1 --format='%h %s'; git tag --points-at HEAD

Push release commit + tag v0.4.0


To https://github.com/SaberMage/spt-claude-code.git
   19c0709..ba43a89  main -> main
=== tag ===
To https://github.com/SaberMage/spt-claude-code.git
 * [new tag]         v0.4.0 -> v0.4.0
=== current ===
ba43a89 chore(release): v0.4.0 — psyche sandbox, skip-perms bringup, :deep removal
v0.4.0


Pushed + tagged. Creating the GitHub release with both assets and the changelog body.


cat > /tmp/rel-0.4.0.md <<'EOF'
### Changed
- **Your live-agent companion now runs in a safe, limited mode.** When you go live with `/sptc:live`, the background companion that writes your context-resume notes works with a file-only toolset and a lighter, cheaper model. It is more contained and costs less to run, with no change to what you see or do.
- **Removed the experimental `:deep` profile.** `claude-spt:deep` was an unused placeholder. The one shipped profile overlay is `claude-spt:ccs` (routes sessions through `ccs`). If you ever selected `:deep`, use `:ccs` or the base adapter instead.

### Fixed
- **Sessions that spt starts for you no longer stall on a permission prompt.** When spt brings up a Claude Code session on your behalf (the live companion, and the spt-hosted launcher), it could hang waiting on an approval prompt that no one was there to answer. Those sessions now start cleanly.

---
**Install / update (per-OS adapter asset):**
```
spt adapter add --release SaberMage/spt-claude-code --asset adapter-windows-x86_64.spt   # Windows
spt adapter add --release SaberMage/spt-claude-code --asset adapter-linux-x86_64.spt     # Linux
```
`/sptc:setup` picks the right asset for your OS automatically. Requires spt-core 0.9.0+.
EOF
gh release create v0.4.0 \
  --repo SaberMage/spt-claude-code \
  --title "v0.4.0" \
  --notes-file /tmp/rel-0.4.0.md \
  dist/adapter-windows-x86_64.spt dist/adapter-linux-x86_64.spt 2>&1 | tail -5

Create GH release v0.4.0 with both per-OS assets


Release created. Verifying assets attached.


gh release view v0.4.0 --repo SaberMage/spt-claude-code --json tagName,name,assets,isDraft --jq '{tag:.tagName, name:.name, draft:.isDraft, assets:[.assets[].name]}'

Verify release + attached assets


Memory update + final report.


Edit

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

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