Base directory for this skill: C:\Users\decid\.claude\plugins\cache\cplugs\spt\1.11.22\skills\commune

# /spt:commune

All commands use `$LIVE` env var, auto-injected by the plugin's SessionStart hook. If commands fail with "command not found", restart the Claude Code session so the SessionStart hook re-runs.

> **Identity auto-detection:** Your identity is auto-detected from your session. Pass your ID explicitly only if auto-detection fails.

## Flow

1. **Download Psyche's *current* context** — it shifts during the session as background echo communes fire. Re-download right before composing; the gen-N snapshot you read at session start is already stale:
   ```bash
   $LIVE psyche-download <your-id>
   ```

   > **Output truncation.** If the Bash tool reports `Output too large (N KB)` and saves the full result to a `tool-results/<id>.txt` file, use the `Read` tool on that saved path to access the full content. Do NOT re-run `psyche-download` to grep/awk out sections — repeated invocations re-download the same context, waste tokens, and may duplicate `## Pending Commune` sections in `live_context.md`.

2. **Diff your knowledge against this fresh download** — only what's missing from *it* is the real delta (new work, decisions, intentions). Anything already absorbed is not. If the download includes a `<memformat>` section, use it as a guide for what topics to cover. A `## Pending Commune (uncommitted)` section means a previous commune is still queued — do NOT re-send it.

3. **Commune only the delta** -- use the **Write tool** to create
   `.claude/{your-id}-commune.md` with the two-slice body as its contents
   (see `## Two-slice body shape (Phase 25 D-10/D-11)` below for the required
   envelope wrapping). Do not use Bash/heredoc -- Write is the canonical path:
   no shell escaping, no `EOF` collision risk, and Write auto-creates the
   `.claude/` parent directory.

   Your Self listener detects the file on its next poll iteration, notifies
   your Psyche wrapper, and the wrapper ingests the content via the existing
   Psyche session. On success (subprocess exit code 0) the wrapper deletes the
   file. On error (token rate limit, etc) the file is retained and retried on
   the next consume cycle. If you write again before the wrapper consumes, the
   latest write wins (last-write-wins overwrite semantics).

If Psyche's context is already current, no commune is needed. Say so and move on.

Read `commune.md` (in this skill directory) for the full commune protocol -- when to send, what to include, and diligence triggers.

**Agent-type guard:** Only works on live agents. If target is not live, refuses with: "Communes require a live agent with Psyche."

## Two-slice body shape (Phase 25 D-10/D-11)

The body you write in `.claude/{your-id}-commune.md` MUST itself be wrapped in two-slice envelopes per Phase 25 D-10/D-11. The taxonomy — what belongs in `<live-context>` vs `<project-context>` — is defined canonically in `psyche.md` §`<output_envelope>` (lines 282–323). Read that section as the source of truth; this skill doc teaches only when and how to apply it.

**In-project detection rule (D-25.1-04).** Before composing your commune body, run `$LIVE psyche-download <your-id>` (Step 1 of `## Flow` above) and inspect the `<current ... />` tag at the top of the output. The `<current/>` tag carries a `project="..."` attribute whenever any payload is produced — its presence means you are inside a tracked project (inside a git repo, `project` is the repo name; outside a git repo per D-11, `project` is the cwd-basename fallback, which still counts as a project context for routing purposes). A `psyche-download` invocation that returns no payload at all (NO-CONTEXT exit) means no project resolved. So: `project="..."` populated on `<current/>` → emit BOTH envelopes (apply rule 1 or 2 below); no payload at all → emit ONLY `<live-context>` (rule 3). Secondary signal: the `<project-context-resolved name="..."/>` sentinel further down the output indicates the project file already has prior content — useful for spotting first-time-in-project pairings, but NOT the routing rule.

**Three rules (D-25.1-01..03):**

- **In-project, both slices populated** (marker present, you have project-specific content this cycle): emit `<live-context>...</live-context>` AND `<project-context>...</project-context>`, both with non-empty bodies.
- **In-project, no project-specific update this cycle** (marker present, but nothing project-bound to report): emit `<live-context>...</live-context>` AND `<project-context></project-context>` (empty body — the deliberate "in-project but quiet" signal per D-25.1-02). Distinguishable from "no project resolved".
- **Outside any tracked project** (marker absent): emit ONLY `<live-context>...</live-context>`. Do NOT emit an empty `<project-context>` envelope (missing tag means "no project resolved" per D-25.1-03).

**Nested envelopes.** The Phase 23 `<EVENT type="commune">` envelope (see `## Envelope shape (Phase 23 v1.8)` below) is composed by `$LIVE commune` automatically — you NEVER write `<EVENT>` tags. You write ONLY the inner two-slice body. The two envelope layers nest: outer EVENT wraps inner two-slice body.

