1	# spt-claude-code — scoping decision ledger
2
3	> Running source of truth for the scoping session (started 2026-06-13, doyle).
4	> Decisions marked **LOCKED** are user-ratified; **OPEN** are still in grill.
5	> This project will be re-homed onto the `experimplate` template structure once
6	> that template is authored — until then this ledger is the interim record.
7
8	## What this project is
9
10	**LOCKED.** `spt-claude-code` is the rebuilt Claude Code harness adapter (the
11	`claude-spt` adapter) — simultaneously:
12	1. spt-core's **v1 acceptance proof** (feature parity with legacy `claude_skill_owl`,
13	   delegating all core to `spt.exe`).
14	2. spt-core's **first casual-end-user entrypoint** — published as a CC plugin on
15	   `SaberMage/cplugs`, like legacy spt today.
16	3. Invisibly an **spt-core installer** for users who don't have it. This is the
17	   intended pattern for *all* casual-facing harness/shell adapters.
18
19	Parity is **user-facing feature parity, NOT 1:1** — most legacy machinery moved
20	INTO spt.exe/daemon; the adapter is the CC-specific shell only. Dead/rare legacy
21	concepts get dropped (parity-trim → REQ seed, OPEN). Built by maintainer **perri**
22	from `SaberMage/spt-releases` + GH Pages docs ONLY (public surface), never the
23	spt-core source tree.
24
25	Legacy parity inventory: captured in this session (claude_skill_owl v1.11.25 —
26	7 hooks, 12 `/spt:*` skills, owl.exe, cplugs marketplace; messaging / live-agent /
27	working-perches / binary-handoff / psyche-sync / doctor).
28
29	## Distribution architecture
30
31	**LOCKED.** Split by volatility (Claude Code has NO plugin-file integrity check —
32	in-place edits don't orphan; only old version dirs orphan on update, GC'd 7d):
33
34	| Layer | Contents | Home | Update path | Churn |
35	|---|---|---|---|---|
36	| Plugin (marketplace) | namespaced `/spt:*` skill *skeletons*, `hooks.json` (call `spt api`), SessionStart bootstrap (installs spt-core if absent), `plugin.json` | `SaberMage/cplugs` | `claude plugin update` (rare structural changes only) | low |
37	| spt binary | all logic | spt-core domain | spt-core's own framework (signed, peer-propagated) | high |
38	| CC adapter manifest | `[digest]` extractor, profiles, strings, hints | spt-core adapter registry (NOT plugin files) | spt-core adapter-update (file-pull) | medium |
39
40	- Skills stay **plugin-provided** → keep `/spt:` namespace (user-scope skills can't
41	  namespace: `~/.claude/skills` → bare `/live`, collision-prone). Rejected global-skills.
42	- The "bulk" spt-core installs/updates = **manifest + binary**, not the skills.
43	- Plugin is a true thin skeleton (wrappers + bootstrap) → rarely needs a marketplace bump.
44	- → ADR-0001 (to write).
45
46	### Skill-instruction delivery — **LOCKED: UPS-injection** (fetch-stub VETOED)
47
48	A `UserPromptSubmit` hook detects `/spt:X` in the prompt and injects X's real
49	instructions as additionalContext. SKILL.md files stay skeletons; instruction churn
50	lives in spt-core-conducted `[strings]` (file-backed — see M12 dep).
51	- **fetch-stub VETOED** (operator): adds terminal noise + latency + an extra tool call.
52	- UPS-injection chosen on operator's empirical confidence from legacy: UPS *does* pick up
53	  slash-commands (CC highlights slash-commands anywhere in the entry field and isn't strict
54	  about trailing text). My fact-check called this undocumented/uncertain — **must confirm
55	  empirically at build time**, but design on it.
56	- Long instruction bodies → **file-backed adapter strings** (M12 spt-core dep #1) so the
57	  manifest doesn't bloat.
58	- `[hints]` channel (same UPS hook, keyword-triggered) kept as-is — legacy proves it works.
59
60	### Update notification — **LOCKED**
61
62	spt-core conducts updates seamlessly → users don't check. Version-of-truth =
63	manifest/binary version spt-core tracks (`spt adapter list` / `/spt:version`), NOT the
64	~static marketplace skeleton version. On update applied: spt-core announces via one-time
65	SessionStart additionalContext (changelog) + optional `notify`. Update path = file-pull
66	(real channel) + cautionary `claude plugin update` (skeleton sync) — dual, kept in sync.
67
68	## ccs integration
69
70	**LOCKED.** ccs = **profile(s) under spt-claude-code** (`claude-spt:glm`,
71	`claude-spt:kimi`, …), NOT its own adapter. It's structurally CC — only launch command +
72	model/billing backend differ, which is exactly the profile seam (leaf-replace
73	spawn/psyche/echo command templates). Per-profile `~/.ccs` log dir → profile also
74	leaf-replaces the history/`[digest]` locate-template. **Hybrid** delivery: ship the
75	profile *templates* (ccs-invoking command structure), user supplies own ccs config/keys.
76	Reconcile spt-core CONTEXT.md: cross-adapter fallback must target `<adapter>:<profile>`,
77	not only bare adapter_name (profile model already supports composite addressing).
78
79	## `/spt:setup` skill
80
81	Needed because most users install the plugin **mid-session** (no SessionStart fire).
82	Proposed paths:
83	1. Generate `cc`/`cc <id>` launcher (capsule-style) at project root
84	2. Offer `.gitignore` the launchers
85	3. Offer create first subnet — surfaces a **QR code** of the TOTP seed → spawns a window
86	   (self-elevating; see elevation + M12 dep #2)
87	4. If spt-core already installed → branch: new subnet / **join subnet (= add this machine)** /
88	   show join-code / just-add-endpoint  *(join == add-this-machine — collapsed)*
89	5. Legacy migration — detect claude_skill_owl/owl → migrate identity+agents+psyche
90	   (spt-core CONTEXT.md first-class commitment)
91	6. OS-service registration (always-on daemon)
92	7. ccs profile wiring — if `~/.ccs` present; **also offer to install ccs** (+1-sentence value
93	   prop) if absent
94	8. Psyche cross-machine sync — **in-subnet sync is AUTOMATIC** (confirmed, M4-D6c); only the
95	   optional off-subnet/hub-mode backup remains, retired-as-default → near-zero v1 surface
96	9. Doctor/verify at end
97
98	**LOCKED:** v1 = {1,2,3,4,5,6,7}, defer {8,9}. Item #1 (`cc` launcher) IS in v1 — depends on
99	full-fat M12 (gating prerequisite, todlando-built before perri starts). `cc` wraps
100	`spt endpoint run` defaulted to claude-spt. _Operator "9. agree" then "except 9" — deferred 9;
101	flag if verify should fold inline._
102
103	### `cc` launcher (capsule-style) — **LOCKED (design)**
104
105	= thin wrapper over spt-core's **spt-hosted topology** (broker PTY + inject + attach),
106	NOT a reimplemented psmux. `cc <id>` → `spt` spawns-or-attaches a CC endpoint in a broker
107	PTY. Reattach-if-exists / `--live` / `--resume` = spt-core spawn/resume seam semantics.
108	No-id picker = reuse spt-core's built-in id-resolution (don't reimplement legacy SEED-001).
109	Sendkeys hazards = spt-core's inject concern, not the adapter's.
110	**OPEN gap:** confirm spt-core "remote attach" covers *local user interactive attach* to a
111	hosted CC session (not just headless PTY).
112
113	### Elevation (subnet create/join/show-totp) — **LOCKED (design)**
114
115	Detect (interactive? elevated? desktop?) → least-friction path:
116	Windows = self-elevating UAC window; Linux+desktop = pkexec/polkit or x-terminal-emulator;
117	Linux+TTY = inline sudo; headless/no-TTY = print exact command, agent relays to user.
118	Question the premise: scope elevation to only steps that need it (service-install /
119	firewall / privileged-port) — subnet-create itself likely unprivileged.
120
121	## CI model
122
123	**LOCKED.** Wholly **agent-driven, autonomous, no LLM-in-the-loop**, on the existing
124	Win+Linux fleet (hfenduleam + kitsubito). GH runners DROPPED.
125	- Gates (build, unit, `traceable-reqs check`, manifest-schema) = deterministic scripts.
126	- Acceptance = scripted orchestration spawning real `claude`/headless sessions as the
127	  **system-under-test** (LLM is SUT, never the runner); assert spt-state/digest output.
128	- **Reporting bus = legacy spt** (`$OWL send` CI progress to responsible agent) — dogfoods
129	  the product as its own CI nervous system.
130	- Rationale: a stock GH runner physically can't run Claude Code (auth/interactivity);
131	  only a real harness on the fleet reaches the acceptance bar. spt-core's GH-runner
132	  justification (heavy multi-platform Rust + signed releases + two-host net) doesn't carry
133	  — the adapter binary is thin glue and delegates releases/signing to spt.exe.
134	- **Trigger (LOCKED):** git post-push hook → `$OWL send` pings a fleet runner-agent → runs
135	  gates → reports over spt. Manual "run gates" = fallback. (Polling rejected: latency + waste.)
136	  - **NOTE:** the `$OWL send` (legacy spt) binary location must be discovered flexibly — it
137	    lives in a per-version `~/.claude/` or `~/.ccs/` plugins folder whose path changes each
138	    version. No further legacy-spt changes anticipated, but the CI bus must locate it robustly.
139	- This CI pattern → reusable, goes in `experimplate`.
140
141	## Parity-trim (→ REQ seed / acceptance bar)
142
143	**DROP** (LOCKED): Spine & Touch; binary-handoff/owl.exe trampoline; TCP transport + SQLite
144	spool + registry + listener internals; localhost-only networking. (all spt.exe/daemon now)
145
146	**TRANSFORM** (LOCKED): Capsule→spt-hosted + `cc`; echo-commune Haiku JSONL→`[digest]`
147	extractor (M10); psyche-sync→subnet/`/spt:setup`; `doctor`→`spt doctor`/setup-verify;
148	working-perches→`api worker-start/stop`.
149
150	**ADD** (LOCKED): `/spt:setup`, `/spt:version`, subnet skills (create/join/show-code),
151	profiles + strings + hints wiring, ccs profiles.
152
153	**DECIDE** (LOCKED): DROP `/spt:fork` + `amend-signoff`. (fork near-unused & only meaningful
154	harness-hosted; amend-signoff deprecated, folds into a follow-up commune)
155
156	**KEEP — FINALIZED** (post-investigation 2026-06-14):
157	- `/live`, `/commune`, `/ready`, `/send`, `/new-alarm`, `/list-agents` — KEEP. (`/list-agents`
158	  → `spt endpoint list`.)
159	- `/signoff` — KEEP. v1 = harness-hosted semantics (writes file; consumed at teardown). The
160	  spt-hosted "drop user from PTY" UX only applies once `cc`/local-attach lands (fast-follow).
161	- `/force-stop` — KEEP, topology-aware. spt-hosted routing already has CLI: `spt endpoint
162	  shutdown` (graceful) + `spt endpoint stop` (soft), both exist.
163	- `/revive` — **DROP.** Daemon owns psyche-loop + liveness (no orphan/dead-listener states to
164	  recover); restart = re-`ready`/re-`listen` or `endpoint stop`+bringup. Confirm.
165	- `/clear-psyche` — **DROP.** Equivalent = delete + recreate endpoint. Confirm.
166	- `/whoami` — **DROP skill**. Core `spt whoami` STAYS in hot-path but → **becomes an alias for
167	  `spt endpoint list`** (M12), whose SELF-pin output gains the Self `endpoint description`.
168
169	### v1 topology scope — **LOCKED** (operator vetoed harness-hosted-only)
170	v1 acceptance = legacy parity **AND** cross-subnet/PTY proof (spt-core's central value prop is
171	networking + PTY ownership). So **spt-hosted mode + local PTY attach + `spt endpoint run`
172	picker are MANDATORY v1.** → `cc` launcher is IN v1; `/spt:setup` #1 back in v1.
173	**Gating prerequisite: full-fat M12 (todlando builds it after this grill, BEFORE perri starts
174	spt-claude-code).** M12 deliverables incl. `spt endpoint run` (picker — see
175	`../spt-core/M12-ENDPOINT-RUN-PICKER.md`) + `spt rc` (cross-node PTY connect) + whoami→alias.
176
177	## spt-core upstream deps
178	Recorded in `../spt-core/M12-CANDIDATES.md` (1: file-backed strings · 2: subnet QR +
179	self-elevating window · 3: spt-hosted bringup + PTY attach · 4: fallback targets
180	adapter:profile · 5: whoami obsolescence). spt-claude-code blocks on these.
181
182	## experimplate (template) — resolved content
183	- **Release procedure = generic shape + placeholders** (CHANGELOG · version bump · tag · GH
184	  Release on same repo); project fills publish specifics. spt-claude-code's publish = cplugs
185	  marketplace + spt-core adapter-registry; **release is light — signing delegated to spt.exe**
186	  (not spt-core's two-key/counter runbook).
187	- **Docs = same-repo `docs-site/` → GH Pages, mdBook, CI-gated against drift.** Reuse
188	  **spt-core's docs CSS / page-layout / styling as a shared transferable theme** (it's strong;
189	  carry it across all consumer projects). DOCS-STRATEGY reframed separate-repo→same-repo.
190	- AGENTS.md = source of truth + thin `CLAUDE.md`=`@AGENTS.md` stub.
191	- Must teach acquisition of `traceable-reqs` + the grill-with-docs skill (toml/INSTANTIATE).
192
193	## Open threads (grill queue)
194
195	- [ ] CI trigger mechanism (git-hook signal vs polling routine)
196	- [ ] Handoff framing to perri (package presentation + public-surface-only constraint)
197	- [ ] Docs split: what lands in experimplate vs spt-claude-code
198	- [ ] experimplate authoring: finalize skeleton + write INSTANTIATE.md
199	- [ ] (downstream) confirm `/spt:setup` #9 verify fold-inline vs deferred
200

# spt-claude-code — scoping decision ledger

> Running source of truth for the scoping session (started 2026-06-13, doyle).
> Decisions marked **LOCKED** are user-ratified; **OPEN** are still in grill.
> This project will be re-homed onto the `experimplate` template structure once
> that template is authored — until then this ledger is the interim record.

## What this project is

**LOCKED.** `spt-claude-code` is the rebuilt Claude Code harness adapter (the
`claude-spt` adapter) — simultaneously:
1. spt-core's **v1 acceptance proof** (feature parity with legacy `claude_skill_owl`,
   delegating all core to `spt.exe`).
