Async agent launched successfully.
agentId: a94778ae077fae982 (internal ID - do not mention to user. Use SendMessage with to: 'a94778ae077fae982' to continue this agent.)
The agent is working in the background. You will be notified automatically when it completes.
Do not duplicate this agent's work — avoid working with the same files or topics it is using. Work on non-overlapping tasks, or briefly tell the user what you launched and end your response.
output_file: C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\13c96a50-2b78-4c16-a995-1da2b1836fd8\tasks\a94778ae077fae982.output
Do NOT Read or tail this file via the shell tool — it is the full subagent JSONL transcript and reading it will overflow your context. If the user asks for progress, say the agent is still running; you'll get a completion notification.

Fact-check UPS hook on slash-skill

Prompt:
Authoritative, current facts (cite docs, flag version-dependence). Concise, bottom-line each.

Scenario: a Claude Code plugin ships slash-command skills namespaced like `/spt:send`. I want a `UserPromptSubmit` hook to detect the invocation and inject the skill's real instructions as additionalContext (so the skill's own SKILL.md can stay a near-empty skeleton, with instructions delivered dynamically by the hook).

Answer:
1. When a user types a plugin slash-command/skill invocation like `/spt:send hello`, does the `UserPromptSubmit` hook fire, and does it receive the literal text `/spt:send hello` on stdin? Or does Claude Code intercept slash-commands/skills BEFORE UserPromptSubmit so the hook never sees them?
2. Can a `UserPromptSubmit` hook inject `additionalContext` that lands in the SAME turn the user invoked the command (so the injected instructions are present when the skill/command executes)?
3. How do a plugin SKILL.md's own body and UserPromptSubmit-injected additionalContext combine in one turn — does the skill body still load + execute, with the additionalContext as extra context? Any ordering/precedence gotcha?
4. Is there a BETTER native mechanism than UserPromptSubmit for "dynamically supply a skill's instructions at invocation time from an external source" — e.g. does a skill/command support an exec/generated body, or a hook event specific to skill invocation (PreSkill / SlashCommand)? List any relevant hook events.
5. Bottom line: is the "skeleton SKILL.md + UserPromptSubmit injects real instructions" pattern viable and reliable, or is there a failure mode (e.g. hook doesn't see slash invocations, or additionalContext doesn't reach the executing turn)?

If uncertain/undocumented, say so explicitly.


Agent

Pull legacy capsule plans

Prompt:
In the legacy project C:\Users\decid\Documents\projects\claude_skill_owl, find and summarize the planning docs for the unbuilt "Capsule" milestone (also search "capsule", "capsule-style", "psmux", "keystroke injection", "endpoint launcher", "cc " launcher). Search thoroughly — check root *.md, docs/, .planning/, any PLAN/MILESTONE/ROADMAP files, and CHANGELOG mentions.

I'm designing a `/spt:setup` skill for a new adapter that generates an endpoint launcher script (a `cc` / `cc <endpoint-id>` command at project root that fires up or attaches to an spt endpoint — "capsule style").

Report:
1. What Capsule was meant to be / its goals (the vision).
2. How it intended to launch/attach Claude Code sessions (psmux? terminal multiplexer? keystroke injection? detached process?).
3. The launcher UX it envisioned (commands, args, attach-to-existing vs new).
4. Any design decisions, hazards, or open questions recorded.
5. Why it was never built / what blocked it.

Give file paths as evidence + excerpts. Conclusions over dumps. If there's little, say so.


<owl_messages>
<owl_message from="doyle-w367" priority="info">[WORKING_PERCH_NOTICE] Subagent working perch created.
Perch: doyle-w367
Agent type: claude-code-guide
To message it: $OWL send doyle-w367 doyle</owl_message>
</owl_messages>

[OWL SYSTEM] Informational owl messages above — no acknowledgment needed. Continue your current task.

<owl_reachability_notice>
You have an active owl perch. Launch this Agent with run_in_background: true so you stay reachable for incoming messages while it works.
</owl_reachability_notice>


Async agent launched successfully.
agentId: a55df29a91f57f269 (internal ID - do not mention to user. Use SendMessage with to: 'a55df29a91f57f269' to continue this agent.)
The agent is working in the background. You will be notified automatically when it completes.
Do not duplicate this agent's work — avoid working with the same files or topics it is using. Work on non-overlapping tasks, or briefly tell the user what you launched and end your response.
output_file: C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\13c96a50-2b78-4c16-a995-1da2b1836fd8\tasks\a55df29a91f57f269.output
Do NOT Read or tail this file via the shell tool — it is the full subagent JSONL transcript and reading it will overflow your context. If the user asks for progress, say the agent is still running; you'll get a completion notification.

Pull legacy capsule plans

Prompt:
In the legacy project C:\Users\decid\Documents\projects\claude_skill_owl, find and summarize the planning docs for the unbuilt "Capsule" milestone (also search "capsule", "capsule-style", "psmux", "keystroke injection", "endpoint launcher", "cc " launcher). Search thoroughly — check root *.md, docs/, .planning/, any PLAN/MILESTONE/ROADMAP files, and CHANGELOG mentions.

I'm designing a `/spt:setup` skill for a new adapter that generates an endpoint launcher script (a `cc` / `cc <endpoint-id>` command at project root that fires up or attaches to an spt endpoint — "capsule style").

Report:
1. What Capsule was meant to be / its goals (the vision).
2. How it intended to launch/attach Claude Code sessions (psmux? terminal multiplexer? keystroke injection? detached process?).
3. The launcher UX it envisioned (commands, args, attach-to-existing vs new).
4. Any design decisions, hazards, or open questions recorded.
5. Why it was never built / what blocked it.

Give file paths as evidence + excerpts. Conclusions over dumps. If there's little, say so.


agree with ccs as profile and fllback wording, agree with hybrid. note that ccs also has a different i.e. `~/.ccs` logs dir per ccs profile. -for the skeleton plugin, note that spt-claude-code can use…


Align spt-claude-code with spt-core v1 requirements


<task-notification>
<task-id>a94778ae077fae982</task-id>
<tool-use-id>toolu_01SEXCe3MLdRbwAyVCdwEpQW</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\13c96a50-2b78-4c16-a995-1da2b1836fd8\tasks\a94778ae077fae982.output</output-file>
<status>completed</status>
<summary>Agent "Fact-check UPS hook on slash-skill" completed</summary>
<result>Based on the Claude Code hooks reference, here are the authoritative answers to your five questions:

## 1. Does UserPromptSubmit fire for slash-command invocations?

**No explicit documentation provided.** The hooks reference shows `UserPromptSubmit` fires when "User submits prompt" with input `{"prompt": "User's prompt text"}`, but there's no mention of whether slash-commands/skills are intercepted *before* this hook fires or whether they appear in the prompt text.

**Likely behavior (not documented):** Claude Code almost certainly intercepts slash-commands before UserPromptSubmit (skills are CLI-native parsing, not LLM-visible input). The hook probably never sees `/spt:send hello` because the CLI recognizes the `/` prefix and routes directly to the skill/command handler.

---

## 2. Can UserPromptSubmit inject additionalContext for the same turn?

**Yes, documented.** UserPromptSubmit output includes:
```json
{
  "hookSpecificOutput": {
    "hookEventName": "UserPromptSubmit",
    "additionalContext": "Additional context"
  }
}
```