(See `psyche.md` §`<output_envelope>` for the canonical taxonomy and per-slice content rules.)

## Envelope shape (Phase 23 v1.8)

As of v1.8 Phase 23, commune deliveries are wrapped in a typed EVENT envelope carrying a 5-field stamp (`machine`, `project`, `branch`, `head_sha`, `head_subject`); the prose `COMMUNE (timestamp): body` form is gone.

```xml
<EVENT type="commune" timestamp="2026-05-20T06:00:00-07:00" machine="hostname" project="claude_skill_owl" branch="main" head_sha="abc123..." head_subject="subject line capped at 72 chars">body</EVENT>
```

Outside a git repo (D-11), `branch`, `head_sha`, and `head_subject` are omitted entirely (not empty-string-set):

```xml
<EVENT type="commune" timestamp="2026-05-20T06:00:00-07:00" machine="hostname" project="cwd-basename">body</EVENT>
```

`$LIVE commune` composes this envelope automatically — Self does NOT manually construct EVENT XML. The `body` placeholder in the example above is the two-slice body (see `## Two-slice body shape (Phase 25 D-10/D-11)` above); the two envelope layers nest. The wrapper-side parser ignores unknown attrs, so the stamp fields are forward-compatible with older receivers. For drift detection on resume, see the `live` skill.

ARGUMENTS: with immediate next steps and broad summary of the project's status + end goal. we'll resume in the next session


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


Download current Psyche context first.


Bash

$LIVE psyche-download doyle 2>&1 | head -120

Download current Psyche context


<memformat>
<?xml version="1.0"?>
<memformat version="1">
<!-- Changelog: v1 - initial seed -->
<topics>
  <topic name="events">Notable or unusual events and requests</topic>
  <topic name="interactions">Agent interactions -- who, roles, contributions</topic>
  <topic name="reflections">Thoughts on recent work -- what went well, what was tricky</topic>
  <topic name="ideas">Ideas to raise with the user</topic>
  <topic name="improvements">Further improvement ideas for recent problem spaces</topic>
  <topic name="timeline">What happened when, timing, sequencing</topic>
  <topic name="blockers">Current blockers or concerns</topic>
  <topic name="focus">Current focus and immediate next steps</topic>
</topics>
</memformat>
</memformat>

<current machine="HFENDULEAM" project="spt-core" branch="dev-freeform" head_sha="104ea8e466fc20f5b8ab7879a3a3b901034ffbd6" head_subject="docs(M2b): author M2b-PLAN.md (live-agent lifecycle)" commits_since="0" commits_unpulled="0"/>
M2a COMPLETE: all 11 tasks (T0–T10) landed as atomic commits. 162 tests green, clippy clean. M2a deliverables: spt-runtime crate (manifest schema, AgentRuntime trait + ManifestRuntime with opaque-template subst), spt binary api surface (dispatch group, local-api-auth, proc::parent_pid anchor, seed-file interim model), adapters/mock, contract E2E via mock. CI gate: build/test/clippy + traceable-reqs, 17 M2a reqs activated.

M2b plan authored (JIT, lightweight pattern). Scope: spt-live crate executing the lifecycle — spawn-psyche seam, history subsystem (three strategies), echo-commune, drop-file ingest, pulse heartbeat, signoff+boundary (ordering invariants), resume-session. 10 tasks (T0 scaffold → T10 activation); interim pulse model (M3 subsumes daemon loop). Workspace: crates/spt-live added, layering acyclic spt-proto→spt-store→spt-msg→spt-runtime→spt-live.

Next: M2b execution begins (task sequencing: history first, then spawn-psyche, echo-commune, drop-file, pulse, signoff, resume, integration, E2E, activation).<project-context-resolved name="spt-core"/>
M2a complete, M2b planned. Roadmap to be amended (M2a mark delivered). CONTEXT to absorb M2b notes (interim pulse, clean-room posture, daemon move to M3). M3 plan stub to be authored (deferred).


In-project (spt-core), both slices. Fresh download already knows M2a-done/M2b-planned. Real delta: T10 finished (ARCH-2 + ROADMAP delivered), plan is 11 tasks not 10, next-session entry point.


Write

<live-context>
Session close — M2a fully shipped + M2b planned, handing off to next session.

Working rhythm that worked this session: execute the JIT plan task-by-task, one
atomic commit per task, tag traceable-reqs evidence + activate reqs in the SAME
commit, run `traceable-reqs check` + `cargo test` green before moving on. Kept a
TaskCreate/TaskUpdate list (T0–T10) as the spine. This cadence held for 11 tasks
without drift — reuse it for M2b.