2. spt-core's **first casual-end-user entrypoint** — published as a CC plugin on
   `SaberMage/cplugs`, like legacy spt today.
3. Invisibly an **spt-core installer** for users who don't have it. This is the
   intended pattern for *all* casual-facing harness/shell adapters.

Parity is **user-facing feature parity, NOT 1:1** — most legacy machinery moved
INTO spt.exe/daemon; the adapter is the CC-specific shell only. Dead/rare legacy
concepts get dropped (parity-trim → REQ seed, OPEN). Built by maintainer **perri**
from `SaberMage/spt-releases` + GH Pages docs ONLY (public surface), never the
spt-core source tree.

Legacy parity inventory: captured in this session (claude_skill_owl v1.11.25 —
7 hooks, 12 `/spt:*` skills, owl.exe, cplugs marketplace; messaging / live-agent /
working-perches / binary-handoff / psyche-sync / doctor).

## Distribution architecture

**LOCKED.** Split by volatility (Claude Code has NO plugin-file integrity check —
in-place edits don't orphan; only old version dirs orphan on update, GC'd 7d):

| Layer | Contents | Home | Update path | Churn |
|---|---|---|---|---|
| Plugin (marketplace) | namespaced `/spt:*` skill *skeletons*, `hooks.json` (call `spt api`), SessionStart bootstrap (installs spt-core if absent), `plugin.json` | `SaberMage/cplugs` | `claude plugin update` (rare structural changes only) | low |
| spt binary | all logic | spt-core domain | spt-core's own framework (signed, peer-propagated) | high |
| CC adapter manifest | `[digest]` extractor, profiles, strings, hints | spt-core adapter registry (NOT plugin files) | spt-core adapter-update (file-pull) | medium |

- Skills stay **plugin-provided** → keep `/spt:` namespace (user-scope skills can't
  namespace: `~/.claude/skills` → bare `/live`, collision-prone). Rejected global-skills.
- The "bulk" spt-core installs/updates = **manifest + binary**, not the skills.
- Plugin is a true thin skeleton (wrappers + bootstrap) → rarely needs a marketplace bump.
- → ADR-0001 (to write).

### Skill-instruction delivery — **LOCKED: UPS-injection** (fetch-stub VETOED)

A `UserPromptSubmit` hook detects `/spt:X` in the prompt and injects X's real
instructions as additionalContext. SKILL.md files stay skeletons; instruction churn
lives in spt-core-conducted `[strings]` (file-backed — see M12 dep).
- **fetch-stub VETOED** (operator): adds terminal noise + latency + an extra tool call.
- UPS-injection chosen on operator's empirical confidence from legacy: UPS *does* pick up
  slash-commands (CC highlights slash-commands anywhere in the entry field and isn't strict
  about trailing text). My fact-check called this undocumented/uncertain — **must confirm
  empirically at build time**, but design on it.
- Long instruction bodies → **file-backed adapter strings** (M12 spt-core dep #1) so the
  manifest doesn't bloat.
- `[hints]` channel (same UPS hook, keyword-triggered) kept as-is — legacy proves it works.

### Update notification — **LOCKED**

spt-core conducts updates seamlessly → users don't check. Version-of-truth =
manifest/binary version spt-core tracks (`spt adapter list` / `/spt:version`), NOT the
~static marketplace skeleton version. On update applied: spt-core announces via one-time
SessionStart additionalContext (changelog) + optional `notify`. Update path = file-pull
(real channel) + cautionary `claude plugin update` (skeleton sync) — dual, kept in sync.

## ccs integration

**LOCKED.** ccs = **profile(s) under spt-claude-code** (`claude-spt:glm`,
`claude-spt:kimi`, …), NOT its own adapter. It's structurally CC — only launch command +
model/billing backend differ, which is exactly the profile seam (leaf-replace
spawn/psyche/echo command templates). Per-profile `~/.ccs` log dir → profile also
leaf-replaces the history/`[digest]` locate-template. **Hybrid** delivery: ship the
profile *templates* (ccs-invoking command structure), user supplies own ccs config/keys.
Reconcile spt-core CONTEXT.md: cross-adapter fallback must target `<adapter>:<profile>`,
not only bare adapter_name (profile model already supports composite addressing).

## `/spt:setup` skill

Needed because most users install the plugin **mid-session** (no SessionStart fire).
Proposed paths:
1. Generate `cc`/`cc <id>` launcher (capsule-style) at project root
2. Offer `.gitignore` the launchers
3. Offer create first subnet — surfaces a **QR code** of the TOTP seed → spawns a window
   (self-elevating; see elevation + M12 dep #2)
4. If spt-core already installed → branch: new subnet / **join subnet (= add this machine)** /
   show join-code / just-add-endpoint  *(join == add-this-machine — collapsed)*
5. Legacy migration — detect claude_skill_owl/owl → migrate identity+agents+psyche
   (spt-core CONTEXT.md first-class commitment)
6. OS-service registration (always-on daemon)
7. ccs profile wiring — if `~/.ccs` present; **also offer to install ccs** (+1-sentence value
   prop) if absent
8. Psyche cross-machine sync — **in-subnet sync is AUTOMATIC** (confirmed, M4-D6c); only the
   optional off-subnet/hub-mode backup remains, retired-as-default → near-zero v1 surface
9. Doctor/verify at end

**LOCKED:** v1 = {1,2,3,4,5,6,7}, defer {8,9}. Item #1 (`cc` launcher) IS in v1 — depends on
full-fat M12 (gating prerequisite, todlando-built before perri starts). `cc` wraps
`spt endpoint run` defaulted to claude-spt. _Operator "9. agree" then "except 9" — deferred 9;
flag if verify should fold inline._

### `cc` launcher (capsule-style) — **LOCKED (design)**

= thin wrapper over spt-core's **spt-hosted topology** (broker PTY + inject + attach),
NOT a reimplemented psmux. `cc <id>` → `spt` spawns-or-attaches a CC endpoint in a broker
PTY. Reattach-if-exists / `--live` / `--resume` = spt-core spawn/resume seam semantics.
No-id picker = reuse spt-core's built-in id-resolution (don't reimplement legacy SEED-001).
Sendkeys hazards = spt-core's inject concern, not the adapter's.
**OPEN gap:** confirm spt-core "remote attach" covers *local user interactive attach* to a
hosted CC session (not just headless PTY).

### Elevation (subnet create/join/show-totp) — **LOCKED (design)**

Detect (interactive? elevated? desktop?) → least-friction path:
Windows = self-elevating UAC window; Linux+desktop = pkexec/polkit or x-terminal-emulator;
Linux+TTY = inline sudo; headless/no-TTY = print exact command, agent relays to user.
Question the premise: scope elevation to only steps that need it (service-install /
firewall / privileged-port) — subnet-create itself likely unprivileged.

## CI model

**LOCKED.** Wholly **agent-driven, autonomous, no LLM-in-the-loop**, on the existing
Win+Linux fleet (hfenduleam + kitsubito). GH runners DROPPED.
- Gates (build, unit, `traceable-reqs check`, manifest-schema) = deterministic scripts.
- Acceptance = scripted orchestration spawning real `claude`/headless sessions as the
  **system-under-test** (LLM is SUT, never the runner); assert spt-state/digest output.
- **Reporting bus = legacy spt** (`$OWL send` CI progress to responsible agent) — dogfoods
  the product as its own CI nervous system.
- Rationale: a stock GH runner physically can't run Claude Code (auth/interactivity);
  only a real harness on the fleet reaches the acceptance bar. spt-core's GH-runner
  justification (heavy multi-platform Rust + signed releases + two-host net) doesn't carry
  — the adapter binary is thin glue and delegates releases/signing to spt.exe.
- **Trigger (LOCKED):** git post-push hook → `$OWL send` pings a fleet runner-agent → runs
  gates → reports over spt. Manual "run gates" = fallback. (Polling rejected: latency + waste.)
  - **NOTE:** the `$OWL send` (legacy spt) binary location must be discovered flexibly — it
    lives in a per-version `~/.claude/` or `~/.ccs/` plugins folder whose path changes each
    version. No further legacy-spt changes anticipated, but the CI bus must locate it robustly.
- This CI pattern → reusable, goes in `experimplate`.

## Parity-trim (→ REQ seed / acceptance bar)

**DROP** (LOCKED): Spine & Touch; binary-handoff/owl.exe trampoline; TCP transport + SQLite
spool + registry + listener internals; localhost-only networking. (all spt.exe/daemon now)

**TRANSFORM** (LOCKED): Capsule→spt-hosted + `cc`; echo-commune Haiku JSONL→`[digest]`
extractor (M10); psyche-sync→subnet/`/spt:setup`; `doctor`→`spt doctor`/setup-verify;
working-perches→`api worker-start/stop`.

**ADD** (LOCKED): `/spt:setup`, `/spt:version`, subnet skills (create/join/show-code),
profiles + strings + hints wiring, ccs profiles.

**DECIDE** (LOCKED): DROP `/spt:fork` + `amend-signoff`. (fork near-unused & only meaningful
harness-hosted; amend-signoff deprecated, folds into a follow-up commune)

**KEEP — FINALIZED** (post-investigation 2026-06-14):
- `/live`, `/commune`, `/ready`, `/send`, `/new-alarm`, `/list-agents` — KEEP. (`/list-agents`
  → `spt endpoint list`.)
- `/signoff` — KEEP. v1 = harness-hosted semantics (writes file; consumed at teardown). The
  spt-hosted "drop user from PTY" UX only applies once `cc`/local-attach lands (fast-follow).
- `/force-stop` — KEEP, topology-aware. spt-hosted routing already has CLI: `spt endpoint
  shutdown` (graceful) + `spt endpoint stop` (soft), both exist.
- `/revive` — **DROP.** Daemon owns psyche-loop + liveness (no orphan/dead-listener states to
  recover); restart = re-`ready`/re-`listen` or `endpoint stop`+bringup. Confirm.
- `/clear-psyche` — **DROP.** Equivalent = delete + recreate endpoint. Confirm.
- `/whoami` — **DROP skill**. Core `spt whoami` STAYS in hot-path but → **becomes an alias for
  `spt endpoint list`** (M12), whose SELF-pin output gains the Self `endpoint description`.

### v1 topology scope — **LOCKED** (operator vetoed harness-hosted-only)
v1 acceptance = legacy parity **AND** cross-subnet/PTY proof (spt-core's central value prop is
networking + PTY ownership). So **spt-hosted mode + local PTY attach + `spt endpoint run`
picker are MANDATORY v1.** → `cc` launcher is IN v1; `/spt:setup` #1 back in v1.
**Gating prerequisite: full-fat M12 (todlando builds it after this grill, BEFORE perri starts
spt-claude-code).** M12 deliverables incl. `spt endpoint run` (picker — see
`../spt-core/M12-ENDPOINT-RUN-PICKER.md`) + `spt rc` (cross-node PTY connect) + whoami→alias.

## spt-core upstream deps
Recorded in `../spt-core/M12-CANDIDATES.md` (1: file-backed strings · 2: subnet QR +
self-elevating window · 3: spt-hosted bringup + PTY attach · 4: fallback targets
adapter:profile · 5: whoami obsolescence). spt-claude-code blocks on these.

## experimplate (template) — resolved content
- **Release procedure = generic shape + placeholders** (CHANGELOG · version bump · tag · GH
  Release on same repo); project fills publish specifics. spt-claude-code's publish = cplugs
  marketplace + spt-core adapter-registry; **release is light — signing delegated to spt.exe**
  (not spt-core's two-key/counter runbook).
- **Docs = same-repo `docs-site/` → GH Pages, mdBook, CI-gated against drift.** Reuse
  **spt-core's docs CSS / page-layout / styling as a shared transferable theme** (it's strong;
  carry it across all consumer projects). DOCS-STRATEGY reframed separate-repo→same-repo.
- AGENTS.md = source of truth + thin `CLAUDE.md`=`@AGENTS.md` stub.
- Must teach acquisition of `traceable-reqs` + the grill-with-docs skill (toml/INSTANTIATE).

## Open threads (grill queue)

- [ ] CI trigger mechanism (git-hook signal vs polling routine)
- [ ] Handoff framing to perri (package presentation + public-surface-only constraint)
- [ ] Docs split: what lands in experimplate vs spt-claude-code
- [ ] experimplate authoring: finalize skeleton + write INSTANTIATE.md
- [ ] (downstream) confirm `/spt:setup` #9 verify fold-inline vs deferred


1	# spt-claude-code — glossary
2
3	> Authoritative for meaning (grill-with-docs convention). Glossary only — no
4	> implementation detail. Decisions/rationale live in `SCOPE.md` and `docs/adr/`.
5
6	**spt-claude-code** — the rebuilt Claude Code harness adapter. The `claude-spt`
7	adapter in spt-core terms. Simultaneously spt-core's v1 acceptance proof (legacy
8	parity), its first casual-end-user entrypoint (a CC plugin), and an invisible spt-core
9	installer. Built by maintainer perri from the public spt-releases surface only.
10
11	**claude-spt** — the adapter_name spt-claude-code registers under (rides every `api`
12	invocation + the manifest). The CC adapter's identity inside spt-core.
13
14	**legacy spt / `claude_skill_owl`** — the sister project; today's shipped CC integration
15	(owl.exe + `spt` plugin, v1.11.25). The parity *target* (user-facing features), not a
16	1:1 port — most of its machinery now lives in spt.exe.
17
18	**skeleton plugin** — the thin marketplace artifact on `SaberMage/cplugs`: namespaced
19	`/spt:*` skill stubs + hooks + a SessionStart bootstrap that installs spt-core. Low-churn;
20	the volatile bulk (binary + manifest) is spt-core-conducted, not in the plugin.
21
22	**fetch-stub skill** — a `/spt:X` SKILL.md that is a 2-line stub fetching its real
23	instructions at runtime from the adapter `[strings]` (`spt adapter get-string`/`skill-help`).
24	Keeps skill files static while instructions update via spt-core. Distinct from a `[hints]`
25	entry (proactive, keyword-triggered, UPS-hook-delivered).
26
27	**ccs profile** — a profile under spt-claude-code (`claude-spt:glm`, `claude-spt:kimi`)
28	that leaf-replaces the launch command + history/digest log dir to use the `ccs` backend.
29	NOT its own adapter — ccs is structurally Claude Code.
30
31	**`cc` launcher (capsule-style)** — a generated `cc`/`cc <id>` script at project root that
32	spawns-or-attaches a CC endpoint via spt-core's spt-hosted topology (broker PTY + inject +
33	attach). The spt-core realization of legacy's unbuilt "Capsule" milestone. _Avoid_: equating
34	it with psmux/sendkeys — spt-core's broker is the terminal host.
35
36	**casual end user** — a user who *uses* an spt-powered system mostly-invisibly, vs the
37	adapter/shell *developer* who is spt-core's nominal target. spt-claude-code serves casual
38	users: install the plugin, get spt-core for free.
39
40	**experimplate** — the standalone reusable project-workflow template (its own sibling repo)
41	extracted from spt-core's working style. spt-claude-code is its first consumer. Carries
42	traceable-reqs gating, JIT plans, grill-with-docs scaffolding, release/changelog, and
43	same-repo published-docs. Defined in its own folder, not here.
44