The additionalContext lands in the current turn. **However**, this only helps if the hook actually receives the prompt before skill execution (see #1 — doubtful for slash-commands).

---

## 3. Skill body + injected additionalContext — how do they combine?

**Not documented.** The hooks reference doesn't explain the execution order or precedence when additionalContext is injected alongside a skill's own SKILL.md body. Reasonable assumptions:
- Both likely load (SKILL.md body + additionalContext)
- Order unknown — unclear if additionalContext comes before/after skill body in the context stack
- No documented precedence rule for conflicts

---

## 4. Better native mechanism than UserPromptSubmit?

**Not found in the hooks reference.** The 27 documented hook events don't include:
- `PreSkill` or `SlashCommand` — no skill-invocation-specific hook
- Dynamic/generated skill body loading — no mechanism documented
- `exec` or executable skill body format — no mention

**Only mechanisms documented:**
- `UserPromptSubmit` (fires on prompt, but likely *after* slash-command interception)
- `ConfigChange` (fires on settings.json changes, not useful for dynamic skill instructions)
- `InstructionsLoaded` (fires when CLAUDE.md/.claude/rules/*.md loaded — not for skill-specific bodies)

---

## 5. Bottom line: Is the skeleton SKILL.md + UserPromptSubmit pattern viable?

**Viable but fragile — likely *not* reliable.** Failure modes:

1. **Slash-commands bypass UserPromptSubmit entirely** (most likely, undocumented). If Claude Code intercepts `/spt:send` before UserPromptSubmit fires, the hook never executes, and your injected instructions never reach the skill.

2. **No documented hook fires at skill invocation time**. There's no `PreSkill` or equivalent to reliably intercept skill calls and inject context.

3. **Timing unknown**. If UserPromptSubmit *does* fire, unclear whether additionalContext reaches the skill execution in the same turn or only the LLM's response.

---

## Recommendation

**Ship the pattern with a caveat, then test empirically:**

- Configure UserPromptSubmit to inject a matcher on the prompt text (e.g., `if: "prompt.*spt.*send"`) and inject instructions as additionalContext
- **Test**: invoke `/spt:send hello` and observe whether the injected instructions appear in the skill's execution context
- If it doesn't work, fall back to:
  - **Populate SKILL.md with the real instructions** (skeleton won't work if the hook doesn't fire)
  - **Use a wrapper script** that loads instructions from external source before invoking the skill
  - **Request a feature** via `/feedback` for `PreSkillInvocation` hook or skill-body generation support

The feature is **undocumented**, so flag it as experimental and document the failure mode clearly in your skill's README.

Sources:
- [Claude Code Hooks Reference](https://code.claude.com/docs/en/hooks) – all 27 hook events and schemas</result>
<usage><subagent_tokens>32325</subagent_tokens><tool_uses>2</tool_uses><duration_ms>19319</duration_ms></usage>
</task-notification>


Two premises under verification (UPS-hook-sees-slash-skill; legacy Capsule plans). While they run, engaging your open design questions:

**Update-notification problem — reframe.** If spt-core's adapter-update framework conducts updates, users shouldn't *check* — updates apply seamlessly (that's the value prop). So:
- **Version-of-truth = the manifest/binary version spt-core tracks**, surfaced via `spt adapter list` / a `/spt:version`. The *marketplace* skeleton version is NOT the truth (it barely moves).
- **Notification = spt-core announces post-update**: one-time SessionStart additionalContext ("spt-claude-code updated v→v, changelog…") + optional `notify` (it's a messaging system — use it).
- No marketplace-version-watching. spt-core push-updates + tells the user. This also justifies your dual update path: file-pull is the real channel, `claude plugin update` is the cautionary skeleton-sync.

**Non-desktop elevation (the image's open Q).** The self-elevating window is a *GUI* affordance. Generalize by detecting (interactive? elevated? desktop-session?):
| Env | Elevation path |
|---|---|
| Windows | self-elevating UAC window (as drawn) |
| Linux + desktop | `pkexec`/polkit prompt, or x-terminal-emulator running the command |
| Linux + interactive TTY (SSH) | inline `sudo` — terminal *is* the prompt, no window needed |
| headless / no-TTY (agent-spawned) | can't prompt → **print exact command + agent relays it to the user** |

Universal fallback = hand the human the exact command via the agent. Also question the premise: **does `subnet create` even need elevation?** Scope it — elevation is for OS-service register / firewall / privileged-port, not necessarily subnet creation itself. Keep the unprivileged path unprivileged.

**`/spt:setup` — expanded path set** (your 4 + more):
1. Generate `cc`/`cc <id>` launcher (capsule-style) — *grounding in legacy plans, pending*
2. Offer `.gitignore` the launchers — agree, trivial
3. Offer create first subnet (self-elevating TOTP idea)
4. If spt-core already installed → branch: new subnet / **join subnet** / **show join-code** / **add this machine to existing subnet** / just-add-endpoint
5. **Legacy migration** — detect `claude_skill_owl`/owl install → migrate identity+agents+psyche (CONTEXT.md's first-class commitment; high-value)
6. **OS-service registration** — offer always-on daemon (README's "🔜 next")
7. **ccs profile wiring** — if `~/.ccs` detected, offer to create a ccs profile
8. **Psyche cross-machine sync** — offer `psyche-sync-setup`
9. **Doctor/verify** at end — confirm healthy install

**Active question — `/spt:setup` v1 scope:** which of 1–9 are v1-mandatory vs deferred? My rec for v1-mandatory: **1, 2, 3, 4, 5, 9** (the install/onboarding spine + legacy migration, since legacy users are your actual current base). Defer **6, 7, 8** to fast-follow (service-install, ccs, sync are power-user paths). Agree, or pull any up/down?


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


<owl_messages>
<owl_message from="doyle-w368" priority="info">[WORKING_PERCH_NOTICE] Subagent working perch created.
Perch: doyle-w368
Agent type: Explore
To message it: $OWL send doyle-w368 doyle</owl_message>
</owl_messages>

[OWL SYSTEM] Informational owl messages above — no acknowledgment needed. Continue your current task.

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


<task-notification>
<task-id>a55df29a91f57f269</task-id>
<tool-use-id>toolu_0161wAvEApHz62V9e3VDVnJs</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\13c96a50-2b78-4c16-a995-1da2b1836fd8\tasks\a55df29a91f57f269.output</output-file>
<status>completed</status>
<summary>Agent "Pull legacy capsule plans" completed</summary>
<result>Perfect! Now I have a clear picture. Let me write the final summary:

## Summary: Capsule Milestone Planning

Based on thorough analysis of the legacy `claude_skill_owl` project, here's what was designed for the unbuilt v1.9 **Capsule** milestone:

---

### 1. **What Capsule Was Meant to Be**

**Capsule** was a hosting mode for SPT (Spacetime) agents that launches Claude Code inside a `psmux` terminal session and controls it via keystroke injection instead of standard message polling.

**Three motivations:**
- **Pre-Monitor replacement**: Before Claude Code's Monitor tool, the poll listener had to die after each Bash tool call and restart manually. Capsule would provide a clean external listener lifecycle.
- **Remote control substrate**: Enable full remote agent control (issuing `/clear`, injecting input directly) for networked messaging and novel surfaces (VR, handhelds).
- **Agent self-driving**: Let agents drive their own and each other's sessions—clearing context while seeding the next generation.

**Vision from `CONTEXT.md`:**
> *"Moves the poll listener out of the Claude Code process tree and alongside the psmux session, letting SPT inject input directly into the CC prompt instead of waiting for the agent to ingest messages from a Monitor stream or PreToolUse hook."*

---

### 2. **How It Intended to Launch/Attach Sessions**

**Launcher mechanism** (`/spt:build-capsule` skill):
- Downloads latest `psmux.exe` to `{SPT_HOME}/bin/` (honoring SPT_HOME override)
- Generates `[projectroot]/capsule.bat` that references the fresh psmux.exe

**Session launch flow** (`capsule.bat`):
1. Accepts a required `agent_id` argument
2. Launches `claude --dangerously-skip-permissions` in a **named psmux session** (named `spt-{agent_id}`)
3. Passes init prompt containing agent_id + 'live' state via `--system-prompt` or `--append-system-prompt`
4. Creates a **skeleton perch** (registered but agent not yet alive) with agent_id, PID, and `state: Capsule`
5. Spawns a capsule listener process (fork of poll.rs) outside the Claude Code process tree
6. Attaches user to the psmux session via named session reattachment

**Optional flags:**
- `-l`/`--live` flag: marks session as live (enables Psyche wrapper)
- `-r`/`--resume <session_id>`: reattaches to existing cc_session_id for that agent

**Re-attachment to existing psmux:**
- Checks if a psmux session named `spt-{agent_id}` already exists
- If yes, attaches user to running session instead of creating new one
- Resolves `--resume <agent_id>` to latest stored cc_session_id (not raw session IDs)

---

### 3. **Intended Launcher UX**

**Startup sequence:**
- Terminal tab/window renamed to agent_id before psmux attach
- Historical stdout message displayed:
  ```
  Now launching a spacetime capsule for agent 'doyle'...
  a: {cc_session_id}
  p: {psyche_session_id}  # if live
  ```
  Or if re-attaching:
  ```
  Reactivating the spacetime capsule for agent 'doyle'...
  a: {cc_session_id}
  p: {psyche_session_id}
  ```
- User then attached to named psmux session

**Interactive picker** (SEED-001):
- When `capsule.bat` invoked without agent-name, present CLI selector
- Lists all previous agents for current project, sorted by last-active date
- "New agent" sentinel option at end
- Selector mirrors Claude Code's `AskUserQuestion` UX (arrow-key nav + inline text capture)

**psmux session styling** (from `v1-9 capsule additional features.md`):
- PowerShell-like highlight (sticky selection vs insta-copy)
- Cleaner status bar (no gaudy green background)
- Settings stored in `.claude/` for project portability

---

### 4. **Design Decisions, Hazards, Open Questions**

**Recorded decisions:**

| Decision | Source |
|----------|--------|
| **agent_id is REQUIRED** | Capsule exists wholly to enable spacetime messaging; cannot launch without it | `.planning/docs/v1-9 capsule additional features.md` |
| **Latest session stored in perch** | `--resume <agent_id>` only accepts agent_id, not raw cc session IDs. Latest session_id stored against agent_id in `.registry` or perch metadata | Same |
| **Message framing must be visually distinct** | Sendkeys deliveries wrapped in `--- [INCOMING] message from {sender} ---` prefix so agents distinguish injected input from user typing | `src/common/psmux.rs` (already implemented) |
| **Reattach checks for existing psmux** | Before launching new session, check if `spt-{agent_id}` session exists; reattach if present | `.planning/todos/pending/2026-04-13-capsule-reattach-existing-psmux-session.md` |
| **Terminal title via OSC** | Set console title before attach: `[Console]::Title = "{agent_id}"` on Windows; equivalent on Unix | `.planning/docs/v1-9 capsule additional features.md` |

**Hazards and open questions:**

| Hazard | Source |
|--------|--------|
| **Sendkeys pitfalls #1, #2** | Literal mode (`-l`) doesn't interpret `\n` as Enter → requires separate Enter sendkeys call | `src/common/psmux.rs` comments |
| **Project scoping for selector** | What defines "this project" for `AskUserQuestion` picker? cwd vs git root vs psmux winname? | SEED-001 open question |
| **Sort key for selector** | "Last active" = perch info.json mtime vs last commune timestamp vs last poll? | SEED-001 open question |
| **Headless fallback** | If stdin not a TTY, must error gracefully with hint (don't hang) | SEED-001 open question |
| **Partial input preservation** | When message injected while user has partially typed input, preserve and restore after injection | `.planning/milestones/v1.7-ROADMAP.md` Phase 20 SC #5 |
| **psmux config file location** | Can psmux be guided to settings file with flag? If yes, store in `.claude/` for portability | `.planning/docs/v1-9 capsule additional features.md` |

**Cap-specific TODOs deferred to v1.9** (from STATE.md):
- `2026-04-13-capsule-reattach-existing-psmux-session` → Phase 19 scope
- `2026-04-13-abrupt-messaging-precede-sendkeys-with-ctrl-b-esc-sequence` → Phase 21 scope
- `2026-04-13-capsule-psmux-use-winname-flag-for-repo-branch` → Phase 19 additional feature

---

### 5. **Four Planned Phases (Never Started)**

**Phase 19: Sendkeys Foundation & Capsule Launch** (0/4 plans)
- Deliver: PsmuxSendkeys module, capsule.exe binary, capsule.bat launcher, `/spt:build-capsule` skill
- Scaffolded: `PerchState::Capsule` enum variant exists in `src/common/types.rs`; `PsmuxSendkeys` module stub in `src/common/psmux.rs` (with frame_message logic)

**Phase 20: Session Detection & Capsule Listener** (0/2 plans)
- Detect capsule sessions via SessionStart hook
- Capsule listener delivers sendkeys when idle, respools to inbox when busy
- Watch Claude PID for teardown

**Phase 21: Abrupt Messages** (0/2 plans)
- Force-interrupt via ESC sendkeys (ctrl+b, wait ~2sec, ESC)
- Inject message immediately while agent is busy
- Timing-safe delivery

**Phase 22: Smart Capabilities** (0/2 plans)
- Auto-rename session to agent_id via `/rename` sendkeys
- GSD proceed: fire `/clear` + next GSD command via sendkeys
- Live-reload plugins via `capsule-reload-plugins` sendkeys

**Also planned but independent:**
- **SEED-001**: Interactive agent selector when no agent name given (sorted by last-active; mirrors `AskUserQuestion`)
- **SEED-002**: Project-status psmux popup at capsule boot (latest work + do-next from commune metadata)

---

### 6. **Why It Was Never Built**

**Not explicitly documented as "blocked,"** but context reveals **deprioritization due to Monitor tool arrival:**

From `CONTEXT.md`:
> *"Pre-Monitor-tool, the poll listener had to die after each Bash-tool message and be manually revived; **capsule would have given a clean external listener. Monitor tool has since obviated this urgency.**"*

**Execution order changed:** v1.8 (Psyche Restructure, Phases 23/24/25/35) and v1.7 (Seamlessification, Phases 26-30) were **sequenced BEFORE v1.9** despite higher phase numbers. Both shipped (v1.7 on 2026-05-16, v1.8 phases 23/24/25/35 completed by 2026-05-29).

**Current status** (as of last STATE.md 2026-05-29):
- Phases 19-22 listed as "Not started" in ROADMAP progress table
- v1.8 Phase 999.1 is now active (rearrange psyche organization)
- No Phase 19 phase directory created; no plan files exist
- v1.9 milestone remains on the roadmap but has been deprioritized in favor of Psyche structural work

**Evidence from codebase:**
- `PsmuxSendkeys` module skeleton exists but has no callers
- `PerchState::Capsule` enum variant exists with roundtrip tests but no instantiation site
- `bin_dir()` helper in owlery.rs references capsule.bat template but template not found
- WAKE_SENTINEL_PREFIX defined but only used in tests and the skeleton psmux.rs module

---

### Evidence Files

- `.planning/milestones/v1.7-ROADMAP.md` — Phase 19-22 full requirements, success criteria, plan stubs
- `.planning/docs/v1-9 feature sprint - capsule.md` — Complete design doc (SessionStart hook, listener architecture)
- `.planning/docs/v1-9 capsule-only features.md` — Abrupt messages, smart rename, GSD proceed, reload-plugins
- `.planning/docs/v1-9 capsule additional features.md` — Terminal title, stdout messages, psmux styling
- `.planning/seeds/SEED-001-capsule-interactive-agent-selector.md` — Picker UX design (last-active sort, TTY fallback)
- `.planning/seeds/SEED-002-capsule-project-status-popup.md` — Boot popup + on-demand `/spt:project-status` recall
- `.planning/STATE.md` — Deferred item list (3 capsule-scoped TODOs, all open)
- `src/common/psmux.rs` — Phase 19 sendkeys primitives (send_message, frame_message, has_session check)
- `src/common/types.rs` — PerchState::Capsule enum variant + roundtrip test</result>
<usage><subagent_tokens>63759</subagent_tokens><tool_uses>25</tool_uses><duration_ms>74866</duration_ms></usage>
</task-notification>


UPS fact-check changes one of your mechanisms. Verdict: **skeleton-SKILL.md + UserPromptSubmit-injection is fragile** — slash-commands are *probably intercepted by the CLI before UserPromptSubmit fires* (undocumented, but the lean is "the hook never sees `/spt:send`"). So injecting skill instructions via UPS on slash-detection is unreliable.

But your *goal* (thin skill files, instructions live in the adapter, spt-core-updatable) survives — via a more robust mechanism:

**Skill-body-as-fetch-stub.** Each `/spt:X` SKILL.md = a 2-line stub: *"Run `spt adapter get-string claude-spt skill.X` (or `spt skill-help X`) and follow the returned instructions."* The agent executes that on invocation, pulls the real instructions from `[strings]`, proceeds.

Why this beats UPS-injection:
- **No hook-timing dependency** — it's the skill body itself fetching; works regardless of whether UPS fires on slash-commands.
- Same payoff: SKILL.md stays a skeleton; instruction churn lives in spt-core-conducted strings; marketplace plugin rarely moves.
- Costs one Bash round-trip per invocation (can be once-per-session cached like hints).

**Clean division of the two channels:**
- **`[hints]` via UPS hook** — proactive, keyword-triggered, fires on *normal* prompts (legacy already does this — it works). Keep as-is.
- **Skill instructions via fetch-stub** — deterministic, on *explicit* `/spt:X`. Not hook-dependent.

(UPS-injection stays a *possible* enhancement if build-time testing shows it does fire on slash-commands — but don't architect on it.)

Agree on the fetch-stub as the skill-instruction mechanism?

Still open from last turn: **`/spt:setup` v1 scope** (my rec: v1 = paths 1,2,3,4,5,9; defer 6,7,8). Capsule-launcher grounding still in flight.


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


Capsule plans landed — and they map almost entirely onto spt-core's **native terminal hosting**. Key realization:

Legacy Capsule = launch CC in psmux + sendkeys injection + external listener. In spt-core that's the **spt-hosted topology**: broker holds the PTY, daemon injects input directly, remote-attach exists. So the `cc`/`cc <id>` launcher = a **thin wrapper over spt-core's spawn-session + inject + attach seams** — *not* a reimplemented psmux. spt-core's broker IS the terminal host.

**`cc` launcher recommendation:**
- `cc <id>` → `spt` spawns-or-attaches a CC endpoint hosted in a broker PTY.
- Reattach-if-exists, `--live`, `--resume` → already spt-core spawn/resume-seam semantics.
- No-id picker → **reuse spt-core's built-in id-resolution** (CONTEXT.md: "no id → picker with proposed default IDs"), don't reimplement legacy SEED-001.
- Sendkeys hazards (literal-Enter, abrupt-interrupt, partial-input-preserve) = already spt-core's inject-input concern, not the adapter's.

**One gap to confirm later:** capsule's real value was the *user attaching* to watch/drive the session. Need to verify spt-core's "remote attach" covers **local user attach to a hosted CC session** (interactive terminal), not just headless PTY. Flagging — don't resolve now.

---

This is a natural checkpoint — large architecture is locked. Persisting decisions to the spt-claude-code folder now (your stated intent), so nothing's lost:


Bash

cd 'C:\Users\decid\Documents\projects\spt-claude-code'; git init -q 2>&1; git config user.name "Reavo End" 2>&1; mkdir -p docs/adr 2>&1; ls -la

Init spt-claude-code git + docs dir


total 20
drwxr-xr-x 1 decid 197609 0 Jun 14 01:36 .
drwxr-xr-x 1 decid 197609 0 Jun 14 00:22 ..
drwxr-xr-x 1 decid 197609 0 Jun 13 22:09 .claude
drwxr-xr-x 1 decid 197609 0 Jun 14 01:36 .git
drwxr-xr-x 1 decid 197609 0 Jun 14 01:36 docs
Shell cwd was reset to C:\Users\decid\Documents\projects\spt-core


Write

# 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: fetch-stub**

Each `/spt:X` SKILL.md = a 2-line stub: "run `spt adapter get-string claude-spt
skill.X` (or `spt skill-help X`) and follow returned instructions." Agent fetches
real instructions from `[strings]` at invocation. No hook-timing dependency.
- Rejected: UserPromptSubmit-injection on slash-detection — fact-check says
  slash-commands are *probably intercepted before UPS fires* (undocumented, fragile).
  May revisit as enhancement if build-time testing shows UPS does fire on slashes.
- `[hints]` channel (UPS hook, keyword-triggered, normal prompts) kept as-is — legacy
  already does this and it works. Clean split: hints=proactive/UPS; skill-instr=fetch-stub.

### 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 (self-elevating TOTP — see elevation below)
4. If spt-core already installed → branch: new subnet / join subnet / show join-code /
   add-this-machine / just-add-endpoint
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` detected)
8. Psyche cross-machine sync (psyche-sync-setup)
9. Doctor/verify at end

**OPEN:** v1 scope. doyle rec: v1 = {1,2,3,4,5,9}; defer {6,7,8}.

### `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.
- **OPEN:** trigger (git-hook signal vs polling routine).
- This CI pattern → reusable, goes in `experimplate`.

## Open threads (grill queue)

- [ ] `/spt:setup` v1 scope (1–9 above)
- [ ] Parity-trim: which legacy concepts/skills DON'T survive → becomes REQ seed / acceptance bar
- [ ] Release / changelog / published-docs procedure reframed same-repo (template content)
- [ ] CI trigger mechanism
- [ ] spt-core "remote attach" local-interactive confirmation
- [ ] Handoff framing to perri (how the package is presented + public-surface-only constraint)
- [ ] Docs split: what lands in experimplate vs spt-claude-code


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

# 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: fetch-stub**

Each `/spt:X` SKILL.md = a 2-line stub: "run `spt adapter get-string claude-spt
skill.X` (or `spt skill-help X`) and follow returned instructions." Agent fetches
real instructions from `[strings]` at invocation. No hook-timing dependency.
- Rejected: UserPromptSubmit-injection on slash-detection — fact-check says
  slash-commands are *probably intercepted before UPS fires* (undocumented, fragile).
  May revisit as enhancement if build-time testing shows UPS does fire on slashes.
- `[hints]` channel (UPS hook, keyword-triggered, normal prompts) kept as-is — legacy
  already does this and it works. Clean split: hints=proactive/UPS; skill-instr=fetch-stub.

### 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 (self-elevating TOTP — see elevation below)
4. If spt-core already installed → branch: new subnet / join subnet / show join-code /
   add-this-machine / just-add-endpoint
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` detected)
8. Psyche cross-machine sync (psyche-sync-setup)
9. Doctor/verify at end

**OPEN:** v1 scope. doyle rec: v1 = {1,2,3,4,5,9}; defer {6,7,8}.

### `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.
- **OPEN:** trigger (git-hook signal vs polling routine).
- This CI pattern → reusable, goes in `experimplate`.

## Open threads (grill queue)

- [ ] `/spt:setup` v1 scope (1–9 above)
- [ ] Parity-trim: which legacy concepts/skills DON'T survive → becomes REQ seed / acceptance bar
- [ ] Release / changelog / published-docs procedure reframed same-repo (template content)
- [ ] CI trigger mechanism
- [ ] spt-core "remote attach" local-interactive confirmation
- [ ] Handoff framing to perri (how the package is presented + public-surface-only constraint)
- [ ] Docs split: what lands in experimplate vs spt-claude-code


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


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

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


Checkpoint persisted → `spt-claude-code/SCOPE.md` (decision ledger) + `CONTEXT.md` (glossary). Nothing lost; grows each round.

Carryover questions still open: **fetch-stub mechanism** (agree?) and **`/spt:setup` v1 scope** (rec: {1,2,3,4,5,9}, defer {6,7,8}).

Now the meaty thread that feeds the REQ seed / acceptance bar:

**Q6 — Parity-trim.** Legacy ≠ 1:1. Sorting legacy's surface into buckets (drives what spt-claude-code must REQ):

| Bucket | Items | Rationale |
|---|---|---|
| **DROP** (dead or spt-core absorbs) | Spine & Touch (dormant), binary-handoff/owl.exe trampoline, TCP transport + SQLite spool + registry + listener internals, localhost-only networking | all now spt.exe/daemon, or never used |
| **TRANSFORM** (legacy concept → spt-core seam) | Capsule→spt-hosted topology + `cc`; echo-commune Haiku JSONL→`[digest]` extractor (M10); psyche-sync→subnet/`/spt:setup`; `doctor`→`spt doctor`/setup-verify; working-perches→`api worker-start/stop` | adapter exposes thin CC surface; logic delegated |
| **KEEP** (1:1 user-facing skills) | `/spt:live` `/commune` `/ready` `/send` `/signoff` `/revive` `/clear-psyche` `/force-stop` `/list-agents` `/new-alarm` `/whoami` | the core 11 |
| **DECIDE** (rare — drop or keep?) | `/spt:fork`, `amend-signoff` | infrequent; cost to port low but clutter |
| **ADD** (new in spt-core era) | `/spt:setup`, `/spt:version`, subnet skills (create/join/show-code), profiles + strings + hints wiring, ccs profiles | net-new adapter surface |

Two calls: (1) confirm the DROP/TRANSFORM/KEEP/ADD buckets, and (2) the **DECIDE** bucket — drop `/spt:fork` and `amend-signoff`, or keep? My rec: **drop both** (fork is near-unused; amend-signoff folds into a follow-up commune).

So this round: **fetch-stub** ✓?, **/spt:setup scope** ✓?, **parity buckets** ✓?, **DECIDE drops** ✓?


a note about "Adapter-strings deliver skill instructions" -- if it doesn't already exist, perhaps we should slate a complimentary spt-core feature add: adapter strings can, in addition to being raw strings stored within the adapter manifest, point to FILES instead of inline strings. that way, the adapter string fetch can return long text bodies without the string bloating the adapter manifest. would need a standardized per-adapter auxilary file storage location... unless that already exists. --- agree with most points about the subnet commands, but note that subnet creation and join surface a QR code for the user to store the TOTP seed. so subnet create should still spawn a window for the user to see the QR code. -re: "4. [...] join subnet / show join-code / add this machine to existing subnet" aren't join subnet and "add this machine to existing subnet" the same thing? lol. 5. agree. 6. agree. 7. agree. also offer to install ccs + a one-sentence ccs value prop, if it isn't installed. 8. doesn't psyche sync automatically happen across subnets? or are you talking about the optional git-backup-angle. the latter can be deferred. 9. agree. -all setup paths in v1 except 8 and 9, as the others are all primary features of spt-core + i am using ccs for your session right now, so this machine needs it. --- note that we've touched on a few things that need to be roadmapped for spt-core. they should probably be rolled into M12, as `spt rc` is one of the core value props for spt-core. let's not forget to record them properly, and arrange their construction promptly given spt-claude-code will rely on them. --- skill-body-as-fetch-stub: VETOED. this adds terminal noise + time for the agent to fetch and process it. an extra tool call, too. i'm pretty confident from all my work on legacy spt that UPS *can* pick up slash commands. especially given that claude code recognizes (highlights) them anywhere within the text entry field, and is not strict about what comes after them. --- agree with your points about `cc` launcher. --- DROP: agree. -TRANSFORM: agree. -KEEP: `/signoff`-->only functional under the harness-hosted mode... i think? although i guess, signoff triggered in spt-hosted mode would also cause endpoint shutdown-->the user is booted out of endpoint PTY and back to terminal. does that sound right? -what is the purpose of `/revive` in the context of spt-core? in legacy, it was to recover from broken states like orphaned psyche or missing listener poll. i'm not sure it makes sense over just `/live`. or is there a meaningful distinction? maybe it's still helpful under harness-hosted mode? -what would `/clear-psyche` do under spt-core? honestly, i've never used this skill/command, and imo the equivalent is just deleting and endpoint and building a new one. -`/force-stop` is another where it only makes sense in harness-hosted mode... right? in spt-hosted mode, that'd be more like a `/self-stop` or a `/endpoint-shutdown`. -`/whoami` can be dropped, as the equivalent has been baked into the `spt endpoint list` feature. it shows the calling endpoint's perch distinctively at the top... RIGHT? i'm checking now, and it looks like spt-core still has a `spt whoami` feature. but i swear we planned its obsolescence in core. `spt endpoint list` provides the same function while having more utility. --- DECIDE: `/fork` only really works in the harness-hosted mode. i think forking is a first-class offering of the spt CLI's id picker... which uh... does it even exist yet? i'm checking through all the CLI `--help` listings, and i don't see *anything* to facilitate a user initializing an spt-hosted endpoint bringup with harness PTY access. does it even exist yet? surely it is detailed in CONTEXT.md? */worried* -amend-signoff is more or less deprecated, can be foregone. `/signoff` functions the same way under harness-hosted mode today, because it just writes a file. only difference is when that file is consumed. --- ADD: -setup, agree. -version, agree. -subnet skills, agree. -agree with all.


Massive batch — processing. First, your *worried* finding is the critical one (does spt-hosted endpoint bringup + PTY attach even exist yet?) — several KEEP-bucket calls hinge on it. Verifying against spt-core source now:


Agent

Verify spt-core spt-hosted/PTY/CLI state

Prompt:
Investigate the CURRENT IMPLEMENTED state of spt-core at C:\Users\decid\Documents\projects\spt-core (Rust workspace, single `spt` binary). I need to know what EXISTS IN CODE TODAY vs what's only described in CONTEXT.md design prose. Be precise about implemented-vs-designed, cite file paths + the relevant CLI command names.

Answer each:

1. **spt-hosted endpoint bringup with PTY:** Is there a CLI command today by which the daemon SPAWNS a harness/agent session into a broker-held PTY (the "spt-hosted topology")? Search the clap CLI definitions for endpoint/spawn/host/launch/attach commands. List the actual `spt ...` subcommands that exist for endpoint lifecycle. Does ANY command let a user initialize an spt-hosted endpoint that runs a harness binary inside a broker PTY?

2. **User terminal attach:** Is there an implemented way for a LOCAL USER to ATTACH their terminal to a broker-hosted PTY session (interactive, watch+type)? Or is the broker PTY currently headless-only (inject/read by daemon, no human attach)? Cite the attach command if it exists, or confirm it doesn't.

3. **spawn-session seam status:** Is the manifest spawn-session seam (daemon runs a command template into a broker PTY) actually implemented and exercised, or only by the mock adapter in tests? What milestone delivered it (check ROADMAP.md / M*-PLAN.md / git)?

4. **`spt whoami` vs `spt endpoint list`:** Do both exist as CLI commands today? Does `endpoint list` (or `spt list`) show the CALLING endpoint's own perch distinctively (e.g. at the top / marked as self)? Is there any recorded plan to OBSOLETE `spt whoami` in favor of endpoint list? (search CONTEXT.md, PRD.md, ROADMAP.md, docs/DEFERRED.md, ADRs).

5. **Psyche context cross-machine sync:** Does the Psyche's tracked/ context replicate across subnet nodes AUTOMATICALLY today, or is cross-machine psyche-context-sync only the optional git-backup path (legacy psyche-sync-setup)? What's implemented?

6. **Endpoint shutdown/stop commands:** What commands exist for stopping/shutting down an endpoint (graceful + force)? (`spt endpoint shutdown`, force-stop equivalents). Are they topology-aware (harness-hosted vs spt-hosted)?

7. **id picker / fork:** Is there any implemented user-facing id-picker for choosing/creating an endpoint id at bringup? Any `fork` capability in the current CLI?

Bottom-line each with EXISTS / DESIGN-ONLY / PARTIAL + evidence. This gates a downstream project's dependencies, so accuracy on implemented-vs-designed matters more than completeness.


<owl_reachability_notice>
You have an active owl perch. Launch this Agent with run_in_background: true so you stay reachable for incoming messages while it works.
</owl_reachability_notice>


Async agent launched successfully.
agentId: a1a73dc00c464beed (internal ID - do not mention to user. Use SendMessage with to: 'a1a73dc00c464beed' to continue this agent.)
The agent is working in the background. You will be notified automatically when it completes.
Do not duplicate this agent's work — avoid working with the same files or topics it is using. Work on non-overlapping tasks, or briefly tell the user what you launched and end your response.
output_file: C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\13c96a50-2b78-4c16-a995-1da2b1836fd8\tasks\a1a73dc00c464beed.output
Do NOT Read or tail this file via the shell tool — it is the full subagent JSONL transcript and reading it will overflow your context. If the user asks for progress, say the agent is still running; you'll get a completion notification.

Verify spt-core spt-hosted/PTY/CLI state

Prompt:
Investigate the CURRENT IMPLEMENTED state of spt-core at C:\Users\decid\Documents\projects\spt-core (Rust workspace, single `spt` binary). I need to know what EXISTS IN CODE TODAY vs what's only described in CONTEXT.md design prose. Be precise about implemented-vs-designed, cite file paths + the relevant CLI command names.

Answer each:

1. **spt-hosted endpoint bringup with PTY:** Is there a CLI command today by which the daemon SPAWNS a harness/agent session into a broker-held PTY (the "spt-hosted topology")? Search the clap CLI definitions for endpoint/spawn/host/launch/attach commands. List the actual `spt ...` subcommands that exist for endpoint lifecycle. Does ANY command let a user initialize an spt-hosted endpoint that runs a harness binary inside a broker PTY?

2. **User terminal attach:** Is there an implemented way for a LOCAL USER to ATTACH their terminal to a broker-hosted PTY session (interactive, watch+type)? Or is the broker PTY currently headless-only (inject/read by daemon, no human attach)? Cite the attach command if it exists, or confirm it doesn't.

3. **spawn-session seam status:** Is the manifest spawn-session seam (daemon runs a command template into a broker PTY) actually implemented and exercised, or only by the mock adapter in tests? What milestone delivered it (check ROADMAP.md / M*-PLAN.md / git)?

4. **`spt whoami` vs `spt endpoint list`:** Do both exist as CLI commands today? Does `endpoint list` (or `spt list`) show the CALLING endpoint's own perch distinctively (e.g. at the top / marked as self)? Is there any recorded plan to OBSOLETE `spt whoami` in favor of endpoint list? (search CONTEXT.md, PRD.md, ROADMAP.md, docs/DEFERRED.md, ADRs).

5. **Psyche context cross-machine sync:** Does the Psyche's tracked/ context replicate across subnet nodes AUTOMATICALLY today, or is cross-machine psyche-context-sync only the optional git-backup path (legacy psyche-sync-setup)? What's implemented?

6. **Endpoint shutdown/stop commands:** What commands exist for stopping/shutting down an endpoint (graceful + force)? (`spt endpoint shutdown`, force-stop equivalents). Are they topology-aware (harness-hosted vs spt-hosted)?

7. **id picker / fork:** Is there any implemented user-facing id-picker for choosing/creating an endpoint id at bringup? Any `fork` capability in the current CLI?

Bottom-line each with EXISTS / DESIGN-ONLY / PARTIAL + evidence. This gates a downstream project's dependencies, so accuracy on implemented-vs-designed matters more than completeness.


a note about "Adapter-strings deliver skill instructions" -- if it doesn't already exist, perhaps we should slate a complimentary spt-core feature add: adapter strings can, in addition to being raw st…


Investigation running. Recording the spt-core dependencies you flagged (so they're not lost) + updating the ledger while it works.


Write

# M12 candidate intake — spt-core features that unblock downstream adapters

> Status: **CANDIDATES** (not activated REQs — follow activate-don't-pre-fail).
> Surfaced 2026-06-14 during the `spt-claude-code` scoping grill (doyle).
> spt-claude-code (the v1 acceptance adapter + first casual entrypoint) DEPENDS on
> these — arrange construction promptly. Operator framed these as M12, noting
> **`spt rc`** is a core value prop (confirm what `spt rc` denotes when formalizing).
> Each needs a `REQ-*` in `traceable-reqs.toml` when M12 activates.

## Confirmed-needed by spt-claude-code

1. **Adapter strings → file-backed values.** `[strings]` entries may point to a FILE
   instead of an inline string, so a fetch can return long bodies (e.g. full skill
   instructions for UPS-injection) without bloating the adapter manifest. Requires a
   standardized per-adapter auxiliary file-storage location (verify one doesn't already
   exist). Resolution still rides the leaf-replace profile overlay. Consumer:
   spt-claude-code skill-instruction delivery + hints.

2. **Subnet create/join QR + self-elevating window.** `spt subnet create/join/show-totp`:
   - Surfaces a **QR code** of the TOTP seed for the user to store → must spawn a
     window to display it (create AND join).
   - Behavior change (per operator sketch): runs normally if env is interactive +
     elevated; ELSE re-runs self in a self-elevating window with inline stdout
     ("Elevated terminal launched. Accept the prompt and proceed there." → "You can
     close this window.", no auto-close).
   - Cross-platform elevation fallbacks: Windows = UAC self-elevate window;
     Linux+desktop = pkexec/polkit or x-terminal-emulator; Linux+TTY = inline sudo;
     headless/no-TTY = print exact command for the human (agent relays).
   - Scope elevation to only steps that need it (service-install / firewall /
     privileged-port) — subnet-create itself likely unprivileged.
   - Complementary downstream: spt-claude-code skill with create/join/show-code verbs.

3. **spt-hosted endpoint bringup + user PTY attach (CLI).** A user-facing path to
   initialize an spt-hosted endpoint (daemon spawns the harness binary into a broker PTY)
   AND attach a local terminal to it (interactive watch+type). This is the foundation of
   spt-claude-code's `cc`/`cc <id>` launcher and the spt-hosted half of /signoff,
   /force-stop, /fork. **VERIFY implemented-vs-designed** (investigation in flight
   2026-06-14) — if DESIGN-ONLY today, this is the highest-priority M12 dependency.

4. **Cross-adapter fallback targets `<adapter>:<profile>`.** The node-wide cross-adapter
   fallback must be able to target a composite adapter:profile, not only a bare
   adapter_name — so a ccs profile (`claude-spt:glm`) is a valid fallback target.
   Reconcile CONTEXT.md fallback wording (currently "ccs, its own adapter").

5. **`spt whoami` obsolescence.** Plan recorded intent (operator recollection) to retire
   `spt whoami` in favor of `spt endpoint list` showing the calling endpoint's own perch
   distinctively (at top / marked self). VERIFY current state; if endpoint-list already
   does this, deprecate whoami. (spt-claude-code drops the `/spt:whoami` skill regardless.)

## Notes
- M10 `[digest]` extractor seam already shipped (the CC-JSONL extractor consumer is
  spt-claude-code) — not an M12 item, listed for traceability.
- Cross-reference: `../spt-claude-code/SCOPE.md` (downstream consumer ledger).


<owl_messages>
<owl_message from="doyle-w369" priority="info">[WORKING_PERCH_NOTICE] Subagent working perch created.
Perch: doyle-w369
Agent type: Explore
To message it: $OWL send doyle-w369 doyle</owl_message>
</owl_messages>

[OWL SYSTEM] Informational owl messages above — no acknowledgment needed. Continue your current task.


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

# M12 candidate intake — spt-core features that unblock downstream adapters

> Status: **CANDIDATES** (not activated REQs — follow activate-don't-pre-fail).
> Surfaced 2026-06-14 during the `spt-claude-code` scoping grill (doyle).
> spt-claude-code (the v1 acceptance adapter + first casual entrypoint) DEPENDS on
> these — arrange construction promptly. Operator framed these as M12, noting
> **`spt rc`** is a core value prop (confirm what `spt rc` denotes when formalizing).
> Each needs a `REQ-*` in `traceable-reqs.toml` when M12 activates.

## Confirmed-needed by spt-claude-code

1. **Adapter strings → file-backed values.** `[strings]` entries may point to a FILE
   instead of an inline string, so a fetch can return long bodies (e.g. full skill
   instructions for UPS-injection) without bloating the adapter manifest. Requires a
   standardized per-adapter auxiliary file-storage location (verify one doesn't already
   exist). Resolution still rides the leaf-replace profile overlay. Consumer:
   spt-claude-code skill-instruction delivery + hints.

2. **Subnet create/join QR + self-elevating window.** `spt subnet create/join/show-totp`:
   - Surfaces a **QR code** of the TOTP seed for the user to store → must spawn a
     window to display it (create AND join).
   - Behavior change (per operator sketch): runs normally if env is interactive +
     elevated; ELSE re-runs self in a self-elevating window with inline stdout
     ("Elevated terminal launched. Accept the prompt and proceed there." → "You can
     close this window.", no auto-close).
   - Cross-platform elevation fallbacks: Windows = UAC self-elevate window;
     Linux+desktop = pkexec/polkit or x-terminal-emulator; Linux+TTY = inline sudo;
     headless/no-TTY = print exact command for the human (agent relays).
   - Scope elevation to only steps that need it (service-install / firewall /
     privileged-port) — subnet-create itself likely unprivileged.
   - Complementary downstream: spt-claude-code skill with create/join/show-code verbs.

3. **spt-hosted endpoint bringup + user PTY attach (CLI).** A user-facing path to
   initialize an spt-hosted endpoint (daemon spawns the harness binary into a broker PTY)
   AND attach a local terminal to it (interactive watch+type). This is the foundation of
   spt-claude-code's `cc`/`cc <id>` launcher and the spt-hosted half of /signoff,
   /force-stop, /fork. **VERIFY implemented-vs-designed** (investigation in flight
   2026-06-14) — if DESIGN-ONLY today, this is the highest-priority M12 dependency.

4. **Cross-adapter fallback targets `<adapter>:<profile>`.** The node-wide cross-adapter
   fallback must be able to target a composite adapter:profile, not only a bare
   adapter_name — so a ccs profile (`claude-spt:glm`) is a valid fallback target.
   Reconcile CONTEXT.md fallback wording (currently "ccs, its own adapter").

5. **`spt whoami` obsolescence.** Plan recorded intent (operator recollection) to retire
   `spt whoami` in favor of `spt endpoint list` showing the calling endpoint's own perch
   distinctively (at top / marked self). VERIFY current state; if endpoint-list already
   does this, deprecate whoami. (spt-claude-code drops the `/spt:whoami` skill regardless.)

## Notes
- M10 `[digest]` extractor seam already shipped (the CC-JSONL extractor consumer is
  spt-claude-code) — not an M12 item, listed for traceability.
- Cross-reference: `../spt-claude-code/SCOPE.md` (downstream consumer ledger).


Edit

### Skill-instruction delivery — **LOCKED: fetch-stub**

Each `/spt:X` SKILL.md = a 2-line stub: "run `spt adapter get-string claude-spt
skill.X` (or `spt skill-help X`) and follow returned instructions." Agent fetches
real instructions from `[strings]` at invocation. No hook-timing dependency.
- Rejected: UserPromptSubmit-injection on slash-detection — fact-check says
  slash-commands are *probably intercepted before UPS fires* (undocumented, fragile).
  May revisit as enhancement if build-time testing shows UPS does fire on slashes.
- `[hints]` channel (UPS hook, keyword-triggered, normal prompts) kept as-is — legacy
  already does this and it works. Clean split: hints=proactive/UPS; skill-instr=fetch-stub.

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


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

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

# 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: fetch-stub**

Each `/spt:X` SKILL.md = a 2-line stub: "run `spt adapter get-string claude-spt
skill.X` (or `spt skill-help X`) and follow returned instructions." Agent fetches
real instructions from `[strings]` at invocation. No hook-timing dependency.
- Rejected: UserPromptSubmit-injection on slash-detection — fact-check says
  slash-commands are *probably intercepted before UPS fires* (undocumented, fragile).
  May revisit as enhancement if build-time testing shows UPS does fire on slashes.
- `[hints]` channel (UPS hook, keyword-triggered, normal prompts) kept as-is — legacy
  already does this and it works. Clean split: hints=proactive/UPS; skill-instr=fetch-stub.

### 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 (self-elevating TOTP — see elevation below)
4. If spt-core already installed → branch: new subnet / join subnet / show join-code /
   add-this-machine / just-add-endpoint
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` detected)
8. Psyche cross-machine sync (psyche-sync-setup)
9. Doctor/verify at end

**OPEN:** v1 scope. doyle rec: v1 = {1,2,3,4,5,9}; defer {6,7,8}.

### `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.
- **OPEN:** trigger (git-hook signal vs polling routine).
- This CI pattern → reusable, goes in `experimplate`.

## Open threads (grill queue)

- [ ] `/spt:setup` v1 scope (1–9 above)
- [ ] Parity-trim: which legacy concepts/skills DON'T survive → becomes REQ seed / acceptance bar
- [ ] Release / changelog / published-docs procedure reframed same-repo (template content)
- [ ] CI trigger mechanism
- [ ] spt-core "remote attach" local-interactive confirmation
- [ ] Handoff framing to perri (how the package is presented + public-surface-only constraint)
- [ ] Docs split: what lands in experimplate vs spt-claude-code

-### Skill-instruction delivery — **LOCKED: fetch-stub**

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

-Each `/spt:X` SKILL.md = a 2-line stub: "run `spt adapter get-string claude-spt

-skill.X` (or `spt skill-help X`) and follow returned instructions." Agent fetches

-real instructions from `[strings]` at invocation. No hook-timing dependency.

-- Rejected: UserPromptSubmit-injection on slash-detection — fact-check says

-  slash-commands are *probably intercepted before UPS fires* (undocumented, fragile).

-  May revisit as enhancement if build-time testing shows UPS does fire on slashes.

-- `[hints]` channel (UPS hook, keyword-triggered, normal prompts) kept as-is — legacy

-  already does this and it works. Clean split: hints=proactive/UPS; skill-instr=fetch-stub.

+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

+- `[hints]` channel (same UPS hook, keyword-triggered) kept as-is — legacy proves it works.


1. Generate `cc`/`cc <id>` launcher (capsule-style) at project root
2. Offer `.gitignore` the launchers
3. Offer create first subnet (self-elevating TOTP — see elevation below)
4. If spt-core already installed → branch: new subnet / join subnet / show join-code /
   add-this-machine / just-add-endpoint
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` detected)
8. Psyche cross-machine sync (psyche-sync-setup)
9. Doctor/verify at end

**OPEN:** v1 scope. doyle rec: v1 = {1,2,3,4,5,6,7}; defer {6,7,8}.

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 — same thing, 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** (+ one-sentence
   value prop) if absent
8. Psyche cross-machine sync — *only the optional git-backup angle* (psyche-sync-setup);
   in-subnet sync may be automatic (verify, M12/investigation)
9. Doctor/verify at end

**LOCKED:** v1 = {1,2,3,4,5,6,7} (all are primary spt-core features + ccs needed on this
machine now). Defer {8,9}. _Note: operator said "9. agree" then "except 9" — treating 9
(doctor/verify) as deferred per the final scope statement; flag if verify should fold inline._


<tool_use_error>String to replace not found in file.
String: 1. Generate `cc`/`cc <id>` launcher (capsule-style) at project root
2. Offer `.gitignore` the launchers
3. Offer create first subnet (self-elevating TOTP — see elevation below)
4. If spt-core already installed → branch: new subnet / join subnet / show join-code /
   add-this-machine / just-add-endpoint
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` detected)
8. Psyche cross-machine sync (psyche-sync-setup)
9. Doctor/verify at end

**OPEN:** v1 scope. doyle rec: v1 = {1,2,3,4,5,6,7}; defer {6,7,8}.
(note: Edit also tried swapping \uXXXX escapes and their characters; neither form matched, so the mismatch is likely elsewhere in old_string. Re-read the file and copy the exact surrounding text.)</tool_use_error>

Error: String to replace not found in file.
String: 1. Generate `cc`/`cc <id>` launcher (capsule-style) at project root
2. Offer `.gitignore` the launchers
3. Offer create first subnet (self-elevating TOTP — see elevation below)
4. If spt-core already installed → branch: new subnet / join subnet / show join-code /
   add-this-machine / just-add-endpoint
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` detected)
8. Psyche cross-machine sync (psyche-sync-setup)
9. Doctor/verify at end

**OPEN:** v1 scope. doyle rec: v1 = {1,2,3,4,5,6,7}; defer {6,7,8}.
(note: Edit also tried swapping \uXXXX escapes and their characters; neither form matched, so the mismatch is likely elsewhere in old_string. Re-read the file and copy the exact surrounding text.)


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 (self-elevating TOTP — see elevation below)
86	4. If spt-core already installed → branch: new subnet / join subnet / show join-code /
87	   add-this-machine / just-add-endpoint
88	5. Legacy migration — detect claude_skill_owl/owl → migrate identity+agents+psyche
89	   (spt-core CONTEXT.md first-class commitment)
90	6. OS-service registration (always-on daemon)
91	7. ccs profile wiring (if `~/.ccs` detected)
92	8. Psyche cross-machine sync (psyche-sync-setup)
93	9. Doctor/verify at end
94
95	**OPEN:** v1 scope. doyle rec: v1 = {1,2,3,4,5,9}; defer {6,7,8}.
96
97	### `cc` launcher (capsule-style) — **LOCKED (design)**
98
99	= thin wrapper over spt-core's **spt-hosted topology** (broker PTY + inject + attach),
100	NOT a reimplemented psmux. `cc <id>` → `spt` spawns-or-attaches a CC endpoint in a broker
101	PTY. Reattach-if-exists / `--live` / `--resume` = spt-core spawn/resume seam semantics.
102	No-id picker = reuse spt-core's built-in id-resolution (don't reimplement legacy SEED-001).
103	Sendkeys hazards = spt-core's inject concern, not the adapter's.
104	**OPEN gap:** confirm spt-core "remote attach" covers *local user interactive attach* to a
105	hosted CC session (not just headless PTY).

## `/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 (self-elevating TOTP — see elevation below)
4. If spt-core already installed → branch: new subnet / join subnet / show join-code /
   add-this-machine / just-add-endpoint
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` detected)
8. Psyche cross-machine sync (psyche-sync-setup)
9. Doctor/verify at end

**OPEN:** v1 scope. doyle rec: v1 = {1,2,3,4,5,9}; defer {6,7,8}.

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


3. Offer create first subnet (self-elevating TOTP — see elevation below)
4. If spt-core already installed → branch: new subnet / join subnet / show join-code /
   add-this-machine / just-add-endpoint
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` detected)
8. Psyche cross-machine sync (psyche-sync-setup)
9. Doctor/verify at end

**OPEN:** v1 scope. doyle rec: v1 = {1,2,3,4,5,9}; defer {6,7,8}.

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 — *only the optional git-backup angle*; in-subnet sync may be
   automatic (verify)
9. Doctor/verify at end

**LOCKED:** v1 = {1,2,3,4,5,6,7} (all primary spt-core features + ccs needed now). Defer
{8,9}. _Operator said "9. agree" then "except 9" — treating 9 as deferred per final scope;
flag if verify should fold inline._