Recurring gotcha solved twice: process-wide SPT_HOME env races in tests. Fix
pattern = one shared lock + fresh temp home per test (spt crate: testutil.rs
isolated_home(); integration tests: a static Mutex serializing the whole test).
Per-module locks are NOT enough — different modules race on the global env.

Next session entry point: M2b T0 (scaffold crates/spt-live). Then T1 history
subsystem FIRST (echo-commune consumes it). Open decision to resolve before T5:
the interim pulse heartbeat has no dedicated REQ — default ruling is "mechanism
under SEAM-PSYCHE, M3 daemon owns the durable loop" (don't pre-register a req
for throwaway glue). Revisit only if T5 pulse grows load-bearing behavior.

End goal (the why): spt-core = harness-independent core for an agent ecosystem —
the proof is the same agent running natively across all a user's machines with a
synced mind, reachable/operable from anywhere, zero-config cross-machine
messaging + seamless self-update. First consumer atop it = a rebuilt spt plugin
at parity with modern SPT. v1 = full PRD incl. networking (the reason it exists).
</live-context>
<project-context>
M2a (Harness contract) COMPLETE + delivered — 11 atomic commits T0–T10, 162
tests green, clippy -D warnings clean, traceable-reqs check green. T10 activation
sweep finished: REQ-ARCH-2 activated [impl] (spt-runtime now in the public SDK
surface alongside spt-proto/spt-msg); ROADMAP M2a bullet marked ✅ delivered
(2026-06-01). 17 M2a reqs activated total (MANIFEST-1, SEAM-SPAWN/POSTSPAWN/
ACTIVITY/INJECT/CAPABILITY, API-1/2/3, START-1/2/4, ARCH-2 + hazards LOCAL-API-
AUTH/CASCADE-WIPE-GUARD/SUBPROCESS-TIMEOUT; +int on API-1/2 + START-2).

Shipped this milestone: spt-runtime (manifest schema all sections + parse/
validate; AgentRuntime trait + ManifestRuntime — opaque {key} fill, bounded run
w/ mandatory timeout). spt binary api surface — full inbound contract: dispatch
+ --adapter + local-api-auth (capability token OR session_id, constant-time);
startup seed→listen→bind (interim seed-file = spt-store::seed, the M3 swap point;
proc::parent_pid anchor; pid-recycle guard); delivery (state/echo-gate sentinels,
poll, inject resolution); workers + cascade-wipe guard; reporting (boundary,
session-end soft/--erase, presence, history-log, emit stub, capability, filedrop/
env-alias resolution). adapters/mock (zero vendor conventions, grep-enforced) +
mock-session helper. Two contract E2Es (spawn→bind→state→poll, and seed→listen→
relay).

M2b plan authored = M2b-PLAN.md (committed 104ea8e), linked from ROADMAP. ELEVEN
tasks T0–T10 (note: 11, not 10): T0 scaffold spt-live → T1 history subsystem →
T2 spawn-psyche → T3 echo-commune → T4 drop-file ingest (single-writer 6.4 +
precedence 6.5) → T5 interim pulse → T6 signoff/boundary (ordering invariants
echo-before-signoff 3.3, grace 1.1, stale sweep 3.2) → T7 resume seam → T8 api
listen wiring → T9 LiveAgent E2E → T10 activation. Interim no-daemon model held
(Psyche a real process, pulse in the listen runner; M3 re-hosts into daemon).
Clean-room posture: COPY sister's orphan/grace ORDERING invariants, clean-room
the CC-coupled wiring behind M2a seams. Layering: add crates/spt-live (5th
layer); spt-live NOT in public SDK (it's the daemon-bound executor M3
consolidates).

Still pending (deferred, not blockers): M3 plan stub (author when M2b lands);
CONTEXT.md absorbing M2b interim-pulse/clean-room notes (the plan captures them;
CONTEXT amend can wait). Orientation docs unchanged: PRD/ROADMAP/CONTEXT/docs.
</project-context>


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)

<live-context>
Session close — M2a fully shipped + M2b planned, handing off to next session.

Working rhythm that worked this session: execute the JIT plan task-by-task, one
atomic commit per task, tag traceable-reqs evidence + activate reqs in the SAME
commit, run `traceable-reqs check` + `cargo test` green before moving on. Kept a
TaskCreate/TaskUpdate list (T0–T10) as the spine. This cadence held for 11 tasks
without drift — reuse it for M2b.