# spt-claude-code — glossary

> Authoritative for meaning (grill-with-docs convention). Glossary only — no
> implementation detail. Decisions/rationale live in `SCOPE.md` and `docs/adr/`.

**spt-claude-code** — the rebuilt Claude Code harness adapter. The `claude-spt`
adapter in spt-core terms. Simultaneously spt-core's v1 acceptance proof (legacy
parity), its first casual-end-user entrypoint (a CC plugin), and an invisible spt-core
installer. Built by maintainer perri from the public spt-releases surface only.

**claude-spt** — the adapter_name spt-claude-code registers under (rides every `api`
invocation + the manifest). The CC adapter's identity inside spt-core.

**legacy spt / `claude_skill_owl`** — the sister project; today's shipped CC integration
(owl.exe + `spt` plugin, v1.11.25). The parity *target* (user-facing features), not a
1:1 port — most of its machinery now lives in spt.exe.

**skeleton plugin** — the thin marketplace artifact on `SaberMage/cplugs`: namespaced
`/spt:*` skill stubs + hooks + a SessionStart bootstrap that installs spt-core. Low-churn;
the volatile bulk (binary + manifest) is spt-core-conducted, not in the plugin.

**fetch-stub skill** — a `/spt:X` SKILL.md that is a 2-line stub fetching its real
instructions at runtime from the adapter `[strings]` (`spt adapter get-string`/`skill-help`).
Keeps skill files static while instructions update via spt-core. Distinct from a `[hints]`
entry (proactive, keyword-triggered, UPS-hook-delivered).

**ccs profile** — a profile under spt-claude-code (`claude-spt:glm`, `claude-spt:kimi`)
that leaf-replaces the launch command + history/digest log dir to use the `ccs` backend.
NOT its own adapter — ccs is structurally Claude Code.

**`cc` launcher (capsule-style)** — a generated `cc`/`cc <id>` script at project root that
spawns-or-attaches a CC endpoint via spt-core's spt-hosted topology (broker PTY + inject +
attach). The spt-core realization of legacy's unbuilt "Capsule" milestone. _Avoid_: equating
it with psmux/sendkeys — spt-core's broker is the terminal host.

**casual end user** — a user who *uses* an spt-powered system mostly-invisibly, vs the
adapter/shell *developer* who is spt-core's nominal target. spt-claude-code serves casual
users: install the plugin, get spt-core for free.

**experimplate** — the standalone reusable project-workflow template (its own sibling repo)
extracted from spt-core's working style. spt-claude-code is its first consumer. Carries
traceable-reqs gating, JIT plans, grill-with-docs scaffolding, release/changelog, and
same-repo published-docs. Defined in its own folder, not here.


