1	# SPT
2
3	## What is SPT?
4
5	A communication ecosystem for all of your computers. Interact with _any resource_, on _any machine_, **from** any machine, using any interface. Empower your LLMs to do the same.
6
7	`spt-core` is the heart of a harness-independent framework. It offers: inter-agent messaging, live agent lifecycle, terminal hosting, seamless self-update, and zero-config cross-machine networking — shipped as both a Rust library workspace and a single canonical binary (`spt` / `spt.exe`).
8
9	SPT lets coding agents talk to each other — across sessions, across projects, and across machines — without a central server. An agent running under one harness can message an agent under another, keep a persistent identity and memory across context resets, and be reached (or revived) from any paired machine. Three pieces make that up:
10	- **(a)** the `spt` binary, the per-machine core that does the work — messaging, lifecycle, terminal hosting, P2P networking — and is what this repository distributes.
11	- **(b)** *harness adapters*, thin declarative manifests that teach spt-core how to drive a specific agent harness. An adapter for Claude Code is in development; harnesses like Codex and Pi — the [pi coding agent](https://github.com/badlogic/pi-mono) — are the kind of target the contract is designed for.
12	- **(c)** *shells*, bridge applications to any resource or service that an agent can drive and be driven through. The adapter contract is public, documented, and royalty-free to build against — today's surface for third parties is the binary plus that contract.
13
14	## Status
15
16	| Capability | State |
17	|---|---|
18	| Inter-agent messaging (send / ring / ready / poll), same-machine and cross-machine | ✅ works today |
19	| Live-agent lifecycle (persistent identity, context communes, dormancy/wake) | ✅ works today |
20	| Terminal hosting + remote attach (drive a session on another node) | ✅ works today |
21	| Zero-config P2P networking (QUIC) + TOTP-seeded machine pairing, private subnets | ✅ works today |
22	| Harness contract: manifest + `spt api` (build your own adapter) | ✅ works today |
23	| Shell adapters (e.g. desktop-notification shell) + `spt adapter add` | ✅ works today |
24	| Signed, peer-propagated self-update | ✅ works today |
25	| Claude Code harness adapter (`spt-claude-code`) | 🚧 in development |
26	| OS-service registration at install (always-on after reboot) | 🔜 next |
27	| macOS builds | 🔜 next |
28	| SDK crates on crates.io | 🔜 later |
29
30	Platforms today: **Windows + Linux**.
31
32	## Install
33
34	One line, non-interactive. Downloads the latest release, sha256-verifies it, places the binary, and registers it on your user PATH.
35
36	**Linux:**
37
38	```sh
39	curl -fsSL https://sabermage.github.io/spt-releases/install.sh | sh
40	```
41
42	**Windows (PowerShell):**
43
44	```powershell
45	irm https://sabermage.github.io/spt-releases/install.ps1 | iex
46	```
47
48	Then verify:
49
50	```
51	spt --version
52	```
53
54	> **Windows note:** the PATH registration takes effect in *new* terminals. The installer prints the absolute path to the binary so you can use it immediately in the current one.
55
56	## Getting started — developers
57
58	Two agents exchanging a message, end to end, in under 10 minutes:
59
60	- **[Human quickstart](https://sabermage.github.io/spt-releases/quickstart/messaging.html)** — install, `spt ready` two agents, send and poll a message, then see what actually happened.
61
62	## Getting started — adapter developers & dev-agents
63
64	Build a working harness or shell adapter from the published contract alone:
65
66	- **[Adapter quickstart](https://sabermage.github.io/spt-releases/quickstart/adapter.html)** — a minimal adapter that satisfies the manifest + `spt api` contract, walked through via the `mock-adapter` reference (source ships with every release).
67	- **[Manifest JSON Schema](https://sabermage.github.io/spt-releases/manifest.schema.json)** — validate your adapter manifest mechanically.
68
69	## Documentation
70
71	- **Docs site:** <https://sabermage.github.io/spt-releases> — mental model, quickstarts, the complete harness-contract reference, CLI reference, rustdoc.
72	- **For AI agents:** [`llms.txt`](https://sabermage.github.io/spt-releases/llms.txt) (curated index) and [`llms-full.txt`](https://sabermage.github.io/spt-releases/llms-full.txt) (full export). Append `.md` to any doc URL for raw markdown.
73
74	## License
75
76	Split by artifact:
77
78	- **Install scripts, `mock-adapter`, and documentation content** — [MIT](./LICENSE-MIT). Copy them; that's what they're for.
79	- **The `spt` binary** — a short [proprietary freeware license](./LICENSE-BINARY): free to run and redistribute unmodified, no warranty. Building adapters, shells, or integrations against the public contract is explicitly **unrestricted and royalty-free**.
80

# SPT

## What is SPT?

A communication ecosystem for all of your computers. Interact with _any resource_, on _any machine_, **from** any machine, using any interface. Empower your LLMs to do the same.

`spt-core` is the heart of a harness-independent framework. It offers: inter-agent messaging, live agent lifecycle, terminal hosting, seamless self-update, and zero-config cross-machine networking — shipped as both a Rust library workspace and a single canonical binary (`spt` / `spt.exe`).

SPT lets coding agents talk to each other — across sessions, across projects, and across machines — without a central server. An agent running under one harness can message an agent under another, keep a persistent identity and memory across context resets, and be reached (or revived) from any paired machine. Three pieces make that up:
- **(a)** the `spt` binary, the per-machine core that does the work — messaging, lifecycle, terminal hosting, P2P networking — and is what this repository distributes.
- **(b)** *harness adapters*, thin declarative manifests that teach spt-core how to drive a specific agent harness. An adapter for Claude Code is in development; harnesses like Codex and Pi — the [pi coding agent](https://github.com/badlogic/pi-mono) — are the kind of target the contract is designed for.
- **(c)** *shells*, bridge applications to any resource or service that an agent can drive and be driven through. The adapter contract is public, documented, and royalty-free to build against — today's surface for third parties is the binary plus that contract.

## Status

| Capability | State |
|---|---|
| Inter-agent messaging (send / ring / ready / poll), same-machine and cross-machine | ✅ works today |
| Live-agent lifecycle (persistent identity, context communes, dormancy/wake) | ✅ works today |
| Terminal hosting + remote attach (drive a session on another node) | ✅ works today |
| Zero-config P2P networking (QUIC) + TOTP-seeded machine pairing, private subnets | ✅ works today |
| Harness contract: manifest + `spt api` (build your own adapter) | ✅ works today |
| Shell adapters (e.g. desktop-notification shell) + `spt adapter add` | ✅ works today |
| Signed, peer-propagated self-update | ✅ works today |
| Claude Code harness adapter (`spt-claude-code`) | 🚧 in development |
| OS-service registration at install (always-on after reboot) | 🔜 next |
| macOS builds | 🔜 next |
| SDK crates on crates.io | 🔜 later |

Platforms today: **Windows + Linux**.

## Install

One line, non-interactive. Downloads the latest release, sha256-verifies it, places the binary, and registers it on your user PATH.

**Linux:**

```sh
curl -fsSL https://sabermage.github.io/spt-releases/install.sh | sh
```

**Windows (PowerShell):**

```powershell
irm https://sabermage.github.io/spt-releases/install.ps1 | iex
```

Then verify:

```
spt --version
```

> **Windows note:** the PATH registration takes effect in *new* terminals. The installer prints the absolute path to the binary so you can use it immediately in the current one.

## Getting started — developers

Two agents exchanging a message, end to end, in under 10 minutes:

- **[Human quickstart](https://sabermage.github.io/spt-releases/quickstart/messaging.html)** — install, `spt ready` two agents, send and poll a message, then see what actually happened.

## Getting started — adapter developers & dev-agents

Build a working harness or shell adapter from the published contract alone:

- **[Adapter quickstart](https://sabermage.github.io/spt-releases/quickstart/adapter.html)** — a minimal adapter that satisfies the manifest + `spt api` contract, walked through via the `mock-adapter` reference (source ships with every release).
- **[Manifest JSON Schema](https://sabermage.github.io/spt-releases/manifest.schema.json)** — validate your adapter manifest mechanically.

## Documentation

- **Docs site:** <https://sabermage.github.io/spt-releases> — mental model, quickstarts, the complete harness-contract reference, CLI reference, rustdoc.
- **For AI agents:** [`llms.txt`](https://sabermage.github.io/spt-releases/llms.txt) (curated index) and [`llms-full.txt`](https://sabermage.github.io/spt-releases/llms-full.txt) (full export). Append `.md` to any doc URL for raw markdown.

## License

Split by artifact:

- **Install scripts, `mock-adapter`, and documentation content** — [MIT](./LICENSE-MIT). Copy them; that's what they're for.
- **The `spt` binary** — a short [proprietary freeware license](./LICENSE-BINARY): free to run and redistribute unmodified, no warranty. Building adapters, shells, or integrations against the public contract is explicitly **unrestricted and royalty-free**.


Bash

cd 'C:\Users\decid\Documents\projects\spt-claude-code'; find .claude -type f 2>&1 | head -50

List spt-claude-code .claude contents


.claude/LIVE_AGENT_IDS.json
Shell cwd was reset to C:\Users\decid\Documents\projects\spt-core


1	# traceable-reqs manifest for spt-core — SEED.
2	#
3	# Authoritative requirement registry: every PRD R-* requirement and every
4	# KNOWN-HAZARDS invariant lives here as a REQ-* id (see docs/TRACEABILITY.md
5	# for the development contract).
6	#
7	# ACTIVATION MODEL: every requirement starts inactive (`required_stages = []`)
8	# so `check` stays green pre-code. A milestone (M0-M5) ACTIVATES its requirements
9	# by setting their real `required_stages`. Validate this seed against the
10	# installed CLI at M0 (the binary isn't installed yet).
11
12	[scan]
13	# CONTEXT.md is a file root: the glossary is authoritative for meaning and
14	# carries doc-stage tags (e.g. §Installation). installer/ added M6-D2.
15	roots = ["src", "tests", "docs", "crates", "installer", "CONTEXT.md", "docs-site", ".github"]
16
17	[policy]
18	# Default policy applied at activation: doc + impl + unit. Networking/lifecycle
19	# reqs add "int". Until a req is activated, its per-req `required_stages = []`
20	# keeps it out of the coverage gate.
21	required_stages = []
22
23	# ───────────────────────────── Architecture / workspace ─────────────────────
24	[[requirements]]
25	id = "REQ-ARCH-1"
26	title = "Many small acyclically-layered crates"
27	required_stages = ["impl"]  # activated M0: spt-proto<-spt-store one-way layering (T14). impl-only: architecture is build-evidenced (cargo rejects cycles); grows as crates are added M1+.
28	[[requirements]]
29	id = "REQ-ARCH-2"
30	title = "Public SDK surface is spt-proto, spt-runtime, spt-msg"
31	required_stages = ["impl"]
32	[[requirements]]
33	id = "REQ-ARCH-3"
34	title = "Wire-protocol version independent of crate semver, N-1 compat window"
35	required_stages = ["impl", "unit"]  # activated M0: spt-proto wire version + compat window (T6)
36	[[requirements]]
37	id = "REQ-ARCH-4"
38	title = "Copy-verbatim the commodity layer from the sister project"
39	required_stages = ["impl", "unit"]  # activated M0: spt-proto EVENT grammar (T2)
40
41	# ───────────────────────────── Daemon ───────────────────────────────────────
42	[[requirements]]
43	id = "REQ-DAEMON-1"
44	title = "One per-machine spt-daemon owning all per-machine state"
45	required_stages = ["impl", "unit", "int"]  # int activated M3b-B9: the daemon E2E (spawn→Psyche-loop→commune→brain-restart-survives→graceful-signoff) drives the consolidated daemon-hosted lifecycle through the real IPC
46	[[requirements]]
47	id = "REQ-DAEMON-2"
48	title = "Broker/brain split for seamless self-update"
49	required_stages = ["impl", "unit", "int"]  # int RE-POINTED at restoration D7-1 (ADR-0018 V5) to the PROCESS-level survival E2E (crates/spt/tests/brain_survive.rs: broker/brain split delivers the seamless update at the process level — a brain-PROCESS restart onto a swapped binary, PTY child + QUIC conn held). Was M3b-B9 daemon_e2e + handoff.rs (the in-process handoff shape — regression-masked per ADR-0018); those tags removed in the same D7-1 commit. The net-ownership facet (netbroker.rs) stays distinct evidence
50	[[requirements]]
51	id = "REQ-DAEMON-3"
52	title = "Any api invocation auto-starts the daemon if absent"
53	required_stages = ["impl", "unit", "int"]
54	[[requirements]]
55	id = "REQ-DAEMON-4"
56	title = "Honor every KNOWN-HAZARDS invariant"
57	required_stages = ["impl", "unit", "int"]  # int activated M3b-B9: the daemon E2E proves graceful signoff runs the echo-before-teardown ordering (3.3) and removes the Self's ready marker in the consolidated daemon
58
59	# ───────────────────────────── Storage ──────────────────────────────────────
60	# git-KV BranchStore substrate (ADR-0011, 2026-06-02; implement M4, optional M3c)

# traceable-reqs manifest for spt-core — SEED.
#
# Authoritative requirement registry: every PRD R-* requirement and every
# KNOWN-HAZARDS invariant lives here as a REQ-* id (see docs/TRACEABILITY.md
# for the development contract).
#
# ACTIVATION MODEL: every requirement starts inactive (`required_stages = []`)
# so `check` stays green pre-code. A milestone (M0-M5) ACTIVATES its requirements
# by setting their real `required_stages`. Validate this seed against the
# installed CLI at M0 (the binary isn't installed yet).

[scan]
# CONTEXT.md is a file root: the glossary is authoritative for meaning and
# carries doc-stage tags (e.g. §Installation). installer/ added M6-D2.
roots = ["src", "tests", "docs", "crates", "installer", "CONTEXT.md", "docs-site", ".github"]

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

# ───────────────────────────── Architecture / workspace ─────────────────────
[[requirements]]
id = "REQ-ARCH-1"
title = "Many small acyclically-layered crates"
required_stages = ["impl"]  # activated M0: spt-proto<-spt-store one-way layering (T14). impl-only: architecture is build-evidenced (cargo rejects cycles); grows as crates are added M1+.
[[requirements]]
id = "REQ-ARCH-2"
title = "Public SDK surface is spt-proto, spt-runtime, spt-msg"
required_stages = ["impl"]
[[requirements]]
id = "REQ-ARCH-3"
title = "Wire-protocol version independent of crate semver, N-1 compat window"
required_stages = ["impl", "unit"]  # activated M0: spt-proto wire version + compat window (T6)
[[requirements]]
id = "REQ-ARCH-4"
title = "Copy-verbatim the commodity layer from the sister project"
required_stages = ["impl", "unit"]  # activated M0: spt-proto EVENT grammar (T2)

# ───────────────────────────── Daemon ───────────────────────────────────────
[[requirements]]
id = "REQ-DAEMON-1"
title = "One per-machine spt-daemon owning all per-machine state"
required_stages = ["impl", "unit", "int"]  # int activated M3b-B9: the daemon E2E (spawn→Psyche-loop→commune→brain-restart-survives→graceful-signoff) drives the consolidated daemon-hosted lifecycle through the real IPC
[[requirements]]
id = "REQ-DAEMON-2"
title = "Broker/brain split for seamless self-update"
required_stages = ["impl", "unit", "int"]  # int RE-POINTED at restoration D7-1 (ADR-0018 V5) to the PROCESS-level survival E2E (crates/spt/tests/brain_survive.rs: broker/brain split delivers the seamless update at the process level — a brain-PROCESS restart onto a swapped binary, PTY child + QUIC conn held). Was M3b-B9 daemon_e2e + handoff.rs (the in-process handoff shape — regression-masked per ADR-0018); those tags removed in the same D7-1 commit. The net-ownership facet (netbroker.rs) stays distinct evidence
[[requirements]]
id = "REQ-DAEMON-3"
title = "Any api invocation auto-starts the daemon if absent"
required_stages = ["impl", "unit", "int"]
[[requirements]]
id = "REQ-DAEMON-4"
title = "Honor every KNOWN-HAZARDS invariant"
required_stages = ["impl", "unit", "int"]  # int activated M3b-B9: the daemon E2E proves graceful signoff runs the echo-before-teardown ordering (3.3) and removes the Self's ready marker in the consolidated daemon

# ───────────────────────────── Storage ──────────────────────────────────────
# git-KV BranchStore substrate (ADR-0011, 2026-06-02; implement M4, optional M3c)


/grill-with-docs over `spt-claude-code`. what do we hand off to perri to set them up for success, and how do we frame it? -the docs that come of this session should be mostly recorded in sibling proje…


Picture clear. Let me ground "what an adapter is" concretely before grilling.


cd 'C:\Users\decid\Documents\projects\spt-core'; echo "===adapters/==="; find adapters -maxdepth 2 -type f 2>&1 | head -40; echo "===any CC adapter refs in source==="; grep -rl "claude_skill_owl\|claude-code\|claude_code" --include=*.md . 2>/dev/null | head

Inspect adapters dir + CC references


===adapters/===
adapters/mock/Cargo.toml
adapters/mock/manifest.toml
adapters/mock-gateway/manifest.toml
===any CC adapter refs in source===
./AGENTS.md
./CLAUDE.md
./CONTEXT.md
./DIGEST-MILESTONE-PLAN.md
./docs/adr/0001-clean-room-fork-from-claude-skill-owl.md
./docs/adr/0002-bake-networking-into-core-collapse-spt-node.md
./docs/adr/0012-psyche-trust-boundary-stdout-event-outbound.md
./docs/adr/0018-broker-brain-process-isolation-restoration.md
./docs/BROKER-BRAIN-SPLIT-RESTORATION.md
./docs/DEFERRED.md


<system-reminder>This memory is 9 days old. Memories are point-in-time observations, not live state — claims about code behavior or file:line citations may be outdated. Verify against current code before asserting as fact.</system-reminder>
1	---
2	name: adapter-glue-model-boundary
3	description: "Adapters (harness AND shell) interface with spt-core via manifest + binary ONLY — never add adapter-aware source to spt-core, never place real adapters in-tree"
4	metadata:
5	  node_type: memory
6	  type: feedback
7	  originSessionId: 82459163-f234-40c3-8afa-90e074af5065
8	---
9
10	User stopped D8 work (2026-06-04) when I (a) placed the real notify shell adapter in-tree and (b) hardcoded its "notify" capability name in the daemon. Both reverted same day: adapter moved to standalone SaberMage/spt-shell-notify (public, self-contained, hand-decoded wire format); daemon-side render became the [session.notif] manifest template seam generalized to shell adapters (vocabulary-agnostic).
11
12	**Why:** The adapter model's entire point is zero source integration — the manifest declares everything, the binary speaks only the public `spt api` surface + documented wire format. The mock stays the only adapter-shaped artifact in-tree (PRD R-DOCS-2). spt-core knowing a shell vocabulary verb = a privileged capability baked into core = the model broken.
13
14	**How to apply:** Before any adapter-touching work: real adapters get their own repo (spt-core CI may add a thin cross-repo hook for E2E); any daemon-side behavior keyed to an adapter must be driven by a manifest declaration spt-core honors generically, never by a name/verb spt-core knows. When a plan says "via the template/manifest", build the manifest seam — don't drift to whatever machinery is freshest in context.
15

---
name: adapter-glue-model-boundary
description: "Adapters (harness AND shell) interface with spt-core via manifest + binary ONLY — never add adapter-aware source to spt-core, never place real adapters in-tree"
metadata:
  node_type: memory
  type: feedback
  originSessionId: 82459163-f234-40c3-8afa-90e074af5065
---

User stopped D8 work (2026-06-04) when I (a) placed the real notify shell adapter in-tree and (b) hardcoded its "notify" capability name in the daemon. Both reverted same day: adapter moved to standalone SaberMage/spt-shell-notify (public, self-contained, hand-decoded wire format); daemon-side render became the [session.notif] manifest template seam generalized to shell adapters (vocabulary-agnostic).

**Why:** The adapter model's entire point is zero source integration — the manifest declares everything, the binary speaks only the public `spt api` surface + documented wire format. The mock stays the only adapter-shaped artifact in-tree (PRD R-DOCS-2). spt-core knowing a shell vocabulary verb = a privileged capability baked into core = the model broken.

**How to apply:** Before any adapter-touching work: real adapters get their own repo (spt-core CI may add a thin cross-repo hook for E2E); any daemon-side behavior keyed to an adapter must be driven by a manifest declaration spt-core honors generically, never by a name/verb spt-core knows. When a plan says "via the template/manifest", build the manifest seam — don't drift to whatever machinery is freshest in context.


1	---
2	name: spt-claude-code-next
3	description: "NEXT-SESSION task — scope a general spt-claude-code project plan, hand to new maintainer \"perri\"; built from spt-releases + GH Pages docs ONLY"
4	metadata:
5	  node_type: memory
6	  type: project
7	  originSessionId: fe10844f-7c10-4582-b8e9-44b7aedcc7f7
8	---
9
10	**Next-session work (operator directive 2026-06-13):** scope out a general **`spt-claude-code`** project plan, then hand it off to its maintainer — a new agent **"perri"**.
11
12	**Framing / hard constraints:**
13	- `spt-claude-code` is **WHOLLY SEPARATE** from `spt-core` — its own project/repo, treated independently. Not an spt-core deliverable (adapters are downstream — see [[adapter-glue-model-boundary]]).
14	- **perri builds it using ONLY `SaberMage/spt-releases` + the corresponding GH Pages docs.** NOT the spt-core source repo. perri is an external consumer of the published release artifacts + docs — proving the adapter contract is buildable from the public surface alone.
15	- `spt-claude-code` = the first REAL Claude Code harness adapter (spt-core's v1 acceptance / feature-parity proof). Enablers: M9 (profiles/strings/hints/digest log-source) + M10 (digest extractor seam — see [[m10-digest-extractor]]).
16
17	**On resume:** start the scoping in a SEPARATE working context (its own project tree, NOT the spt-core repo), produce a general project plan, hand to perri with the spt-releases-and-docs-only constraint stated up front.
18

---
name: spt-claude-code-next
description: "NEXT-SESSION task — scope a general spt-claude-code project plan, hand to new maintainer \"perri\"; built from spt-releases + GH Pages docs ONLY"
metadata:
  node_type: memory
  type: project
  originSessionId: fe10844f-7c10-4582-b8e9-44b7aedcc7f7
---

**Next-session work (operator directive 2026-06-13):** scope out a general **`spt-claude-code`** project plan, then hand it off to its maintainer — a new agent **"perri"**.

**Framing / hard constraints:**
- `spt-claude-code` is **WHOLLY SEPARATE** from `spt-core` — its own project/repo, treated independently. Not an spt-core deliverable (adapters are downstream — see [[adapter-glue-model-boundary]]).
- **perri builds it using ONLY `SaberMage/spt-releases` + the corresponding GH Pages docs.** NOT the spt-core source repo. perri is an external consumer of the published release artifacts + docs — proving the adapter contract is buildable from the public surface alone.
- `spt-claude-code` = the first REAL Claude Code harness adapter (spt-core's v1 acceptance / feature-parity proof). Enablers: M9 (profiles/strings/hints/digest log-source) + M10 (digest extractor seam — see [[m10-digest-extractor]]).

**On resume:** start the scoping in a SEPARATE working context (its own project tree, NOT the spt-core repo), produce a general project plan, hand to perri with the spt-releases-and-docs-only constraint stated up front.


1	# Generic mock harness adapter — the canonical, harness-AGNOSTIC exercise of the
2	# spt-core contract. ZERO vendor harness conventions: no vendor binary name, no
3	# vendor config dir, no vendor hook names. The command templates spawn the
4	# trivial `mock-session` helper; the [hooks.*] table binds generic event names to
5	# the inbound `api` surface.
6	#
7	# This is the only adapter-shaped artifact in spt-core (PRD R-DOCS-2). A real
8	# harness adapter (e.g. the downstream spt-plugin) lives in its own repo.
9
10	[adapter]
11	name = "mock"
12	kind = "harness"
13	version = "1.0.0"
14	min_spt_core_version = "1.0.0"
15	hostable_types = ["LiveAgent", "ReadyAgent", "Worker"]
16
17	# Inbound hooks: generic event names → the `api` command each fires. SessionStart
18	# seeds; Idle reports idle (and arms the echo-gate); SessionEnd soft-tears-down.
19	[hooks.SessionStart]
20	fires = "api seed --pid {parent_pid} --session-id {session_id} --adapter {adapter_name}"
21	reads = ["session_id", "parent_pid"]
22	can_inject = true
23
24	[hooks.Idle]
25	fires = "api state idle"
26	reads = []
27	can_inject = false              # no inject channel → sentinel/relay fallback
28
29	[hooks.SessionEnd]
30	fires = "api session-end"
31	reads = []
32	can_inject = false
33
34	# Watched dirs: commune/signoff are file-drops (filenames spt-core-fixed), not
35	# commands.
36	[session]
37	commune_dir = ".mock"
38	signoff_dir = ".mock"
39
40	# Outbound session role: the opaque template ManifestRuntime spawns. `mock-session`
41	# stands in for a real harness binary; spt-core just runs it with keys filled.
42	[session.self]
43	command = "mock-session --id {id} --session-id {session_id}"
44	detach = true
45	keys = ["id", "session_id"]
46
47	# M2b live-agent lifecycle roles (harness-agnostic stand-ins). A real adapter's
48	# templates select a model + harness flags inside `command`; spt-core only fills
49	# {key} placeholders. The recursion guard makes the Psyche/echo children's own
50	# hooks bail (no Psyche-of-Psyche, no echo-of-echo).
51	[session.psyche_init]
52	command = "mock-session --mode psyche --id {id} --session-id {session_id}"
53	cwd = "{psyche_dir}"
54	recursion_guard_env = "MOCK_ECHO_COMMUNE"
55	detach = true
56	keys = ["id", "session_id", "psyche_dir", "psyche_prompt"]
57
58	[session.psyche_resume]
59	command = "mock-session --mode psyche --id {id} --session-id {session_id}"
60	cwd = "{psyche_dir}"
61	recursion_guard_env = "MOCK_ECHO_COMMUNE"
62	detach = true
63	keys = ["id", "session_id", "psyche_dir", "psyche_prompt"]
64
65	# Echo-commune: a bounded cheap-model template reading history on stdin.
66	[session.echo_commune]
67	command = "mock-session --mode echo --id {id}"
68	recursion_guard_env = "MOCK_ECHO_COMMUNE"
69	keys = ["id"]
70
71	# Signoff: a psyche_resume variant firing a final context-save.
72	[session.signoff]
73	command = "mock-session --mode echo --id {id}"
74	recursion_guard_env = "MOCK_ECHO_COMMUNE"
75	keys = ["id"]
76
77	# History: native Path-B store (the adapter pushes via `api history-log`).
78	[history]
79	strategy = "native"
80
81	# Env aliases the adapter injects for in-session use ($SPT = spt api, etc.).
82	[env.SPT_AGENT_ID]
83	direction = "inject"
84	value = "{id}"
85
86	# Inject methods per activity state (PTY is spt-core/M3, never offered here).
87	[inject]
88	activity = ["hook"]
89	idle = ["hook", "relay"]
90
91	[identity]
92	session_id_source = "post_spawn"
93	parent_ancestor_name = "mock-session"
94

# Generic mock harness adapter — the canonical, harness-AGNOSTIC exercise of the
# spt-core contract. ZERO vendor harness conventions: no vendor binary name, no
# vendor config dir, no vendor hook names. The command templates spawn the
# trivial `mock-session` helper; the [hooks.*] table binds generic event names to
# the inbound `api` surface.
#
# This is the only adapter-shaped artifact in spt-core (PRD R-DOCS-2). A real
# harness adapter (e.g. the downstream spt-plugin) lives in its own repo.

[adapter]
name = "mock"
kind = "harness"
version = "1.0.0"
min_spt_core_version = "1.0.0"
hostable_types = ["LiveAgent", "ReadyAgent", "Worker"]

# Inbound hooks: generic event names → the `api` command each fires. SessionStart
# seeds; Idle reports idle (and arms the echo-gate); SessionEnd soft-tears-down.
[hooks.SessionStart]
fires = "api seed --pid {parent_pid} --session-id {session_id} --adapter {adapter_name}"
reads = ["session_id", "parent_pid"]
can_inject = true

[hooks.Idle]
fires = "api state idle"
reads = []
can_inject = false              # no inject channel → sentinel/relay fallback

[hooks.SessionEnd]
fires = "api session-end"
reads = []
can_inject = false

# Watched dirs: commune/signoff are file-drops (filenames spt-core-fixed), not
# commands.
[session]
commune_dir = ".mock"
signoff_dir = ".mock"

# Outbound session role: the opaque template ManifestRuntime spawns. `mock-session`
# stands in for a real harness binary; spt-core just runs it with keys filled.
[session.self]
command = "mock-session --id {id} --session-id {session_id}"
detach = true
keys = ["id", "session_id"]

# M2b live-agent lifecycle roles (harness-agnostic stand-ins). A real adapter's
# templates select a model + harness flags inside `command`; spt-core only fills
# {key} placeholders. The recursion guard makes the Psyche/echo children's own
# hooks bail (no Psyche-of-Psyche, no echo-of-echo).
[session.psyche_init]
command = "mock-session --mode psyche --id {id} --session-id {session_id}"
cwd = "{psyche_dir}"
recursion_guard_env = "MOCK_ECHO_COMMUNE"
detach = true
keys = ["id", "session_id", "psyche_dir", "psyche_prompt"]

[session.psyche_resume]
command = "mock-session --mode psyche --id {id} --session-id {session_id}"
cwd = "{psyche_dir}"
recursion_guard_env = "MOCK_ECHO_COMMUNE"
detach = true
keys = ["id", "session_id", "psyche_dir", "psyche_prompt"]

# Echo-commune: a bounded cheap-model template reading history on stdin.
[session.echo_commune]
command = "mock-session --mode echo --id {id}"
recursion_guard_env = "MOCK_ECHO_COMMUNE"
keys = ["id"]

# Signoff: a psyche_resume variant firing a final context-save.
[session.signoff]
command = "mock-session --mode echo --id {id}"
recursion_guard_env = "MOCK_ECHO_COMMUNE"
keys = ["id"]

# History: native Path-B store (the adapter pushes via `api history-log`).
[history]
strategy = "native"

# Env aliases the adapter injects for in-session use ($SPT = spt api, etc.).
[env.SPT_AGENT_ID]
direction = "inject"
value = "{id}"

# Inject methods per activity state (PTY is spt-core/M3, never offered here).
[inject]
activity = ["hook"]
idle = ["hook", "relay"]

[identity]
session_id_source = "post_spawn"
parent_ancestor_name = "mock-session"


Grounded. spt-claude-code = empty (`.claude` perch leftover, no git). spt-releases = README + license local; real surface = GH Pages (docs site, install scripts, `llms.txt`, `manifest.schema.json`, mock-adapter source). Adapter shape = `manifest.toml` (declarative hooks/session-roles/digest/inject) ± thin glue binary. CC adapter's meat = real CC hook names → `spt api`, CC JSONL as `[digest]` source, M9 profiles/strings/hints.

Decision tree, dependency order: **deliverable shape → acceptance bar → handoff package → workflow carry-over → CI model**. Starting at the root.

---

**Q1 — What IS the spt-claude-code deliverable, concretely?**

Three plausible shapes:

| Shape | What perri ships | Build weight |
|---|---|---|
| **A. Pure manifest** | `manifest.toml` + CC hook scripts (shell/PS calling `spt api`) + install glue. No compiled binary. | ~none |
| **B. Manifest + thin binary** | manifest + a small `spt-claude-code` helper binary (hook dispatch, JSONL digest extraction logic too heavy for a template) | light Rust/whatever build |
| **C. Manifest + binary + bundled UX** | B plus CC plugin/skill packaging, slash-commands, installer, its own release pipeline | real build+release |

My rec: **B**. CC already has a hooks system (SessionStart/Stop/PreToolUse/etc.) that shells out — most glue is declarative manifest + hook commands. But the M10 `[digest]` extractor for CC's JSONL almost certainly needs real code (parse transcript, map roles, skip-diagnostics), more than a template string holds. A thin helper binary is the natural home. C is scope-creep for a v1 *acceptance proof*; defer packaging.

The shape sets CI weight (your explicit question) and the REQ seed.

Which shape — A, B, or C?


it needs to be (C). `spt-claude-code` is, while still an independent project, the acceptance phase of `spt-core` v1. it needs to have full parity to legacy spt, which is in sister project `claude_skill_owl`. much of this information should already be in CONTEXT.md. please check the docs here and the sister project to better align your understanding of what spt-claude-code needs to be.


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


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


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


Correcting to (C) = v1 acceptance, full legacy parity. Reading CONTEXT.md + surveying claude_skill_owl.