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

# Commune — doyle → doyle-psyche (2026-06-02, branch dev-freeform)

## Where we are this session

**M3a SHIPPED** — `spt-term`, the session-surface mechanism (the broker's PTY half). 7 atomic commits (A0–A6), all OS-validated on Windows (ConPTY) + Linux (forkpty via gravity-linux):
- A1 `SessionSurface` trait + native PTY backend (ConPTY/forkpty via portable-pty), resize behind master lock.
- A2 ConPTY-DSR auto-answer drain pump (no-EOF-while-writer-held discipline). Found Win11 26200 ConPTY doesn't emit `ESC[6n` for short cmds → proved the auto-answer by synthetic injection, not host behavior.
- A3 send-keys/send-line injection. Found a real ConPTY race: Ctrl-C dropped if sent before child installs handler → readiness handshake.
- A4 bounded byte-stream (OutputStream over sync_channel → backpressure).
- A5 PTY-digest parser primitive (ADR-0008): adapter-supplied patterns in, structured source-tagged turns out; ANSI-stripped, tail-wins repaint tolerance.
- REQ-TERM-1/2/3/4 + REQ-HAZARD-CONPTY-DSR activated.

**Bonus fixes (the session's surprise depth):**
- Cross-OS validation exposed **8 pre-existing tests broken on Linux/CI** (spt-live + spt-runtime) — `cfg(unix)` manifest fixtures with bad TOML-vs-tokenizer quoting, never caught on the Windows dev host. Fixed.
- And a **real production concurrency bug** behind the "flaky" `two_agents_exchange_message_tcp_and_spool`: SQLite `database is locked` because `busy_timeout` was set *after* the `journal_mode=WAL` switch (which bypasses the busy-handler anyway). Fixed with a shared `spt_store::db::tune_connection` (busy_timeout first, WAL-with-bounded-retry) + new hazard REQ-HAZARD-REGISTRY-CONCURRENT (KNOWN-HAZARDS 4.7) + 16-thread regression test. killer_quickstart 4/5-FAIL → 12/12-PASS on Linux.

**CI is now FULLY GREEN for the first time** (test ubuntu ✓ / test windows ✓ / traceability ✓). Two CI-infra fixes: a `TRACEABLE_REQS_TOKEN` PAT secret (cross-org private binary download), and **cut traceable-reqs v0.1.1** on BigscreenVR (the pinned v0.1.0 predated the `[<stage>->...]` doc-escape and flagged TRACEABILITY.md examples). See memory `ci-traceability-gate.md` — I have admin to cut those releases.

**M3b planned, not started.** `M3b-PLAN.md` fleshed from stub into a full B0–B9 task table (committed 7db111f).

## Immediate next steps (resume here)

**Execute M3b, starting B0.** M3b = the `spt-daemon` broker/brain process (ADR-0004). The hard, load-bearing idea: two real processes — **broker** (stable kernel: holds PTYs from spt-term + harness children + sockets, NO logic) and **brain** (restartable logic) — over a **versioned local IPC**, so a brain-only self-update swaps logic with zero endpoint interruption. Spikes #1/#3/#5/#6 already proved the shape on both OSes.

Order (full detail in `M3b-PLAN.md`):
- **B0** scaffold `crates/spt-daemon` (above spt-live, below spt) + the versioned IPC transport (named-pipe/UDS behind one trait, forward-compat frame schema, version handshake). ← START HERE
- B1 broker kernel → B2 brain + **gapless handoff** (the milestone's proof-gate: kill brain ≥10×, child+stream survive; `gen_start=now()`) → B3 consolidation (fold listen/pulse/Psyche loops into the brain) → B4 daemon-authoritative liveness → B5 idempotent boundary (Spike #6) → B6 auto-start + in-memory startup (retire the seed *file*) → B7 orphan-watch → B8 digest daemon-half (completes REQ-TERM-4 `int`) → B9 activation + brain-restart E2E + docs + M3c stub.

Discipline that's working: each task = one atomic commit, evidence-tagged, `traceable-reqs check` green, validated on BOTH OSes (Windows local + gravity-linux) before the next. Reuse `spt-term::PtySession` for broker PTYs; re-host (don't rewrite) the pure spt-live seams.

Binding constraints: broker holds ZERO logic (resist scope creep); version the IPC frame from byte one (forward-compat retrofits are expensive); B2 gapless-handoff is a gate not polish.

## Project status (broad) + end goal

**spt-core** = harness-independent core for an agent ecosystem — clean-room rebuild of `claude_skill_owl`. Rust crates + one `spt` binary. **End goal:** the *same* agent runs natively across all of a user's machines with a synced mind, reachable + operable from anywhere, seamless self-update, zero-config cross-machine messaging. First thing built atop it: a rebuilt `spt` plugin at parity with modern SPT.

Milestone map: M0 (proto+store) ✅ · M1 (msg) ✅ · M2a (runtime/harness contract) ✅ · M2b (live-agent lifecycle) ✅ · **M3a (spt-term) ✅** · **M3b (spt-daemon) ← NEXT** · M3c (self-update) · M4 (spt-net: Iroh/mDNS/pairing + multi-subnet + cross-node Psyche sync — the real proof: drive an agent on machine A from machine B) · M5 (Shells, presence, gated capabilities). 9 ADRs. Phase 0 spike-gate complete.

Layering (acyclic): `spt-proto → spt-store → spt-msg → {spt-net, spt-term, spt-runtime} → spt-live → spt-daemon → spt`. Binding rules: requirement traceability (`traceable-reqs.toml` authoritative, tag evidence in-commit), honor KNOWN-HAZARDS invariants, copy-verbatim sister's stable wire formats / clean-room everything else.

State: branch `dev-freeform`, head 7db111f, pushed, CI green, all reqs green (116/116). Resume by reading M3b-PLAN.md + starting B0.


Commune dropped (Self listener ingests + deletes on success). Quick confirm, then self-clear.


Bash

sleep 3; if [ -f .claude/doyle-commune.md ]; then echo "commune still present (ingest pending or listener inactive)"; else echo "commune ingested + deleted ✓"; fi

Check commune ingestion


commit it, then /commune with immediate next steps and broad summary of the project's status + end goal. we'll resume in the next session --> finally, perform /self-clear


commune still present (ingest pending or listener inactive)


Commune file dropped (still present — Self listener may ingest async or be inactive this session; the artifact persists either way). All work committed + pushed, CI green.

Performing `/self-clear` now — re-seeding to resume at M3b B0.


Skill

Resume spt-core M3b. State: branch dev-freeform, head 7db111f, pushed, CI fully green, all reqs 116/116. M3a (spt-term) SHIPPED. Next: execute M3b (spt-daemon broker/brain) starting task B0 — read M3b-PLAN.md for the full B0–B9 table. B0 = scaffold crates/spt-daemon (above spt-live, below spt) + versioned local-IPC transport (named-pipe/UDS behind one trait, forward-compat frames, version handshake). Discipline: atomic commit per task, evidence-tag + traceable-reqs check green, validate BOTH OSes (Windows local + gravity-linux via tar-over-ssh, askpass shim — see memory cross-machine-test-rig.md). Reuse spt-term::PtySession for broker PTYs; re-host (don't rewrite) spt-live seams; broker holds ZERO logic. Context dropped to .claude/doyle-commune.md.


Launching skill: self-clear


Base directory for this skill: C:\Users\decid\.claude\skills\self-clear

# /self-clear

Wipes THIS agent's conversation (`/clear`), then ~10s later TYPES a self-note
as a fresh user prompt so the agent wakes on a clean context and proceeds.

## Run it

One script does everything. Just run:

```powershell
& "C:\Users\decid\.claude\skills\self-clear\scripts\self-clear.ps1"
```

Expect: `SELF-CLEAR armed: id=<agent_id> winpid=<n> hwnd=<n> — /clear queued; self-note typed in ~10s`

Then stop — end your turn promptly so the queued `/clear` fires.

## What the script does

1. `owl whoami` → resolves this session's `agent_id` (context-independent, survives the wipe). No perch → it aborts WITHOUT clearing and tells you to `/spt:ready` or `/spt:live` first.
2. Walks the parent chain (`pwsh → claude.exe → … → WindowsTerminal`) to the ancestor that owns the window, foregrounds it.
3. Types `/clear` + Enter — **queued**; only fires when this turn ends.
4. Spawns a **detached** waker: waits 10s (past turn-end + wipe), re-foregrounds the terminal via the arm-time `hwnd`/`winpid`, then **types** `NOTE FROM THE USER: proceed with next steps.` + Enter as a fresh user prompt.

The 10s delay + detachment are deliberate: the prompt must be typed **after**
`/clear` takes effect, so it lands on the clean context and starts a new turn.

Why typed, not `owl send`: after `/clear` the session sits idle awaiting user
input. A spooled owl message can't self-start a turn — it surfaces only during an
already-active turn (PreToolUse hook) or in a live Monitor stream (whose buffer
`/clear` wipes). So a self-addressed owl note never woke the agent. A typed prompt
deterministically starts a turn AND is the re-seed.

## Caveats

- Window focus brings the whole terminal forward; it can't target a specific tab. Clean when the agent's tab is active.
- The note is typed via SendKeys, so the terminal must stay the foreground-able window of `winpid`. Don't close/replace the terminal in the ~10s gap.
- SendKeys reserves `+ ^ % ~ ( ) { } [ ]`; the default note text uses none. If you customize the note, escape those chars.
- If your turn runs longer than ~10s after the script returns, the prompt could be typed before the wipe completes. Stop promptly after running.

ARGUMENTS: Resume spt-core M3b. State: branch dev-freeform, head 7db111f, pushed, CI fully green, all reqs 116/116. M3a (spt-term) SHIPPED. Next: execute M3b (spt-daemon broker/brain) starting task B0 — read M3b-PLAN.md for the full B0–B9 table. B0 = scaffold crates/spt-daemon (above spt-live, below spt) + versioned local-IPC transport (named-pipe/UDS behind one trait, forward-compat frames, version handshake). Discipline: atomic commit per task, evidence-tag + traceable-reqs check green, validate BOTH OSes (Windows local + gravity-linux via tar-over-ssh, askpass shim — see memory cross-machine-test-rig.md). Reuse spt-term::PtySession for broker PTYs; re-host (don't rewrite) spt-live seams; broker holds ZERO logic. Context dropped to .claude/doyle-commune.md.


/clear


PowerShell

Run self-clear: queue /clear + schedule wake note


SELF-CLEAR armed: id=doyle winpid=29328 hwnd=133338 — /clear queued; self-note typed in ~10s


Self-clear armed — `/clear` queued, wake note fires in ~10s. Ending turn now so the wipe lands.

Session wrap: M3a shipped, CI fully green (116/116), `M3b-PLAN.md` committed (`7db111f`, pushed), handoff in `.claude/doyle-commune.md`. Resume at **M3b B0**. 🪵