Recurring gotcha solved twice: process-wide SPT_HOME env races in tests. Fix
pattern = one shared lock + fresh temp home per test (spt crate: testutil.rs
isolated_home(); integration tests: a static Mutex serializing the whole test).
Per-module locks are NOT enough — different modules race on the global env.

Next session entry point: M2b T0 (scaffold crates/spt-live). Then T1 history
subsystem FIRST (echo-commune consumes it). Open decision to resolve before T5:
the interim pulse heartbeat has no dedicated REQ — default ruling is "mechanism
under SEAM-PSYCHE, M3 daemon owns the durable loop" (don't pre-register a req
for throwaway glue). Revisit only if T5 pulse grows load-bearing behavior.

End goal (the why): spt-core = harness-independent core for an agent ecosystem —
the proof is the same agent running natively across all a user's machines with a
synced mind, reachable/operable from anywhere, zero-config cross-machine
messaging + seamless self-update. First consumer atop it = a rebuilt spt plugin
at parity with modern SPT. v1 = full PRD incl. networking (the reason it exists).
</live-context>
<project-context>
M2a (Harness contract) COMPLETE + delivered — 11 atomic commits T0–T10, 162
tests green, clippy -D warnings clean, traceable-reqs check green. T10 activation
sweep finished: REQ-ARCH-2 activated [impl] (spt-runtime now in the public SDK
surface alongside spt-proto/spt-msg); ROADMAP M2a bullet marked ✅ delivered
(2026-06-01). 17 M2a reqs activated total (MANIFEST-1, SEAM-SPAWN/POSTSPAWN/
ACTIVITY/INJECT/CAPABILITY, API-1/2/3, START-1/2/4, ARCH-2 + hazards LOCAL-API-
AUTH/CASCADE-WIPE-GUARD/SUBPROCESS-TIMEOUT; +int on API-1/2 + START-2).

Shipped this milestone: spt-runtime (manifest schema all sections + parse/
validate; AgentRuntime trait + ManifestRuntime — opaque {key} fill, bounded run
w/ mandatory timeout). spt binary api surface — full inbound contract: dispatch
+ --adapter + local-api-auth (capability token OR session_id, constant-time);
startup seed→listen→bind (interim seed-file = spt-store::seed, the M3 swap point;
proc::parent_pid anchor; pid-recycle guard); delivery (state/echo-gate sentinels,
poll, inject resolution); workers + cascade-wipe guard; reporting (boundary,
session-end soft/--erase, presence, history-log, emit stub, capability, filedrop/
env-alias resolution). adapters/mock (zero vendor conventions, grep-enforced) +
mock-session helper. Two contract E2Es (spawn→bind→state→poll, and seed→listen→
relay).

M2b plan authored = M2b-PLAN.md (committed 104ea8e), linked from ROADMAP. ELEVEN
tasks T0–T10 (note: 11, not 10): T0 scaffold spt-live → T1 history subsystem →
T2 spawn-psyche → T3 echo-commune → T4 drop-file ingest (single-writer 6.4 +
precedence 6.5) → T5 interim pulse → T6 signoff/boundary (ordering invariants
echo-before-signoff 3.3, grace 1.1, stale sweep 3.2) → T7 resume seam → T8 api
listen wiring → T9 LiveAgent E2E → T10 activation. Interim no-daemon model held
(Psyche a real process, pulse in the listen runner; M3 re-hosts into daemon).
Clean-room posture: COPY sister's orphan/grace ORDERING invariants, clean-room
the CC-coupled wiring behind M2a seams. Layering: add crates/spt-live (5th
layer); spt-live NOT in public SDK (it's the daemon-bound executor M3
consolidates).

Still pending (deferred, not blockers): M3 plan stub (author when M2b lands);
CONTEXT.md absorbing M2b interim-pulse/clean-room notes (the plan captures them;
CONTEXT amend can wait). Orientation docs unchanged: PRD/ROADMAP/CONTEXT/docs.
</project-context>


/spt:commune with immediate next steps and broad summary of the project's status + end goal. we'll resume in the next session


Commune written to `.claude/doyle-commune.md` — Self listener ingests on next poll, Psyche absorbs, wrapper deletes on success.

**Delta communed (both slices, in-project):**
- **M2a delivered** — T10 finished: REQ-ARCH-2 activated, ROADMAP marked ✅. (download treated this as pending)
- **M2b plan = 11 tasks** T0–T10 (download said 10)
- **Next-session entry:** M2b T0 scaffold `spt-live` → T1 history first
- **Open decision flagged:** pulse heartbeat REQ (default: mechanism under SEAM-PSYCHE)
- **Working rhythm + the SPT_HOME test-race fix pattern** for reuse
- **End goal** restated (synced agent across machines; v1 = full PRD)

Resume next session at M2b T0.