1	# Handoff to perri — building `spt-claude-code`
2
3	Welcome, perri. You own `spt-claude-code`: the Claude Code harness adapter for the SPT
4	ecosystem. This document orients you, states your hard constraints, and points you at the
5	detailed spec. Read it fully before writing anything.
6
7	---
8
9	## 1. THE HARD CONSTRAINT — read this first
10
11	**You build `spt-claude-code` using ONLY the published public surface of spt-core:**
12
13	- **`SaberMage/spt-releases`** — the release artifacts (the `spt`/`spt.exe` binary, install
14	  scripts, `mock-adapter` source, `manifest.schema.json`).
15	- **The GitHub Pages docs** at `https://sabermage.github.io/spt-releases` — the mental model,
16	  quickstarts, the complete harness-contract reference, CLI reference, rustdoc, and the agent
17	  exports (`llms.txt` / `llms-full.txt`; append `.md` to any doc URL for raw markdown).
18
19	**You do NOT have, and must NOT use, the `spt-core` source repository.** That is the entire
20	point of this project: it proves the adapter contract is buildable from the public surface
21	alone. If something you need to build the adapter is missing from the public docs/releases,
22	that is a **finding** — report it (it means spt-core's published contract has a gap), do not
23	go reach into spt-core source to work around it.
24
25	**What you MAY read freely:** everything in *this* repo (`spt-claude-code/`). `SCOPE.md`,
26	`CONTEXT.md`, this file, and the future PRD/ROADMAP/ADRs are *your own project's* design — not
27	spt-core source. They describe spt-core features by their *public contract*, not internals.
28
29	---
30
31	## 2. PREREQUISITE GATE — do not start yet
32
33	`spt-claude-code` v1 acceptance = **legacy parity AND proof of spt-core's cross-subnet / PTY
34	features**. Those features (spt-hosted endpoint bringup via `spt endpoint run`, `spt rc`
35	cross-node PTY attach, file-backed adapter strings, `adapter:profile` fallback, subnet QR /
36	self-elevation, `whoami`→alias) are being delivered in **spt-core M12**, in progress now
37	(maintainer: todlando).
38
39	**You begin once full-fat M12 ships AND its docs publish to `spt-releases` GH Pages.** Until
40	then those capabilities aren't in the public surface you build against. Confirm M12 is
41	published before starting. (The operator will signal go.)
42
43	---
44
45	## 3. What `spt-claude-code` is
46
47	The `claude-spt` adapter. Three things at once:
48
49	1. **spt-core's v1 acceptance proof** — feature parity with legacy `claude_skill_owl` (today's
50	   shipped CC integration), delegating all core functionality to the `spt` binary. Parity is
51	   **user-facing feature parity, NOT a 1:1 port** — most legacy machinery now lives inside
52	   `spt` itself; you build the CC-specific shell only.
53	2. **spt-core's first casual-end-user entrypoint** — published as a Claude Code plugin on the
54	   `SaberMage/cplugs` marketplace, like legacy spt is today.
55	3. **An invisible spt-core installer** — for users who don't have spt-core, the plugin
56	   bootstraps it. This is the intended pattern for all casual-facing adapters.
57
58	---
59
60	## 4. How to build it — workflow
61
62	This project is instantiated **from the `experimplate` template** (the reusable workflow
63	scaffold — traceable-reqs gating, JIT plans, grill-with-docs, release + same-repo published
64	docs). The workflow you must follow:
65
66	- **Requirement traceability is binding.** Every requirement is a `REQ-*` in
67	  `traceable-reqs.toml`; tag evidence (`doc`/`impl`/`unit`/`int`) in the same commit; run
68	  `traceable-reqs check` (EXIT=0) before declaring work done; add a REQ before satisfying it;
69	  activate stages incrementally (don't pre-fail). See `docs/TRACEABILITY.md` (from experimplate).
70	- **JIT plans** — plan the next immediate body of work, not the whole project up front.
71	- **grill-with-docs** — keep `CONTEXT.md` (glossary) and `docs/adr/` current as decisions land.
72	- **Docs are same-repo** → GH Pages (mdBook, CI-gated against drift), reusing spt-core's docs
73	  theme. Releases are light (plugin publish + spt-core adapter-registry; **signing delegated to
74	  the `spt` binary** — you do NOT run a two-key signing runbook).
75
76	---
77
78	## 5. Parity target + REQ seed
79
80	The complete legacy inventory (claude_skill_owl v1.11.25: 7 CC hooks, 12 `/spt:*` skills, the
81	messaging/live-agent/working-perch surfaces, marketplace packaging, CC-specifics like JSONL
82	transcript parsing and parent-pid binding) is the parity reference. **It has been triaged**
83	into DROP / TRANSFORM / KEEP / ADD buckets in `SCOPE.md` → "Parity-trim". Seed your
84	`traceable-reqs.toml` from those buckets:
85
86	- **KEEP** (port the user-facing skill): `/live` `/commune` `/ready` `/send` `/signoff`
87	  `/force-stop` `/new-alarm` `/list-agents`.
88	- **DROP** (do not port): `/revive`, `/clear-psyche`, `/whoami` (skill), `/fork`,
89	  `amend-signoff`, Spine/Touch, legacy psmux Capsule, binary-handoff, the TCP/spool/registry
90	  internals (all now inside `spt`).
91	- **TRANSFORM**: Capsule → spt-hosted topology + the `cc` launcher; echo-commune JSONL → the
92	  `[digest]` extractor; psyche-sync → subnet/`/spt:setup`; doctor → `spt doctor`/setup-verify;
93	  working-perches → `api worker-*`.
94	- **ADD**: `/spt:setup`, `/spt:version`, subnet skills (create/join/show-code), profiles +
95	  strings + hints wiring, ccs profiles.
96
97	---
98
99	## 6. Locked architecture (full detail in `SCOPE.md`)
100
101	- **Distribution**: a thin marketplace **skeleton plugin** (namespaced `/spt:*` skill
102	  skeletons + `hooks.json` calling `spt api` + a SessionStart bootstrap that installs spt-core)
103	  on cplugs. The volatile bulk (the `spt` binary + the CC adapter manifest) is **spt-core-
104	  conducted**, not plugin files — so the plugin rarely needs a marketplace bump and never
105	  orphans. Updates: file-pull (real channel) + a cautionary `claude plugin update`.
106	- **Skill instructions**: a `UserPromptSubmit` hook detects `/spt:X` and injects X's real
107	  instructions as `additionalContext`, sourced from the adapter `[strings]` (file-backed, so
108	  the manifest doesn't bloat). SKILL.md files stay skeletons. (Verify empirically at build
109	  time that UPS fires on slash-commands — design assumes it does.)
110	- **ccs** = profile(s) under `claude-spt` (`claude-spt:glm`, …), NOT its own adapter — leaf-
111	  replaces the launch command + per-profile `~/.ccs` log dir. Ship profile *templates*; user
112	  supplies their own ccs config/keys.
113	- **`/spt:setup`** (needed because users install mid-session, no SessionStart fire): v1 paths
114	  = generate `cc`/`cc <id>` launcher · `.gitignore` it · create-subnet (QR) · if-installed
115	  branch (new/join/show-code) · legacy migration · OS-service register · ccs wiring. The `cc`
116	  launcher wraps `spt endpoint run` defaulted to claude-spt.
117	- **CI** = autonomous fleet (Windows + Linux), **no LLM in the gate loop**: deterministic
118	  gates (build, unit, `traceable-reqs check`, manifest-schema); acceptance = scripted
119	  orchestration spawning real `claude` sessions as the system-under-test; **spt messaging is
120	  the reporting bus** (dogfood). GH runners are not used. Trigger = git post-push hook →
121	  `$OWL send` a fleet runner-agent.
122
123	---
124
125	## 7. Acceptance bar (v1)
126
127	Legacy user-facing feature parity **AND** demonstrated cross-subnet + PTY-hosting proof:
128	- The KEEP skills work end-to-end under Claude Code (harness-hosted).
129	- spt-hosted mode works: `cc`/`spt endpoint run` brings up a CC endpoint in a broker PTY and
130	  the user attaches (local); `spt rc` attaches cross-node.
131	- The `[digest]` extractor surfaces a CC session correctly (carried criterion: **real-CC
132	  digest-proof** against a real `~/.claude` session JSONL).
133	- Plugin installs from cplugs, bootstraps spt-core on a clean machine, legacy users migrate.
134
135	---
136
137	## 8. Your calls / open items (from `SCOPE.md`)
138
139	- `/spt:setup` #9 (doctor/verify) — fold inline or defer? (operator left ambiguous)
140	- The `cc` launcher's exact flag set (must cover every terminal action of `spt endpoint run`).
141	- Whether to keep UPS-injection or fall back to in-SKILL.md instructions if UPS doesn't fire
142	  on slash-commands (empirical, build-time).
143
144	---
145
146	## 9. Pointers
147
148	- `SCOPE.md` — the full decision ledger (authoritative for what/why). **Start here after this.**
149	- `CONTEXT.md` — glossary (authoritative for meaning).
150	- Public spt-core surface — `SaberMage/spt-releases` + `https://sabermage.github.io/spt-releases`
151	  (incl. `llms.txt` / `llms-full.txt` for agent ingestion).
152	- experimplate — the template you instantiate from (workflow scaffolding + INSTANTIATE.md).
153	- spt-core M12 (your dependency, by its *published contract* only): `spt endpoint run`, `spt rc`,
154	  file-backed strings, `adapter:profile` fallback, subnet QR/elevation, `whoami`→alias.
155
156	Build from the public surface. If the public surface can't build it, that's the bug — report it.
157	— doyle (scoping, 2026-06-14)
158

# Handoff to perri — building `spt-claude-code`

Welcome, perri. You own `spt-claude-code`: the Claude Code harness adapter for the SPT
ecosystem. This document orients you, states your hard constraints, and points you at the
detailed spec. Read it fully before writing anything.

---

## 1. THE HARD CONSTRAINT — read this first

**You build `spt-claude-code` using ONLY the published public surface of spt-core:**

- **`SaberMage/spt-releases`** — the release artifacts (the `spt`/`spt.exe` binary, install
  scripts, `mock-adapter` source, `manifest.schema.json`).
- **The GitHub Pages docs** at `https://sabermage.github.io/spt-releases` — the mental model,
  quickstarts, the complete harness-contract reference, CLI reference, rustdoc, and the agent
  exports (`llms.txt` / `llms-full.txt`; append `.md` to any doc URL for raw markdown).

**You do NOT have, and must NOT use, the `spt-core` source repository.** That is the entire
point of this project: it proves the adapter contract is buildable from the public surface
alone. If something you need to build the adapter is missing from the public docs/releases,
that is a **finding** — report it (it means spt-core's published contract has a gap), do not
go reach into spt-core source to work around it.

**What you MAY read freely:** everything in *this* repo (`spt-claude-code/`). `SCOPE.md`,
`CONTEXT.md`, this file, and the future PRD/ROADMAP/ADRs are *your own project's* design — not
spt-core source. They describe spt-core features by their *public contract*, not internals.

---

## 2. PREREQUISITE GATE — do not start yet

`spt-claude-code` v1 acceptance = **legacy parity AND proof of spt-core's cross-subnet / PTY
features**. Those features (spt-hosted endpoint bringup via `spt endpoint run`, `spt rc`
cross-node PTY attach, file-backed adapter strings, `adapter:profile` fallback, subnet QR /
self-elevation, `whoami`→alias) are being delivered in **spt-core M12**, in progress now
(maintainer: todlando).

**You begin once full-fat M12 ships AND its docs publish to `spt-releases` GH Pages.** Until
then those capabilities aren't in the public surface you build against. Confirm M12 is
published before starting. (The operator will signal go.)

---

## 3. What `spt-claude-code` is

The `claude-spt` adapter. Three things at once:

1. **spt-core's v1 acceptance proof** — feature parity with legacy `claude_skill_owl` (today's
   shipped CC integration), delegating all core functionality to the `spt` binary. Parity is
   **user-facing feature parity, NOT a 1:1 port** — most legacy machinery now lives inside
   `spt` itself; you build the CC-specific shell only.
2. **spt-core's first casual-end-user entrypoint** — published as a Claude Code plugin on the
   `SaberMage/cplugs` marketplace, like legacy spt is today.
3. **An invisible spt-core installer** — for users who don't have spt-core, the plugin
   bootstraps it. This is the intended pattern for all casual-facing adapters.

---

## 4. How to build it — workflow

This project is instantiated **from the `experimplate` template** (the reusable workflow
scaffold — traceable-reqs gating, JIT plans, grill-with-docs, release + same-repo published
docs). The workflow you must follow:

- **Requirement traceability is binding.** Every requirement is a `REQ-*` in
  `traceable-reqs.toml`; tag evidence (`doc`/`impl`/`unit`/`int`) in the same commit; run
  `traceable-reqs check` (EXIT=0) before declaring work done; add a REQ before satisfying it;
  activate stages incrementally (don't pre-fail). See `docs/TRACEABILITY.md` (from experimplate).
- **JIT plans** — plan the next immediate body of work, not the whole project up front.
- **grill-with-docs** — keep `CONTEXT.md` (glossary) and `docs/adr/` current as decisions land.
- **Docs are same-repo** → GH Pages (mdBook, CI-gated against drift), reusing spt-core's docs
  theme. Releases are light (plugin publish + spt-core adapter-registry; **signing delegated to
  the `spt` binary** — you do NOT run a two-key signing runbook).

---

## 5. Parity target + REQ seed

The complete legacy inventory (claude_skill_owl v1.11.25: 7 CC hooks, 12 `/spt:*` skills, the
messaging/live-agent/working-perch surfaces, marketplace packaging, CC-specifics like JSONL
transcript parsing and parent-pid binding) is the parity reference. **It has been triaged**
into DROP / TRANSFORM / KEEP / ADD buckets in `SCOPE.md` → "Parity-trim". Seed your
`traceable-reqs.toml` from those buckets:

- **KEEP** (port the user-facing skill): `/live` `/commune` `/ready` `/send` `/signoff`
  `/force-stop` `/new-alarm` `/list-agents`.
- **DROP** (do not port): `/revive`, `/clear-psyche`, `/whoami` (skill), `/fork`,
  `amend-signoff`, Spine/Touch, legacy psmux Capsule, binary-handoff, the TCP/spool/registry
  internals (all now inside `spt`).
- **TRANSFORM**: Capsule → spt-hosted topology + the `cc` launcher; echo-commune JSONL → the
  `[digest]` extractor; psyche-sync → subnet/`/spt:setup`; doctor → `spt doctor`/setup-verify;
  working-perches → `api worker-*`.
- **ADD**: `/spt:setup`, `/spt:version`, subnet skills (create/join/show-code), profiles +
  strings + hints wiring, ccs profiles.

---

## 6. Locked architecture (full detail in `SCOPE.md`)

- **Distribution**: a thin marketplace **skeleton plugin** (namespaced `/spt:*` skill
  skeletons + `hooks.json` calling `spt api` + a SessionStart bootstrap that installs spt-core)
  on cplugs. The volatile bulk (the `spt` binary + the CC adapter manifest) is **spt-core-
  conducted**, not plugin files — so the plugin rarely needs a marketplace bump and never
  orphans. Updates: file-pull (real channel) + a cautionary `claude plugin update`.
- **Skill instructions**: a `UserPromptSubmit` hook detects `/spt:X` and injects X's real
  instructions as `additionalContext`, sourced from the adapter `[strings]` (file-backed, so
  the manifest doesn't bloat). SKILL.md files stay skeletons. (Verify empirically at build
  time that UPS fires on slash-commands — design assumes it does.)
- **ccs** = profile(s) under `claude-spt` (`claude-spt:glm`, …), NOT its own adapter — leaf-
  replaces the launch command + per-profile `~/.ccs` log dir. Ship profile *templates*; user
  supplies their own ccs config/keys.
- **`/spt:setup`** (needed because users install mid-session, no SessionStart fire): v1 paths
  = generate `cc`/`cc <id>` launcher · `.gitignore` it · create-subnet (QR) · if-installed
  branch (new/join/show-code) · legacy migration · OS-service register · ccs wiring. The `cc`
  launcher wraps `spt endpoint run` defaulted to claude-spt.
- **CI** = autonomous fleet (Windows + Linux), **no LLM in the gate loop**: deterministic
  gates (build, unit, `traceable-reqs check`, manifest-schema); acceptance = scripted
  orchestration spawning real `claude` sessions as the system-under-test; **spt messaging is
  the reporting bus** (dogfood). GH runners are not used. Trigger = git post-push hook →
  `$OWL send` a fleet runner-agent.

---

## 7. Acceptance bar (v1)

Legacy user-facing feature parity **AND** demonstrated cross-subnet + PTY-hosting proof:
- The KEEP skills work end-to-end under Claude Code (harness-hosted).
- spt-hosted mode works: `cc`/`spt endpoint run` brings up a CC endpoint in a broker PTY and
  the user attaches (local); `spt rc` attaches cross-node.
- The `[digest]` extractor surfaces a CC session correctly (carried criterion: **real-CC
  digest-proof** against a real `~/.claude` session JSONL).
- Plugin installs from cplugs, bootstraps spt-core on a clean machine, legacy users migrate.

---

## 8. Your calls / open items (from `SCOPE.md`)

- `/spt:setup` #9 (doctor/verify) — fold inline or defer? (operator left ambiguous)
- The `cc` launcher's exact flag set (must cover every terminal action of `spt endpoint run`).
- Whether to keep UPS-injection or fall back to in-SKILL.md instructions if UPS doesn't fire
  on slash-commands (empirical, build-time).

---

## 9. Pointers

- `SCOPE.md` — the full decision ledger (authoritative for what/why). **Start here after this.**
- `CONTEXT.md` — glossary (authoritative for meaning).
- Public spt-core surface — `SaberMage/spt-releases` + `https://sabermage.github.io/spt-releases`
  (incl. `llms.txt` / `llms-full.txt` for agent ingestion).
- experimplate — the template you instantiate from (workflow scaffolding + INSTANTIATE.md).
- spt-core M12 (your dependency, by its *published contract* only): `spt endpoint run`, `spt rc`,
  file-backed strings, `adapter:profile` fallback, subnet QR/elevation, `whoami`→alias.

Build from the public surface. If the public surface can't build it, that's the bug — report it.
— doyle (scoping, 2026-06-14)


1	# spt-claude-code — agent working rules
2
3	> **Canonical source of truth for how agents work in this repo.** Harness-agnostic:
4	> Claude Code reads it via the one-line `CLAUDE.md` (`@AGENTS.md`); other harnesses read
5	> this file directly. Edit working rules HERE, never in `CLAUDE.md`.
6
7	## Public-surface-only constraint (read first)
8
9	You build `spt-claude-code` against **only the published public surface of spt-core**:
10	`SaberMage/spt-releases` (the `spt`/`spt.exe` binary, install scripts, `mock-adapter`
11	source, `manifest.schema.json`) and the GitHub Pages docs at
12	`https://sabermage.github.io/spt-releases` (mental model, quickstarts, harness-contract +
13	CLI reference, rustdoc, `llms.txt` / `llms-full.txt`). **Never read the `spt-core` source
14	tree.** Proving the adapter contract is buildable from the public surface alone is the entire
15	point of this project. If a capability you need is missing from the public docs/releases,
16	that is a **finding to report** (spt-core's published contract has a gap) — not a reason to
17	reach into spt-core source to work around it. (See `HANDOFF.md` §1.)
18
19	`spt-claude-code` is the rebuilt Claude Code harness adapter (`claude-spt`) — spt-core's v1
20	acceptance proof, its first casual-end-user entrypoint (a CC plugin), and an invisible
21	spt-core installer.
22
23	**Orientation — read before working:** `SCOPE.md` (decision ledger, authoritative for
24	what/why), `HANDOFF.md` (build orientation + the hard public-surface-only constraint),
25	`CONTEXT.md` (glossary/model, authoritative for meaning), `docs/adr/` (decisions),
26	`docs/KNOWN-HAZARDS.md` (invariants we must not re-break), `docs/{DOCS-STRATEGY,TRACEABILITY}.md`.
27
28	## Requirement traceability (binding)
29
30	This project uses [`traceable-reqs`](https://github.com/BigscreenVR/traceable-reqs)
31	(`traceable-reqs.toml` = the authoritative `REQ-*` registry). The full contract is
32	`docs/TRACEABILITY.md`. The rules you must follow:
33
34	1. **Tag evidence in the same change.** When you write a function/test/doc-section that
35	   satisfies a requirement stage, add its tag in that same commit:
36	   `// [impl->REQ-FOO]` · `// [unit->REQ-FOO]` · `<!-- [doc->REQ-FOO] -->`
37	   Stages: `doc` / `impl` / `unit` / `int`. Tag *on or immediately above* the real
38	   evidence — never at file tops to satisfy coverage.
39	2. **Run `traceable-reqs check` before declaring work done.** Exit-1 means missing/invalid
40	   evidence — fix it, don't ship it.
41	3. **New requirement → add it to `traceable-reqs.toml` first** (with a `REQ-*` id), then
42	   satisfy it. No untracked work; no untagged evidence.
43	4. **KNOWN-HAZARDS are `REQ-HAZARD-*` requirements** — each needs a test before it's
44	   "covered." Treat the hazard list as a conformance checklist you must satisfy, not advice.
45	5. **Activate, don't pre-fail.** Requirements you aren't yet working stay
46	   `required_stages = []`. Activate (set real stages) only when starting the milestone that
47	   delivers them.
48
49	## Other conventions
50
51	- Match surrounding code style. spt-claude-code consumes spt-core's **published** manifest
52	  contract (`manifest.schema.json` from `spt-releases`) — validate your manifest against it.
53	  Do **not** copy spt-core internals: build against the public surface only.
54	- Honor every `docs/KNOWN-HAZARDS.md` invariant — these are real bugs already paid for once
55	  (or hazards you have committed to never introduce). Each is a `REQ-HAZARD-*` with a test.
56	- Docs are dual-audience (human + AI dev-agent) per `docs/DOCS-STRATEGY.md`; doc generation
57	  is CI-gated against drift.
58	- Commit messages end with the project's co-author trailer:
59	  `Co-authored by: <your live agent name>` (e.g. `Co-authored by: perri`).
60
61	## Plans and context hygiene
62
63	- **JIT plans.** Plan the next immediate body of work just-in-time (a short `*-PLAN.md`),
64	  not the whole project up front. A plan names scope, open design questions, tasks, and the
65	  gate (build + `traceable-reqs check` green).
66	- If you finish a significant body of work without need for user intervention, or if your
67	  context gets too high, you can clear your own context and keep moving:
68	  1. Create a JIT plan for the next immediate body of work, if it isn't already planned.
69	  2. If you are a live agent: commune immediate next steps + a broad project-status/end-goal
70	     summary, then clear.
71

# spt-claude-code — agent working rules

> **Canonical source of truth for how agents work in this repo.** Harness-agnostic:
> Claude Code reads it via the one-line `CLAUDE.md` (`@AGENTS.md`); other harnesses read
> this file directly. Edit working rules HERE, never in `CLAUDE.md`.

## Public-surface-only constraint (read first)

You build `spt-claude-code` against **only the published public surface of spt-core**:
`SaberMage/spt-releases` (the `spt`/`spt.exe` binary, install scripts, `mock-adapter`
source, `manifest.schema.json`) and the GitHub Pages docs at
`https://sabermage.github.io/spt-releases` (mental model, quickstarts, harness-contract +
CLI reference, rustdoc, `llms.txt` / `llms-full.txt`). **Never read the `spt-core` source
tree.** Proving the adapter contract is buildable from the public surface alone is the entire
point of this project. If a capability you need is missing from the public docs/releases,
that is a **finding to report** (spt-core's published contract has a gap) — not a reason to
reach into spt-core source to work around it. (See `HANDOFF.md` §1.)

`spt-claude-code` is the rebuilt Claude Code harness adapter (`claude-spt`) — spt-core's v1
acceptance proof, its first casual-end-user entrypoint (a CC plugin), and an invisible
spt-core installer.

**Orientation — read before working:** `SCOPE.md` (decision ledger, authoritative for
what/why), `HANDOFF.md` (build orientation + the hard public-surface-only constraint),
`CONTEXT.md` (glossary/model, authoritative for meaning), `docs/adr/` (decisions),
`docs/KNOWN-HAZARDS.md` (invariants we must not re-break), `docs/{DOCS-STRATEGY,TRACEABILITY}.md`.

## Requirement traceability (binding)

This project uses [`traceable-reqs`](https://github.com/BigscreenVR/traceable-reqs)
(`traceable-reqs.toml` = the authoritative `REQ-*` registry). The full contract is
`docs/TRACEABILITY.md`. The rules you must follow:

1. **Tag evidence in the same change.** When you write a function/test/doc-section that
   satisfies a requirement stage, add its tag in that same commit:
   `// [impl->REQ-FOO]` · `// [unit->REQ-FOO]` · `<!-- [doc->REQ-FOO] -->`
   Stages: `doc` / `impl` / `unit` / `int`. Tag *on or immediately above* the real
   evidence — never at file tops to satisfy coverage.
2. **Run `traceable-reqs check` before declaring work done.** Exit-1 means missing/invalid
   evidence — fix it, don't ship it.
3. **New requirement → add it to `traceable-reqs.toml` first** (with a `REQ-*` id), then
   satisfy it. No untracked work; no untagged evidence.
4. **KNOWN-HAZARDS are `REQ-HAZARD-*` requirements** — each needs a test before it's
   "covered." Treat the hazard list as a conformance checklist you must satisfy, not advice.
5. **Activate, don't pre-fail.** Requirements you aren't yet working stay
   `required_stages = []`. Activate (set real stages) only when starting the milestone that
   delivers them.

## Other conventions

- Match surrounding code style. spt-claude-code consumes spt-core's **published** manifest
  contract (`manifest.schema.json` from `spt-releases`) — validate your manifest against it.
  Do **not** copy spt-core internals: build against the public surface only.
- Honor every `docs/KNOWN-HAZARDS.md` invariant — these are real bugs already paid for once
  (or hazards you have committed to never introduce). Each is a `REQ-HAZARD-*` with a test.
- Docs are dual-audience (human + AI dev-agent) per `docs/DOCS-STRATEGY.md`; doc generation
  is CI-gated against drift.
- Commit messages end with the project's co-author trailer:
  `Co-authored by: <your live agent name>` (e.g. `Co-authored by: perri`).

## Plans and context hygiene

- **JIT plans.** Plan the next immediate body of work just-in-time (a short `*-PLAN.md`),
  not the whole project up front. A plan names scope, open design questions, tasks, and the
  gate (build + `traceable-reqs check` green).
- If you finish a significant body of work without need for user intervention, or if your
  context gets too high, you can clear your own context and keep moving:
  1. Create a JIT plan for the next immediate body of work, if it isn't already planned.
  2. If you are a live agent: commune immediate next steps + a broad project-status/end-goal
     summary, then clear.


1	@AGENTS.md
2
3	<!--
4	Claude Code reads CLAUDE.md only; the `@AGENTS.md` import above bridges the canonical rules.
5	Keep working rules in AGENTS.md (harness-agnostic). Put ONLY Claude-Code-specific extras
6	below this line (e.g. CC slash-command notes, hook reminders) — and prefer none.
7	-->
8

@AGENTS.md

<!--
Claude Code reads CLAUDE.md only; the `@AGENTS.md` import above bridges the canonical rules.
Keep working rules in AGENTS.md (harness-agnostic). Put ONLY Claude-Code-specific extras
below this line (e.g. CC slash-command notes, hook reminders) — and prefer none.
-->


1	# traceable-reqs manifest for spt-claude-code — SEED.
2	#
3	# Authoritative requirement registry: every requirement and every KNOWN-HAZARDS
4	# invariant lives here as a REQ-* id (see docs/TRACEABILITY.md for the full contract).
5	#
6	# SEED YOUR REQs FROM SCOPE.md "Parity-trim" — the DROP / TRANSFORM / KEEP / ADD buckets are
7	# the parity reference. Mint a REQ-* per surface you port/transform/add as you START each
8	# milestone (NOT up front). The registry below is intentionally EMPTY (commented shapes only).
9	#
10	# ACQUIRE the CLI (it is a released binary, not a crate dependency):
11	#   gh release download --repo BigscreenVR/traceable-reqs \
12	#     --pattern '*<your-platform>' --output traceable-reqs   # then chmod +x
13	# (see INSTANTIATE.md for per-platform patterns + CI wiring.) Validate this seed against
14	# the installed CLI before relying on it: `traceable-reqs check`.
15	#
16	# THE FOUR-STAGE CONTRACT: every requirement is traced from
17	#   doc  (prose/design)  ->  impl (production code)  ->  unit (unit test)  ->  int (cross-process/node)
18	# Tag evidence in the SAME commit, on/above the real evidence:
19	#   // [impl->REQ-FOO]   // [unit->REQ-FOO]   <!-- [doc->REQ-FOO] -->
20	#
21	# ACTIVATION MODEL: every requirement starts inactive (`required_stages = []`) so `check`
22	# stays green pre-code. A milestone ACTIVATES its requirements by setting their real
23	# `required_stages` when work on them begins. Deferred items stay [] until promoted.
24	# Never declare the full end-state stage list up front — activate incrementally as evidence
25	# lands (add "int" at the final integrating wave).
26
27	[scan]
28	# Every evidence location. A missing root makes evidence SILENTLY vanish from the trace —
29	# audit this whenever a new evidence dir appears. Fill with this project's real layout.
30	roots = ["skills", "hooks", "plugin", "tests", "docs", "CONTEXT.md", "SCOPE.md"]
31
32	[policy]
33	# Default policy applied at activation: doc + impl + unit. Networking/lifecycle/cross-node
34	# reqs add "int". Until a req is activated, its per-req `required_stages = []` keeps it out
35	# of the coverage gate.
36	required_stages = []
37
38	# ───────────────────────────── Requirements ─────────────────────────────────
39	# Add requirements as you scope milestones, seeded from SCOPE.md "Parity-trim". Shape:
40	#
41	# [[requirements]]
42	# id = "REQ-EXAMPLE-1"
43	# title = "One-line statement of the requirement"
44	# required_stages = []  # activate (e.g. ["doc","impl","unit"]) when the milestone starts
45	#
46	# KNOWN-HAZARDS invariants are first-class requirements — one REQ-HAZARD-* per invariant,
47	# each requiring at least "unit" (add "int" where cross-process/cross-node):
48	#
49	# [[requirements]]
50	# id = "REQ-HAZARD-EXAMPLE"
51	# title = "The invariant, stated so a test can prove it"
52	# required_stages = []
53

# traceable-reqs manifest for spt-claude-code — SEED.
#
# Authoritative requirement registry: every requirement and every KNOWN-HAZARDS
# invariant lives here as a REQ-* id (see docs/TRACEABILITY.md for the full contract).
#
# SEED YOUR REQs FROM SCOPE.md "Parity-trim" — the DROP / TRANSFORM / KEEP / ADD buckets are
# the parity reference. Mint a REQ-* per surface you port/transform/add as you START each
# milestone (NOT up front). The registry below is intentionally EMPTY (commented shapes only).
#
# ACQUIRE the CLI (it is a released binary, not a crate dependency):
#   gh release download --repo BigscreenVR/traceable-reqs \
#     --pattern '*<your-platform>' --output traceable-reqs   # then chmod +x
# (see INSTANTIATE.md for per-platform patterns + CI wiring.) Validate this seed against
# the installed CLI before relying on it: `traceable-reqs check`.
#
# THE FOUR-STAGE CONTRACT: every requirement is traced from
#   doc  (prose/design)  ->  impl (production code)  ->  unit (unit test)  ->  int (cross-process/node)
# Tag evidence in the SAME commit, on/above the real evidence:
#   // [impl->REQ-FOO]   // [unit->REQ-FOO]   <!-- [doc->REQ-FOO] -->
#
# ACTIVATION MODEL: every requirement starts inactive (`required_stages = []`) so `check`
# stays green pre-code. A milestone ACTIVATES its requirements by setting their real
# `required_stages` when work on them begins. Deferred items stay [] until promoted.
# Never declare the full end-state stage list up front — activate incrementally as evidence
# lands (add "int" at the final integrating wave).

[scan]
# Every evidence location. A missing root makes evidence SILENTLY vanish from the trace —
# audit this whenever a new evidence dir appears. Fill with this project's real layout.
roots = ["skills", "hooks", "plugin", "tests", "docs", "CONTEXT.md", "SCOPE.md"]

[policy]
# Default policy applied at activation: doc + impl + unit. Networking/lifecycle/cross-node
# reqs add "int". Until a req is activated, its per-req `required_stages = []` keeps it out
# of the coverage gate.
required_stages = []

# ───────────────────────────── Requirements ─────────────────────────────────
# Add requirements as you scope milestones, seeded from SCOPE.md "Parity-trim". Shape:
#
# [[requirements]]
# id = "REQ-EXAMPLE-1"
# title = "One-line statement of the requirement"
# required_stages = []  # activate (e.g. ["doc","impl","unit"]) when the milestone starts
#
# KNOWN-HAZARDS invariants are first-class requirements — one REQ-HAZARD-* per invariant,
# each requiring at least "unit" (add "int" where cross-process/cross-node):
#
# [[requirements]]
# id = "REQ-HAZARD-EXAMPLE"
# title = "The invariant, stated so a test can prove it"
# required_stages = []


Oriented. Check scaffolding state before planning first work.


Bash

cd "C:/Users/decid/Documents/projects/spt-claude-code" && echo "=== docs/ ===" && ls -R docs 2>&1 | head -40 && echo "=== docs-site/ ===" && ls -R docs-site 2>&1 | head -40 && echo "=== .gitignore ===" && cat .gitignore && echo "=== traceable-reqs CLI present? ===" && (command -v traceable-reqs || ls -la traceable-reqs* 2>&1 || echo "NOT FOUND")

Inspect docs scaffolding and CLI presence


=== docs/ ===
docs:
CI.md
DOCS-STRATEGY.md
KNOWN-HAZARDS.md
RELEASE-RUNBOOK.md
TRACEABILITY.md
adr
formats

docs/adr:
0000-template.md

docs/formats:
adr-format.md
context-format.md
=== docs-site/ ===
docs-site:
README.md
theme

docs-site/theme:
theme.css
=== .gitignore ===
# spt runtime perch state (not source)
.claude/LIVE_AGENT_IDS.json
.claude/*-commune.md
.claude/*-signoff.md

# generated launchers (capsule-style cc / cc-<id>)
/cc
/cc.bat
/cc.sh
/cc-*
=== traceable-reqs CLI present? ===
/c/Users/decid/AppData/Local/Programs/traceable-reqs/traceable-reqs


cd "C:/Users/decid/Documents/projects/spt-claude-code" && traceable-reqs --version 2>&1; echo "--- check ---"; traceable-reqs check 2>&1 | head -30

Validate traceable-reqs CLI and run check on seed


traceable-reqs 0.1.2
--- check ---
manifest_error: scan root 'skills' is unreadable or does not exist


1	# Traceability development contract
2
3	> How spt-claude-code uses [`traceable-reqs`](https://github.com/BigscreenVR/traceable-reqs)
4	> to keep every requirement traced from doc → impl → test. The manifest is
5	> `traceable-reqs.toml` (seed it from your requirements source + your KNOWN-HAZARDS
6	> invariants). This contract makes the trace pay off instead of rotting.
7
8	## Why
9
10	A requirement that isn't traced to real evidence (a doc, an implementation, a test) is a
11	requirement you're only *hoping* is met. This contract converts that hope into a build that
12	**fails when evidence is missing** — so scope ships verifiably and known hazards can't
13	silently regress.
14
15	## The contract (rules)
16
17	1. **The manifest is the authoritative requirement registry.** Every requirement and every
18	   KNOWN-HAZARDS invariant exists in `traceable-reqs.toml` as a `REQ-*` id. No work without a
19	   REQ; no REQ without intent to satisfy. Your prose source (PRD / spec / design doc) holds the
20	   wording; the manifest holds the id + `required_stages`.
21	2. **Tag in the same change as the evidence.** When you write the function / test / doc-section
22	   that satisfies a stage, add its `[<stage>-><REQ-ID>]` tag in *that same commit*. Never "tag
23	   later" — this single rule is what stops the trace from drifting.
24	3. **Evidence-proximate tags, not file-tops.** A tag sits on or immediately above the real
25	   function, test, doc section, config entry, or workflow step that proves the stage. One tag =
26	   one piece of real evidence. Tags at file tops to satisfy coverage are noise and usually wrong.
27	4. **KNOWN-HAZARDS are first-class requirements.** Each invariant is a `REQ-HAZARD-*` requiring
28	   `unit` (and `int` where cross-process / cross-node). A hazard cannot be "covered" without a
29	   test tagging it — the anti-regression promise becomes mechanical.
30	5. **Activation, not premature failure.** Every requirement starts `required_stages = []`
31	   (inactive) so `check` stays green pre-code. A **milestone activates** the requirements it
32	   delivers by setting their real `required_stages`. Deferred items stay `[]` until promoted.
33	6. **Scan roots stay honest.** `[scan].roots` includes every evidence location (your source,
34	   tests, docs, and later your CI workflows and scripts). Audit roots whenever a new evidence
35	   dir appears — a missing root makes evidence *silently* vanish from the trace.
36
37	### Stages
38
39	`doc` (prose / design / API-doc) · `impl` (production code) · `unit` (unit test) · `int`
40	(integration / e2e / cross-process / cross-node). Default activation policy:
41	`["doc","impl","unit"]`; networking / lifecycle / cross-node reqs add `int`.
42
43	### Tag examples
44
45	Real tags are `[<stage>->REQ-ID]` with a bare stage word. The examples below angle-bracket the
46	stage (`[<impl>->...]`) only so the scanner treats them as illustrations, not live evidence —
47	write a bare stage word in real code.
48
49	```rust
50	// [<impl>->REQ-EXAMPLE-1]
51	fn do_the_thing(...) { ... }
52	```
53	```rust
54	// [<unit>->REQ-HAZARD-EXAMPLE]
55	#[test] fn upholds_the_invariant() { ... }
56	```
57	```markdown
58	<!-- [<doc>->REQ-EXAMPLE-1] -->
59	## The thing, explained
60	```
61
62	## Enforcement (four layers — defense in depth)
63
64	1. **CI gate (hard backstop).** `traceable-reqs check --json` runs on every PR / push; exit-1
65	   (`missing_stage` / `undeclared_id` / `parse_error` / `manifest_error`) **fails the build**. A
66	   PR can't merge if it leaves an *activated* req's required stage uncovered. Runs alongside the
67	   DOCS-STRATEGY docs-drift gate.
68	2. **Milestone activation gate.** Starting a milestone flips its reqs from `[]` to the real
69	   policy; the milestone **is not done until `check` is green for its reqs**. Coverage grows
70	   *with* the project instead of failing on day one.
71	3. **Agent-facing rule.** The repo `AGENTS.md` instructs every dev-agent: tag
72	   `[<stage>-><REQ-ID>]` in the same change as the evidence, and run `traceable-reqs check`
73	   before declaring done. If this project is built *with* agents, the contract must be
74	   machine-followable — agent discipline + CI as the net.
75	4. **Quality audit (anti-box-ticking).** `check` proves a tag *exists*; `traceable-reqs review`
76	   + `lint` audit whether tags sit near *real* evidence and whether titles are meaningful. Run
77	   advisory in CI (or periodically). Presence = hard gate; quality = audited.
78
79	Optional fast-feedback: a pre-push git hook running `traceable-reqs check` locally.
80
81	## CI snippet (hosted-runner fallback; see `docs/CI.md` for the agent-driven default)
82
83	```yaml
84	# .github/workflows/traceability.yml
85	name: traceability
86	on: [push, pull_request]
87	jobs:
88	  check:
89	    runs-on: ubuntu-latest
90	    steps:
91	      - uses: actions/checkout@v4
92	      - name: Install traceable-reqs
93	        run: gh release download --repo BigscreenVR/traceable-reqs --pattern '*linux-x86_64' --output traceable-reqs && chmod +x traceable-reqs
94	        env: { GH_TOKEN: ${{ github.token }} }
95	      - name: Coverage gate (hard)
96	        run: ./traceable-reqs check --json
97	      - name: Quality audit (advisory)
98	        run: ./traceable-reqs lint || true
99	```
100
101	## Lifecycle
102
103	- **Now (planning):** manifest seeded, all reqs inactive. `check` is green (nothing required
104	  yet).
105	- **First milestone:** install the CLI, validate the seed against it, wire the CI gate,
106	  **activate that milestone's reqs** (and the `REQ-HAZARD-*` invariants it must uphold), tag as
107	  code lands.
108	- **Each later milestone:** activates + covers its requirements before it's called done.
109

# Traceability development contract

> How spt-claude-code uses [`traceable-reqs`](https://github.com/BigscreenVR/traceable-reqs)
> to keep every requirement traced from doc → impl → test. The manifest is
> `traceable-reqs.toml` (seed it from your requirements source + your KNOWN-HAZARDS
> invariants). This contract makes the trace pay off instead of rotting.

## Why

A requirement that isn't traced to real evidence (a doc, an implementation, a test) is a
requirement you're only *hoping* is met. This contract converts that hope into a build that
**fails when evidence is missing** — so scope ships verifiably and known hazards can't
silently regress.

## The contract (rules)

1. **The manifest is the authoritative requirement registry.** Every requirement and every
   KNOWN-HAZARDS invariant exists in `traceable-reqs.toml` as a `REQ-*` id. No work without a
   REQ; no REQ without intent to satisfy. Your prose source (PRD / spec / design doc) holds the
   wording; the manifest holds the id + `required_stages`.
2. **Tag in the same change as the evidence.** When you write the function / test / doc-section
   that satisfies a stage, add its `[<stage>-><REQ-ID>]` tag in *that same commit*. Never "tag
   later" — this single rule is what stops the trace from drifting.
3. **Evidence-proximate tags, not file-tops.** A tag sits on or immediately above the real
   function, test, doc section, config entry, or workflow step that proves the stage. One tag =
   one piece of real evidence. Tags at file tops to satisfy coverage are noise and usually wrong.
4. **KNOWN-HAZARDS are first-class requirements.** Each invariant is a `REQ-HAZARD-*` requiring
   `unit` (and `int` where cross-process / cross-node). A hazard cannot be "covered" without a
   test tagging it — the anti-regression promise becomes mechanical.
5. **Activation, not premature failure.** Every requirement starts `required_stages = []`
   (inactive) so `check` stays green pre-code. A **milestone activates** the requirements it
   delivers by setting their real `required_stages`. Deferred items stay `[]` until promoted.
6. **Scan roots stay honest.** `[scan].roots` includes every evidence location (your source,
   tests, docs, and later your CI workflows and scripts). Audit roots whenever a new evidence
   dir appears — a missing root makes evidence *silently* vanish from the trace.

### Stages

`doc` (prose / design / API-doc) · `impl` (production code) · `unit` (unit test) · `int`
(integration / e2e / cross-process / cross-node). Default activation policy:
`["doc","impl","unit"]`; networking / lifecycle / cross-node reqs add `int`.

### Tag examples

Real tags are `[<stage>->REQ-ID]` with a bare stage word. The examples below angle-bracket the
stage (`[<impl>->...]`) only so the scanner treats them as illustrations, not live evidence —
write a bare stage word in real code.

```rust
// [<impl>->REQ-EXAMPLE-1]
fn do_the_thing(...) { ... }
```
```rust
// [<unit>->REQ-HAZARD-EXAMPLE]
#[test] fn upholds_the_invariant() { ... }
```
```markdown
<!-- [<doc>->REQ-EXAMPLE-1] -->
## The thing, explained
```

## Enforcement (four layers — defense in depth)

1. **CI gate (hard backstop).** `traceable-reqs check --json` runs on every PR / push; exit-1
   (`missing_stage` / `undeclared_id` / `parse_error` / `manifest_error`) **fails the build**. A
   PR can't merge if it leaves an *activated* req's required stage uncovered. Runs alongside the
   DOCS-STRATEGY docs-drift gate.
2. **Milestone activation gate.** Starting a milestone flips its reqs from `[]` to the real
   policy; the milestone **is not done until `check` is green for its reqs**. Coverage grows
   *with* the project instead of failing on day one.
3. **Agent-facing rule.** The repo `AGENTS.md` instructs every dev-agent: tag
   `[<stage>-><REQ-ID>]` in the same change as the evidence, and run `traceable-reqs check`
   before declaring done. If this project is built *with* agents, the contract must be
   machine-followable — agent discipline + CI as the net.
4. **Quality audit (anti-box-ticking).** `check` proves a tag *exists*; `traceable-reqs review`
   + `lint` audit whether tags sit near *real* evidence and whether titles are meaningful. Run
   advisory in CI (or periodically). Presence = hard gate; quality = audited.

Optional fast-feedback: a pre-push git hook running `traceable-reqs check` locally.

## CI snippet (hosted-runner fallback; see `docs/CI.md` for the agent-driven default)

```yaml
# .github/workflows/traceability.yml
name: traceability
on: [push, pull_request]
jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install traceable-reqs
        run: gh release download --repo BigscreenVR/traceable-reqs --pattern '*linux-x86_64' --output traceable-reqs && chmod +x traceable-reqs
        env: { GH_TOKEN: ${{ github.token }} }
      - name: Coverage gate (hard)
        run: ./traceable-reqs check --json
      - name: Quality audit (advisory)
        run: ./traceable-reqs lint || true
```

## Lifecycle

- **Now (planning):** manifest seeded, all reqs inactive. `check` is green (nothing required
  yet).
- **First milestone:** install the CLI, validate the seed against it, wire the CI gate,
  **activate that milestone's reqs** (and the `REQ-HAZARD-*` invariants it must uphold), tag as
  code lands.
- **Each later milestone:** activates + covers its requirements before it's called done.


1	# Known Hazards
2
3	> A **conformance checklist, not advice.** Each hazard below is a first-class
4	> `REQ-HAZARD-*` requirement in `traceable-reqs.toml`, and is **not "covered" until a test tags
5	> it** (`unit`, plus `int` where the failure is cross-process / cross-node). This file exists to
6	> make "we won't re-break X" mechanical: an entry without a passing tagged test is an open risk,
7	> and `traceable-reqs check` will say so once the hazard is activated.
8
9	A hazard earns a place here when it is an invariant you have *paid for once* (a real bug, an
10	incident) or one you have *committed never to introduce*. State it so a test can prove it.
11
12	## Entry format
13
14	Each entry is one numbered subsection with these fields:
15
16	- **Failure** — the concrete bad behavior: what goes wrong, under what sequence / timing / input.
17	- **Invariant** — the property that MUST hold, phrased so a test can assert it (the thing the
18	  `REQ-HAZARD-*` requires).
19	- **Mapping / notes** — where this lives in *this* project, and anything that changes the shape
20	  of the test (e.g. "in-process now, so use a lock instead of racing on disk").
21	- **cite** — where the failure / fix is evidenced (an incident, a prior commit, a source path);
22	  reference only — the binding evidence is the tagged test.
23
24	Mirror each entry as a requirement:
25
26	```toml
27	[[requirements]]
28	id = "REQ-HAZARD-EXAMPLE"
29	title = "The invariant, stated so a test can prove it"
30	required_stages = []   # activate (["unit"] or ["unit","int"]) when you cover it
31	```
32
33	---
34
35	## 1. `<Category — e.g. Race conditions & ordering>`
36
37	### 1.1 `<Short hazard name>` — PLACEHOLDER (replace with a real hazard)
38
39	- **Failure:** `<the concrete bad behavior and the exact sequence that triggers it>`.
40	- **Invariant:** `<the property that must hold, phrased for a test>`.
41	- **Mapping / notes:** `<where this lives in this project; what changes the test's shape>`.
42	- **cite:** `<incident / commit / source path — reference only>`.
43

# Known Hazards

> A **conformance checklist, not advice.** Each hazard below is a first-class
> `REQ-HAZARD-*` requirement in `traceable-reqs.toml`, and is **not "covered" until a test tags
> it** (`unit`, plus `int` where the failure is cross-process / cross-node). This file exists to
> make "we won't re-break X" mechanical: an entry without a passing tagged test is an open risk,
> and `traceable-reqs check` will say so once the hazard is activated.

A hazard earns a place here when it is an invariant you have *paid for once* (a real bug, an
incident) or one you have *committed never to introduce*. State it so a test can prove it.

## Entry format

Each entry is one numbered subsection with these fields:

- **Failure** — the concrete bad behavior: what goes wrong, under what sequence / timing / input.
- **Invariant** — the property that MUST hold, phrased so a test can assert it (the thing the
  `REQ-HAZARD-*` requires).
- **Mapping / notes** — where this lives in *this* project, and anything that changes the shape
  of the test (e.g. "in-process now, so use a lock instead of racing on disk").
- **cite** — where the failure / fix is evidenced (an incident, a prior commit, a source path);
  reference only — the binding evidence is the tagged test.

Mirror each entry as a requirement:

```toml
[[requirements]]
id = "REQ-HAZARD-EXAMPLE"
title = "The invariant, stated so a test can prove it"
required_stages = []   # activate (["unit"] or ["unit","int"]) when you cover it
```

---

## 1. `<Category — e.g. Race conditions & ordering>`

### 1.1 `<Short hazard name>` — PLACEHOLDER (replace with a real hazard)

- **Failure:** `<the concrete bad behavior and the exact sequence that triggers it>`.
- **Invariant:** `<the property that must hold, phrased for a test>`.
- **Mapping / notes:** `<where this lives in this project; what changes the test's shape>`.
- **cite:** `<incident / commit / source path — reference only>`.


1	# CI model — agent-driven, autonomous, no-LLM-in-the-loop
2
3	> spt-claude-code's CI is **wholly agent-driven and autonomous** on the existing Windows +
4	> Linux fleet (hfenduleam + kitsubito). **GitHub-hosted runners are NOT used** — a stock
5	> hosted runner physically can't run Claude Code (auth + interactivity), so only a real
6	> harness on the fleet reaches the acceptance bar. **Deterministic gates** run by a fleet
7	> runner-agent, triggered by a git post-push hook, reporting over **spt messaging**. No LLM
8	> sits in the gate path — the gates are plain scripts; the "agent" is just the autonomous
9	> runner that fires them and reports.
10
11	## The gates (deterministic)
12
13	Every gate is a script with a binary pass / fail — no judgment, no model:
14
15	1. **Build** — the project assembles clean.
16	2. **Unit tests** — the suite passes.
17	3. **`traceable-reqs check`** — requirement coverage gate; exit-1 fails the build (see
18	   `docs/TRACEABILITY.md`).
19	4. **Manifest-schema** — the CC adapter manifest validates against spt-core's **published**
20	   `manifest.schema.json` (from `SaberMage/spt-releases`).
21	5. **Docs-drift** — generated docs (API reference, `llms.txt`, schema, CLI help) are regenerated
22	   and must match what's checked in; a diff fails (see `docs/DOCS-STRATEGY.md`).
23
24	## Acceptance (the system-under-test is a real `claude` session)
25
26	Acceptance is **scripted orchestration that spawns real `claude` / headless sessions as the
27	system-under-test**, then asserts spt-state / `[digest]` output. The **LLM is the SUT, never
28	the runner** — the orchestration is deterministic; only the thing it drives is a real harness.
29	This is what a stock hosted runner can't do, and why the fleet is mandatory. (spt-core's
30	GH-runner justification — heavy multi-platform Rust + signed releases + two-host net — does
31	not carry here: the adapter binary is thin glue and delegates releases/signing to `spt`.)
32
33	## Reporting bus = spt messaging (dogfood)
34
35	The reporting bus is **legacy spt** (`$OWL send`): the runner reports gate/acceptance results
36	over spt messaging to the responsible agent / channel. This dogfoods the product as its own CI
37	nervous system.
38
39	## Trigger: git post-push hook → ping a runner-agent over spt
40
41	The trigger is **push-driven, not polling** (polling adds latency and wastes cycles):
42
43	1. A **git post-push hook** fires after a push.
44	2. The hook **`$OWL send`s a one-line "run gates for `<ref>`" message** to a fleet runner-agent
45	   over spt messaging.
46	3. The runner-agent **runs the deterministic gates** (and acceptance) on the fleet.
47	4. The runner **reports the result back over spt** to the responsible agent / channel.
48
49	### Discovering the `$OWL send` (spt messaging) binary robustly
50
51	The bus binary's path **changes between versions** — legacy spt lives in a per-version
52	`~/.claude/` or `~/.ccs/` plugins folder whose path moves each release. No further
53	legacy-spt changes are anticipated, but the hook and runner **must locate it robustly**:
54	resolve it at run time (search the known plugins/install roots / a configured path / `PATH`)
55	rather than hard-coding a versioned location. A stale hard-coded path is the most likely cause
56	of a silently dead trigger.
57
58	## Manual fallback
59
60	A **manual "run gates" command** must always exist — the same gate scripts, runnable by hand on
61	any fleet host. Use it when the hook didn't fire, when reproducing a failure, or before a hook is
62	wired at all.
63
64	## Hosted-runner workflow (not used here)
65
66	A hosted CI workflow (e.g. GitHub Actions) is **explicitly dropped** for this project: it can't
67	run the real-harness acceptance bar. `docs/TRACEABILITY.md` carries a ready GitHub Actions
68	snippet for the pure-deterministic `traceable-reqs check` gate if a hosted fallback is ever
69	wanted, but the agent-driven fleet pattern is the primary and intended path.
70

# CI model — agent-driven, autonomous, no-LLM-in-the-loop

> spt-claude-code's CI is **wholly agent-driven and autonomous** on the existing Windows +
> Linux fleet (hfenduleam + kitsubito). **GitHub-hosted runners are NOT used** — a stock
> hosted runner physically can't run Claude Code (auth + interactivity), so only a real
> harness on the fleet reaches the acceptance bar. **Deterministic gates** run by a fleet
> runner-agent, triggered by a git post-push hook, reporting over **spt messaging**. No LLM
> sits in the gate path — the gates are plain scripts; the "agent" is just the autonomous
> runner that fires them and reports.

## The gates (deterministic)

Every gate is a script with a binary pass / fail — no judgment, no model:

1. **Build** — the project assembles clean.
2. **Unit tests** — the suite passes.
3. **`traceable-reqs check`** — requirement coverage gate; exit-1 fails the build (see
   `docs/TRACEABILITY.md`).
4. **Manifest-schema** — the CC adapter manifest validates against spt-core's **published**
   `manifest.schema.json` (from `SaberMage/spt-releases`).
5. **Docs-drift** — generated docs (API reference, `llms.txt`, schema, CLI help) are regenerated
   and must match what's checked in; a diff fails (see `docs/DOCS-STRATEGY.md`).

## Acceptance (the system-under-test is a real `claude` session)

Acceptance is **scripted orchestration that spawns real `claude` / headless sessions as the
system-under-test**, then asserts spt-state / `[digest]` output. The **LLM is the SUT, never
the runner** — the orchestration is deterministic; only the thing it drives is a real harness.
This is what a stock hosted runner can't do, and why the fleet is mandatory. (spt-core's
GH-runner justification — heavy multi-platform Rust + signed releases + two-host net — does
not carry here: the adapter binary is thin glue and delegates releases/signing to `spt`.)

## Reporting bus = spt messaging (dogfood)

The reporting bus is **legacy spt** (`$OWL send`): the runner reports gate/acceptance results
over spt messaging to the responsible agent / channel. This dogfoods the product as its own CI
nervous system.

## Trigger: git post-push hook → ping a runner-agent over spt

The trigger is **push-driven, not polling** (polling adds latency and wastes cycles):

1. A **git post-push hook** fires after a push.
2. The hook **`$OWL send`s a one-line "run gates for `<ref>`" message** to a fleet runner-agent
   over spt messaging.
3. The runner-agent **runs the deterministic gates** (and acceptance) on the fleet.
4. The runner **reports the result back over spt** to the responsible agent / channel.

### Discovering the `$OWL send` (spt messaging) binary robustly

The bus binary's path **changes between versions** — legacy spt lives in a per-version
`~/.claude/` or `~/.ccs/` plugins folder whose path moves each release. No further
legacy-spt changes are anticipated, but the hook and runner **must locate it robustly**:
resolve it at run time (search the known plugins/install roots / a configured path / `PATH`)
rather than hard-coding a versioned location. A stale hard-coded path is the most likely cause
of a silently dead trigger.

## Manual fallback

A **manual "run gates" command** must always exist — the same gate scripts, runnable by hand on
any fleet host. Use it when the hook didn't fire, when reproducing a failure, or before a hook is
wired at all.

## Hosted-runner workflow (not used here)

A hosted CI workflow (e.g. GitHub Actions) is **explicitly dropped** for this project: it can't
run the real-harness acceptance bar. `docs/TRACEABILITY.md` carries a ready GitHub Actions
snippet for the pure-deterministic `traceable-reqs check` gate if a hosted fallback is ever
wanted, but the agent-driven fleet pattern is the primary and intended path.


Fully oriented. Key finding: `traceable-reqs check` is **RED** now — `manifest_error: scan root 'skills' is unreadable` (seed lists dirs that don't exist yet). CLI present (v0.1.2, global). Fixing the gate is the unambiguous first step.

JIT plan: body #1 = **foundation + skeleton-milestone kickoff** (green gate + milestone-scoped REQ seed + JIT plan doc). Body #2 = build the actual thin cplugs plugin skeleton. Minting only the skeleton milestone's REQs (per toml's "NOT up front" rule), all inactive.

Writing the JIT plan + fixing the registry.


Edit

[scan]
# Every evidence location. A missing root makes evidence SILENTLY vanish from the trace —
# audit this whenever a new evidence dir appears. Fill with this project's real layout.
roots = ["skills", "hooks", "plugin", "tests", "docs", "CONTEXT.md", "SCOPE.md"]

[scan]
# Every evidence location. A missing root makes evidence SILENTLY vanish from the trace —
# audit this whenever a new evidence dir appears. ADD `plugin`, `skills`, `hooks`, `tests`
# the moment those dirs are created (skeleton milestone, body #2) — until they exist a
# nonexistent root is a hard manifest_error, so only list what is on disk now.
roots = ["docs", "docs-site", "CONTEXT.md", "SCOPE.md", "AGENTS.md", "HANDOFF.md"]


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)

[scan]
# Every evidence location. A missing root makes evidence SILENTLY vanish from the trace —
# audit this whenever a new evidence dir appears. ADD `plugin`, `skills`, `hooks`, `tests`
# the moment those dirs are created (skeleton milestone, body #2) — until they exist a
# nonexistent root is a hard manifest_error, so only list what is on disk now.
roots = ["docs", "docs-site", "CONTEXT.md", "SCOPE.md", "AGENTS.md", "HANDOFF.md"]

# traceable-reqs manifest for spt-claude-code — SEED.
#
# Authoritative requirement registry: every requirement and every KNOWN-HAZARDS
# invariant lives here as a REQ-* id (see docs/TRACEABILITY.md for the full contract).
#
# SEED YOUR REQs FROM SCOPE.md "Parity-trim" — the DROP / TRANSFORM / KEEP / ADD buckets are
# the parity reference. Mint a REQ-* per surface you port/transform/add as you START each
# milestone (NOT up front). The registry below is intentionally EMPTY (commented shapes only).
#
# ACQUIRE the CLI (it is a released binary, not a crate dependency):
#   gh release download --repo BigscreenVR/traceable-reqs \
#     --pattern '*<your-platform>' --output traceable-reqs   # then chmod +x
# (see INSTANTIATE.md for per-platform patterns + CI wiring.) Validate this seed against
# the installed CLI before relying on it: `traceable-reqs check`.
#
# THE FOUR-STAGE CONTRACT: every requirement is traced from
#   doc  (prose/design)  ->  impl (production code)  ->  unit (unit test)  ->  int (cross-process/node)
# Tag evidence in the SAME commit, on/above the real evidence:
#   // [impl->REQ-FOO]   // [unit->REQ-FOO]   <!-- [doc->REQ-FOO] -->
#
# ACTIVATION MODEL: every requirement starts inactive (`required_stages = []`) so `check`
# stays green pre-code. A milestone ACTIVATES its requirements by setting their real
# `required_stages` when work on them begins. Deferred items stay [] until promoted.
# Never declare the full end-state stage list up front — activate incrementally as evidence
# lands (add "int" at the final integrating wave).

[scan]
# Every evidence location. A missing root makes evidence SILENTLY vanish from the trace —
# audit this whenever a new evidence dir appears. Fill with this project's real layout.
roots = ["skills", "hooks", "plugin", "tests", "docs", "CONTEXT.md", "SCOPE.md"]

[policy]
# Default policy applied at activation: doc + impl + unit. Networking/lifecycle/cross-node
# reqs add "int". Until a req is activated, its per-req `required_stages = []` keeps it out
# of the coverage gate.
required_stages = []

# ───────────────────────────── Requirements ─────────────────────────────────
# Add requirements as you scope milestones, seeded from SCOPE.md "Parity-trim". Shape:
#
# [[requirements]]
# id = "REQ-EXAMPLE-1"
# title = "One-line statement of the requirement"
# required_stages = []  # activate (e.g. ["doc","impl","unit"]) when the milestone starts
#
# KNOWN-HAZARDS invariants are first-class requirements — one REQ-HAZARD-* per invariant,
# each requiring at least "unit" (add "int" where cross-process/cross-node):
#
# [[requirements]]
# id = "REQ-HAZARD-EXAMPLE"
# title = "The invariant, stated so a test can prove it"
# required_stages = []

-# audit this whenever a new evidence dir appears. Fill with this project's real layout.

-roots = ["skills", "hooks", "plugin", "tests", "docs", "CONTEXT.md", "SCOPE.md"]

+# audit this whenever a new evidence dir appears. ADD `plugin`, `skills`, `hooks`, `tests`

+# the moment those dirs are created (skeleton milestone, body #2) — until they exist a

+# nonexistent root is a hard manifest_error, so only list what is on disk now.

+roots = ["docs", "docs-site", "CONTEXT.md", "SCOPE.md", "AGENTS.md", "HANDOFF.md"]


# KNOWN-HAZARDS invariants are first-class requirements — one REQ-HAZARD-* per invariant,
# each requiring at least "unit" (add "int" where cross-process/cross-node):
#
# [[requirements]]
# id = "REQ-HAZARD-EXAMPLE"
# title = "The invariant, stated so a test can prove it"
# required_stages = []

# KNOWN-HAZARDS invariants are first-class requirements — one REQ-HAZARD-* per invariant,
# each requiring at least "unit" (add "int" where cross-process/cross-node):
#
# [[requirements]]
# id = "REQ-HAZARD-EXAMPLE"
# title = "The invariant, stated so a test can prove it"
# required_stages = []

# ── Milestone: SKELETON (thin cplugs plugin) — minted at kickoff, per-milestone (not
# the whole registry up front). All inactive (required_stages = []) so `check` stays
# green until body #2 lands evidence and flips each to ["doc"] / ["doc","impl"] etc.
# Seeded from SCOPE.md "Parity-trim" (Distribution + ADD buckets).

[[requirements]]
id = "REQ-DIST-PLUGIN-SKELETON"
title = "Marketplace artifact on cplugs is a thin skeleton: namespaced /spt:* skill stubs + hooks.json + plugin.json, no embedded logic"
required_stages = []

[[requirements]]
id = "REQ-DIST-BOOTSTRAP-INSTALL"
title = "SessionStart bootstrap installs spt-core when absent (invisible-installer pattern)"
required_stages = []

[[requirements]]
id = "REQ-DIST-HOOKS-API"
title = "hooks.json delegates to `spt api` rather than carrying adapter logic"
required_stages = []

[[requirements]]
id = "REQ-DIST-MANIFEST-SCHEMA"
title = "CC adapter manifest validates against spt-core's published manifest.schema.json (from spt-releases)"
required_stages = []

[[requirements]]
id = "REQ-UPS-INJECTION"
title = "UserPromptSubmit hook detects /spt:X and injects X's real instructions as additionalContext (SKILL.md files stay skeletons); must be empirically confirmed UPS fires on slash-commands"
required_stages = []

[[requirements]]
id = "REQ-SKILL-VERSION"
title = "/spt:version reports the spt-core-tracked manifest/binary version (the version-of-truth, not the marketplace skeleton version)"
required_stages = []