# /sptc:setup — operative instructions

**Goal:** install or repair spt-core for this session **and activate the claude-spt adapter** — the
mid-session installer covering the gap when no SessionStart bootstrap has fired. Installing the
binary is only half the job: a present binary with a **deregistered** adapter has no
profiles/strings/hints/`[digest]`, so the `/sptc:*` surface is inert until activation.

<!-- [doc->REQ-SETUP-ACTIVATE] -->

**Do this:**

1. **Binary.** If spt-core is absent (`command -v spt && spt --version` reports nothing), run the
   published install-on-demand bootstrap (spt-releases `harness-contract/install-on-demand.md`):
   - **POSIX:** `curl -fsSL https://sabermage.github.io/spt-releases/install.sh | sh`
   - **Windows (PowerShell):** `irm https://sabermage.github.io/spt-releases/install.ps1 | iex`

   `PATH` is not reloaded in this shell after a fresh install — verify with the absolute path:
   `"$HOME/.local/bin/spt" --version`. After this, `spt update` handles signed self-updates.

2. **Activate the adapter.** Run `spt adapter list` and find `claude-spt`:
   - Listed and **not** `deregistered` → already active; report it and skip to step 3.
   - Missing or `deregistered` → activate it:
     - **Local dev / dogfooding a repo checkout** (an `adapter/claude-spt.toml` near cwd):
       `spt adapter add ./adapter/claude-spt.toml`.
     - **End-user (plugin only):** the `.spt` carries native binaries, so it ships **per-OS** — pick
       the host's. Detect: `os=$(uname -s)` → MINGW*/MSYS*/CYGWIN*=windows, Linux=linux, Darwin=macos;
       `arch=$(uname -m)` → x86_64/amd64=x86_64, arm64/aarch64=aarch64. Then
       `spt adapter add --release SaberMage/spt-claude-code --asset adapter-$os-$arch.spt` — fetches
       the per-OS asset (tar root = `manifest.toml` + `strings/` + native tool binaries), extracts to
       the durable home, registers. `--tag <ver>` pins a version. v1 ships windows + linux.
       <!-- [doc->REQ-DIST-ADAPTER-PEROS] -->

3. **Verify + set active.** Re-run `spt adapter list` — `claude-spt` must read **active** (no
   `deregistered`). Then `spt adapter use claude-spt` so bare resolution lands here for the `claude`
   host (the legacy-parity bare flow — `/sptc:live`/`/sptc:ready` need no `--adapter`). The
   `claude-spt-digest` + `claude-spt-psyche` tools are invoked by bare name and resolve **from the
   adapter install dir** (the `from …` path in `spt adapter list`), where activation extracted them —
   no PATH copy needed. If either fails to start, confirm both are present in that dir (a packaging
   defect, not a PATH problem).

4. **ccs wiring (optional).** Detect `~/.ccs`:
   - Present → the shipped `claude-spt:ccs` profile leaf-replaces the session command with `ccs` (a
     drop-in for `claude`), so live/ready agents can run on ccs backends via `--adapter
     claude-spt:ccs`. Check `command -v ccs`; if `~/.ccs` exists but `ccs` isn't on PATH, point the
     user at their ccs bin dir.
   - Absent → ccs is an optional CLI router for alternate model backends in place of `claude`. To
     enable: install ccs, then re-run `/sptc:setup`. Skip if unwanted.
   <!-- [doc->REQ-SETUP-CCS] -->

5. **Subnet onboarding (optional).** A subnet is the private group of paired machines that makes
   `/sptc:send`, `/sptc:ready`, and live agents work cross-machine (local use needs none). Check
   `spt subnet status`:
   - In a subnet → invite a machine with `spt subnet show-code`; on the joiner, `spt subnet join`.
   - Not in one → offer **create** (`spt subnet create` — this node becomes seed-holder) or **join**
     (`spt subnet join`). Full verb guidance → **/sptc:subnet**.
   - **Elevation:** create/join/show-code are OS-elevation-gated — Windows: elevated (UAC) shell;
     Linux desktop: pkexec/polkit or sudo terminal; Linux TTY: inline sudo; headless: print the exact
     command for the user to run elevated.
   <!-- [doc->REQ-SETUP-SUBNET] -->

Idempotent and safe to re-run — the same bootstrap + activation the SessionStart hook performs.


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

# /sptc:setup — operative instructions

**Goal:** install or repair spt-core for this session **and activate the claude-spt adapter** — the
mid-session installer covering the gap when no SessionStart bootstrap has fired. Installing the
binary is only half the job: a present binary with a **deregistered** adapter has no
profiles/strings/hints/`[digest]`, so the `/sptc:*` surface is inert until activation.

<!-- [doc->REQ-SETUP-ACTIVATE] -->

**Do this:**

1. **Binary.** If spt-core is absent (`command -v spt && spt --version` reports nothing), run the
   published install-on-demand bootstrap (spt-releases `harness-contract/install-on-demand.md`):
   - **POSIX:** `curl -fsSL https://sabermage.github.io/spt-releases/install.sh | sh`
   - **Windows (PowerShell):** `irm https://sabermage.github.io/spt-releases/install.ps1 | iex`

   `PATH` is not reloaded in this shell after a fresh install — verify with the absolute path:
   `"$HOME/.local/bin/spt" --version`. After this, `spt update` handles signed self-updates.

2. **Activate the adapter.** Run `spt adapter list` and find `claude-spt`:
   - Listed and **not** `deregistered` → already active; report it and skip to step 3.
   - Missing or `deregistered` → activate it:
     - **Local dev / dogfooding a repo checkout** (an `adapter/claude-spt.toml` near cwd):
       `spt adapter add ./adapter/claude-spt.toml`.
     - **End-user (plugin only):** the `.spt` carries native binaries, so it ships **per-OS** — pick
       the host's. Detect: `os=$(uname -s)` → MINGW*/MSYS*/CYGWIN*=windows, Linux=linux, Darwin=macos;
       `arch=$(uname -m)` → x86_64/amd64=x86_64, arm64/aarch64=aarch64. Then
       `spt adapter add --release SaberMage/spt-claude-code --asset adapter-$os-$arch.spt` — fetches
       the per-OS asset (tar root = `manifest.toml` + `strings/` + native tool binaries), extracts to
       the durable home, registers. `--tag <ver>` pins a version. v1 ships windows + linux.
       <!-- [doc->REQ-DIST-ADAPTER-PEROS] -->

3. **Verify + set active.** Re-run `spt adapter list` — `claude-spt` must read **active** (no
   `deregistered`). Then `spt adapter use claude-spt` so bare resolution lands here for the `claude`
   host (the legacy-parity bare flow — `/sptc:live`/`/sptc:ready` need no `--adapter`). The
   `claude-spt-digest` + `claude-spt-psyche` tools are invoked by bare name and resolve **from the
   adapter install dir** (the `from …` path in `spt adapter list`), where activation extracted them —
   no PATH copy needed. If either fails to start, confirm both are present in that dir (a packaging
   defect, not a PATH problem).

4. **ccs wiring (optional).** Detect `~/.ccs`:
   - Present → the shipped `claude-spt:ccs` profile leaf-replaces the session command with `ccs` (a
     drop-in for `claude`), so live/ready agents can run on ccs backends via `--adapter
     claude-spt:ccs`. Check `command -v ccs`; if `~/.ccs` exists but `ccs` isn't on PATH, point the
     user at their ccs bin dir.
   - Absent → ccs is an optional CLI router for alternate model backends in place of `claude`. To
     enable: install ccs, then re-run `/sptc:setup`. Skip if unwanted.
   <!-- [doc->REQ-SETUP-CCS] -->

5. **Subnet onboarding (optional).** A subnet is the private group of paired machines that makes
   `/sptc:send`, `/sptc:ready`, and live agents work cross-machine (local use needs none). Check
   `spt subnet status`:
   - In a subnet → invite a machine with `spt subnet show-code`; on the joiner, `spt subnet join`.
   - Not in one → offer **create** (`spt subnet create` — this node becomes seed-holder) or **join**
     (`spt subnet join`). Full verb guidance → **/sptc:subnet**.
   - **Elevation:** create/join/show-code are OS-elevation-gated — Windows: elevated (UAC) shell;
     Linux desktop: pkexec/polkit or sudo terminal; Linux TTY: inline sudo; headless: print the exact
     command for the user to run elevated.
   <!-- [doc->REQ-SETUP-SUBNET] -->

Idempotent and safe to re-run — the same bootstrap + activation the SessionStart hook performs.

-> Delivered file-backed via the `claude-spt` adapter `[strings]`

-> (`[strings.skills].setup = { file = "skills/setup.md" }`), resolved at injection time. The cplugs

-> SKILL.md stays a thin skeleton (ADR-0001).

+**Goal:** install or repair spt-core for this session **and activate the claude-spt adapter** — the

+mid-session installer covering the gap when no SessionStart bootstrap has fired. Installing the

+binary is only half the job: a present binary with a **deregistered** adapter has no

+profiles/strings/hints/`[digest]`, so the `/sptc:*` surface is inert until activation.

-**Goal:** install or repair spt-core for this session **and ACTIVATE the claude-spt adapter** — the

-mid-session installer that covers the gap when no SessionStart bootstrap has fired (a user who

-installs the plugin mid-session). Installing the binary is only half the job: a present binary with

-a **deregistered** adapter has no profiles/strings/hints/`[digest]`, so `/sptc:*` injection has

-nothing to source. Setup must leave the adapter **active**.

-1. **Binary.** Check whether spt-core is present: `command -v spt && spt --version`.

-   - If absent, run the published install-on-demand bootstrap (verbatim against the spt-releases

-     contract, `harness-contract/install-on-demand.md`):

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

-     - **Windows (PowerShell):** `irm https://sabermage.github.io/spt-releases/install.ps1 | iex`

-   - `PATH` is not reloaded in the current shell after a fresh install — verify with the absolute

-     path for the first call: `"$HOME/.local/bin/spt" --version` (POSIX). Report the version.

+1. **Binary.** If spt-core is absent (`command -v spt && spt --version` reports nothing), run the

+   published install-on-demand bootstrap (spt-releases `harness-contract/install-on-demand.md`):

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

+   - **Windows (PowerShell):** `irm https://sabermage.github.io/spt-releases/install.ps1 | iex`

-2. **Adapter activation (the step a present binary still needs).** Run `spt adapter list` and look

-   - If `claude-spt` is listed and **not** marked `deregistered` → the adapter is **active**; report

-     "adapter active" and go to step 4.

-   - If `claude-spt` is **missing or `deregistered`** → **activate** it. Pick the source:

-     - **Local dev / dogfooding from a repo checkout** (an `adapter/claude-spt.toml` is present near

-       cwd): `spt adapter add ./adapter/claude-spt.toml` (the file-form takes any path + filename).

-     - **End-user (plugin only, no repo checkout):** the `.spt` asset carries native binaries, so it

-       ships **per-OS** — select the one matching this host. Detect os + arch:

-       os=$(uname -s);  case "$os" in MINGW*|MSYS*|CYGWIN*|Windows*) os=windows;; Linux) os=linux;; Darwin) os=macos;; esac

-       arch=$(uname -m); case "$arch" in x86_64|amd64) arch=x86_64;; arm64|aarch64) arch=aarch64;; esac

-       then `spt adapter add --release SaberMage/spt-claude-code --asset adapter-$os-$arch.spt` —

-       fetches the per-OS `adapter-<os>-<arch>.spt` release asset (a tar whose **root** holds

-       `manifest.toml` + `strings/` + the native tool binaries) from the repo's GitHub release,

-       extracts it to the durable adapter home, and registers it. Add `--tag <ver>` to pin a version

-       (omit for latest). Re-running with a newer `--tag` is a manual re-acquire. `adapter add` is

-       manifest-first (an invalid manifest registers nothing). (v1 ships **windows + linux** assets.

-       Recommended path — straight from the monorepo, no dedicated repo. Needs the spt release that

-       carries `--release`; the older `--github <root-manifest-repo>` is the alternative.)

+   `PATH` is not reloaded in this shell after a fresh install — verify with the absolute path:

+   `"$HOME/.local/bin/spt" --version`. After this, `spt update` handles signed self-updates.

+2. **Activate the adapter.** Run `spt adapter list` and find `claude-spt`:

+   - Listed and **not** `deregistered` → already active; report it and skip to step 3.

+   - Missing or `deregistered` → activate it:

+     - **Local dev / dogfooding a repo checkout** (an `adapter/claude-spt.toml` near cwd):

+       `spt adapter add ./adapter/claude-spt.toml`.

+     - **End-user (plugin only):** the `.spt` carries native binaries, so it ships **per-OS** — pick

+       the host's. Detect: `os=$(uname -s)` → MINGW*/MSYS*/CYGWIN*=windows, Linux=linux, Darwin=macos;

+       `arch=$(uname -m)` → x86_64/amd64=x86_64, arm64/aarch64=aarch64. Then

+       `spt adapter add --release SaberMage/spt-claude-code --asset adapter-$os-$arch.spt` — fetches

+       the per-OS asset (tar root = `manifest.toml` + `strings/` + native tool binaries), extracts to

+       the durable home, registers. `--tag <ver>` pins a version. v1 ships windows + linux.

-3. **Verify activation.** Re-run `spt adapter list`: `claude-spt` must now appear **active** (no

-   `deregistered`). Spot-check the profile resolves: `spt adapter get-string claude-spt:ccs adapter_label`

-   (the shipped overlay — `:ccs`). Report the active state.

+3. **Verify + set active.** Re-run `spt adapter list` — `claude-spt` must read **active** (no

+   `deregistered`). Then `spt adapter use claude-spt` so bare resolution lands here for the `claude`

+   host (the legacy-parity bare flow — `/sptc:live`/`/sptc:ready` need no `--adapter`). The

+   `claude-spt-digest` + `claude-spt-psyche` tools are invoked by bare name and resolve **from the

+   adapter install dir** (the `from …` path in `spt adapter list`), where activation extracted them —

+   no PATH copy needed. If either fails to start, confirm both are present in that dir (a packaging

-   Then **set the active-profile pointer** so bare resolution lands on this adapter for the `claude`

-   host binary (the legacy-parity bare flow — `/sptc:live` and `/sptc:ready` need no `--adapter`):

-   `spt adapter use claude-spt`. (With a single claude-hosting adapter registered this is the implicit

-   default, but setting it is explicit + durable. There is **no `:live` profile** — base claude-spt is

-   live-capable and the command decides ready vs live; reach for `--adapter claude-spt:ccs`

-   only to select the ccs override profile.)

-4. **Tool binaries — resolved from the install dir (REQ-INSTALL-11; no PATH copy).** The `[digest]`

-   extractor (`claude-spt-digest`) and the Psyche runner (`claude-spt-psyche`) are invoked by **bare

-   name**. spt-core resolves them **from the adapter install dir** — the `from …` path in

-   `spt adapter list` (e.g. `…/adapters/_github/<safe>/`), where `--release` activation already

-   extracted them beside the manifest. **Nothing to do here:** step 2 placed them; no PATH copy is

-   needed. Verified on spt **v0.8.1** — session-digest and the daemon-hosted Psyche both resolve the

-   binary straight from the install dir with nothing on PATH.

-   - *(The legacy F-006 interim PATH-copy step is **retired**: spt-core's install-dir resolution —

-     REQ-INSTALL-11, Feature B, landed in spt v0.8.0 — supersedes it. If session-digest or the Psyche

-     ever fails to start, confirm the two `.exe`s are present in the install dir above; their absence

-     is a packaging defect, not a PATH problem.)*

-5. **ccs wiring (optional — SCOPE setup #7).** Detect `~/.ccs`:

-   - **Present** → ccs is installed. The shipped **`claude-spt:ccs`** profile leaf-replaces the live

-     session command with `ccs` (a drop-in for `claude`), so live/ready agents can run on ccs's

-     configured backends (glm/kimi/custom from `~/.ccs/config.json`) instead of `claude`. Use it by

-     selecting the `:ccs` composite: e.g. `/sptc:live` / `/sptc:ready` under `--adapter claude-spt:ccs`,

-     or `spt endpoint run --adapter claude-spt:ccs`. Sanity-check `command -v ccs`; if `~/.ccs` exists

-     but `ccs` is not on PATH, point the user at their ccs install's bin dir. (No action needed if

-     they don't want ccs — base `claude-spt` is unaffected.)

-   - **Absent** → ccs is an optional CLI router that lets your spt sessions drive alternate model

-     backends (glm/kimi/custom) in place of `claude`. To enable: install ccs (see its docs), then

-     re-run `/sptc:setup`. Skip if not wanted.

+4. **ccs wiring (optional).** Detect `~/.ccs`:

+   - Present → the shipped `claude-spt:ccs` profile leaf-replaces the session command with `ccs` (a

+     drop-in for `claude`), so live/ready agents can run on ccs backends via `--adapter

+     claude-spt:ccs`. Check `command -v ccs`; if `~/.ccs` exists but `ccs` isn't on PATH, point the

+   - Absent → ccs is an optional CLI router for alternate model backends in place of `claude`. To

+     enable: install ccs, then re-run `/sptc:setup`. Skip if unwanted.

-6. **Subnet onboarding (optional — SCOPE setup #3/#4).** A **subnet** is the private group of paired

-   machines that makes `/sptc:send`, `/sptc:ready`, and live agents work **cross-machine** (local

-   single-machine use needs none). Check membership: `spt subnet status` (or bare `spt subnet`).

-   - **Already in a subnet** → report it. To invite another machine: `spt subnet show-code` (prints

-     the current 6-digit code + `otpauth://` URI + a terminal QR). On the joining machine run

-     `spt subnet join <name> --code <code>`.

-   - **Not in a subnet** → offer either: **create** the first one — `spt subnet create <name>` (this

-     node becomes the seed-holder; prints code/URI/QR) — or **join** an existing one —

-     `spt subnet join <name> --code <code>`. Skip if single-machine use is fine.

-   - Full verb guidance (status/create/show-code/join + lifecycle) lives in **/sptc:subnet** — route

-   - **Elevation:** `create`/`join`/`show-code` are **OS-elevation-gated** (seed-reveal /

-     machine-enrollment). Run where elevation can be granted: **Windows** → an elevated (UAC) shell;

-     **Linux desktop** → pkexec/polkit or a sudo-capable terminal; **Linux TTY** → inline `sudo`;

-     **headless / no-TTY** → print the exact command for the user to run elevated. (Automated

-     context-aware elevation is a deeper wave; today, surface the requirement + the exact command.)

+5. **Subnet onboarding (optional).** A subnet is the private group of paired machines that makes

+   `/sptc:send`, `/sptc:ready`, and live agents work cross-machine (local use needs none). Check

+   - In a subnet → invite a machine with `spt subnet show-code`; on the joiner, `spt subnet join`.

+   - Not in one → offer **create** (`spt subnet create` — this node becomes seed-holder) or **join**

+     (`spt subnet join`). Full verb guidance → **/sptc:subnet**.

+   - **Elevation:** create/join/show-code are OS-elevation-gated — Windows: elevated (UAC) shell;

+     Linux desktop: pkexec/polkit or sudo terminal; Linux TTY: inline sudo; headless: print the exact

+     command for the user to run elevated.

-After this initial bootstrap + activation, `spt update` handles signed self-updates automatically —

-the user does not run setup again. The whole flow is idempotent and safe to re-run.

+Idempotent and safe to re-run — the same bootstrap + activation the SessionStart hook performs.

# /sptc:setup — operative instructions

> Delivered file-backed via the `claude-spt` adapter `[strings]`
> (`[strings.skills].setup = { file = "skills/setup.md" }`), resolved at injection time. The cplugs
> SKILL.md stays a thin skeleton (ADR-0001).

**Goal:** install or repair spt-core for this session **and ACTIVATE the claude-spt adapter** — the
mid-session installer that covers the gap when no SessionStart bootstrap has fired (a user who
installs the plugin mid-session). Installing the binary is only half the job: a present binary with
a **deregistered** adapter has no profiles/strings/hints/`[digest]`, so `/sptc:*` injection has
nothing to source. Setup must leave the adapter **active**.

<!-- [doc->REQ-SETUP-ACTIVATE] -->

**Do this:**

1. **Binary.** Check whether spt-core is present: `command -v spt && spt --version`.
   - If absent, run the published install-on-demand bootstrap (verbatim against the spt-releases
     contract, `harness-contract/install-on-demand.md`):
     - **POSIX:** `curl -fsSL https://sabermage.github.io/spt-releases/install.sh | sh`
     - **Windows (PowerShell):** `irm https://sabermage.github.io/spt-releases/install.ps1 | iex`
   - `PATH` is not reloaded in the current shell after a fresh install — verify with the absolute
     path for the first call: `"$HOME/.local/bin/spt" --version` (POSIX). Report the version.

2. **Adapter activation (the step a present binary still needs).** Run `spt adapter list` and look
   for `claude-spt`:
   - If `claude-spt` is listed and **not** marked `deregistered` → the adapter is **active**; report
     "adapter active" and go to step 4.
   - If `claude-spt` is **missing or `deregistered`** → **activate** it. Pick the source:
     - **Local dev / dogfooding from a repo checkout** (an `adapter/claude-spt.toml` is present near
       cwd): `spt adapter add ./adapter/claude-spt.toml` (the file-form takes any path + filename).
     - **End-user (plugin only, no repo checkout):** the `.spt` asset carries native binaries, so it
       ships **per-OS** — select the one matching this host. Detect os + arch:
       ```sh
       os=$(uname -s);  case "$os" in MINGW*|MSYS*|CYGWIN*|Windows*) os=windows;; Linux) os=linux;; Darwin) os=macos;; esac
       arch=$(uname -m); case "$arch" in x86_64|amd64) arch=x86_64;; arm64|aarch64) arch=aarch64;; esac
       ```
       then `spt adapter add --release SaberMage/spt-claude-code --asset adapter-$os-$arch.spt` —
       fetches the per-OS `adapter-<os>-<arch>.spt` release asset (a tar whose **root** holds
       `manifest.toml` + `strings/` + the native tool binaries) from the repo's GitHub release,
       extracts it to the durable adapter home, and registers it. Add `--tag <ver>` to pin a version
       (omit for latest). Re-running with a newer `--tag` is a manual re-acquire. `adapter add` is
       manifest-first (an invalid manifest registers nothing). (v1 ships **windows + linux** assets.
       Recommended path — straight from the monorepo, no dedicated repo. Needs the spt release that
       carries `--release`; the older `--github <root-manifest-repo>` is the alternative.)
       <!-- [doc->REQ-DIST-ADAPTER-PEROS] -->

3. **Verify activation.** Re-run `spt adapter list`: `claude-spt` must now appear **active** (no
   `deregistered`). Spot-check the profile resolves: `spt adapter get-string claude-spt:ccs adapter_label`
   (the shipped overlay — `:ccs`). Report the active state.

   Then **set the active-profile pointer** so bare resolution lands on this adapter for the `claude`
   host binary (the legacy-parity bare flow — `/sptc:live` and `/sptc:ready` need no `--adapter`):
   `spt adapter use claude-spt`. (With a single claude-hosting adapter registered this is the implicit
   default, but setting it is explicit + durable. There is **no `:live` profile** — base claude-spt is
   live-capable and the command decides ready vs live; reach for `--adapter claude-spt:ccs`
   only to select the ccs override profile.)

4. **Tool binaries — resolved from the install dir (REQ-INSTALL-11; no PATH copy).** The `[digest]`
   extractor (`claude-spt-digest`) and the Psyche runner (`claude-spt-psyche`) are invoked by **bare
   name**. spt-core resolves them **from the adapter install dir** — the `from …` path in
   `spt adapter list` (e.g. `…/adapters/_github/<safe>/`), where `--release` activation already
   extracted them beside the manifest. **Nothing to do here:** step 2 placed them; no PATH copy is
   needed. Verified on spt **v0.8.1** — session-digest and the daemon-hosted Psyche both resolve the
   binary straight from the install dir with nothing on PATH.
   - *(The legacy F-006 interim PATH-copy step is **retired**: spt-core's install-dir resolution —
     REQ-INSTALL-11, Feature B, landed in spt v0.8.0 — supersedes it. If session-digest or the Psyche
     ever fails to start, confirm the two `.exe`s are present in the install dir above; their absence
     is a packaging defect, not a PATH problem.)*

5. **ccs wiring (optional — SCOPE setup #7).** Detect `~/.ccs`:
   - **Present** → ccs is installed. The shipped **`claude-spt:ccs`** profile leaf-replaces the live
     session command with `ccs` (a drop-in for `claude`), so live/ready agents can run on ccs's
     configured backends (glm/kimi/custom from `~/.ccs/config.json`) instead of `claude`. Use it by
     selecting the `:ccs` composite: e.g. `/sptc:live` / `/sptc:ready` under `--adapter claude-spt:ccs`,
     or `spt endpoint run --adapter claude-spt:ccs`. Sanity-check `command -v ccs`; if `~/.ccs` exists
     but `ccs` is not on PATH, point the user at their ccs install's bin dir. (No action needed if
     they don't want ccs — base `claude-spt` is unaffected.)
   - **Absent** → ccs is an optional CLI router that lets your spt sessions drive alternate model
     backends (glm/kimi/custom) in place of `claude`. To enable: install ccs (see its docs), then
     re-run `/sptc:setup`. Skip if not wanted.

   <!-- [doc->REQ-SETUP-CCS] -->

6. **Subnet onboarding (optional — SCOPE setup #3/#4).** A **subnet** is the private group of paired
   machines that makes `/sptc:send`, `/sptc:ready`, and live agents work **cross-machine** (local
   single-machine use needs none). Check membership: `spt subnet status` (or bare `spt subnet`).
   - **Already in a subnet** → report it. To invite another machine: `spt subnet show-code` (prints
     the current 6-digit code + `otpauth://` URI + a terminal QR). On the joining machine run
     `spt subnet join <name> --code <code>`.
   - **Not in a subnet** → offer either: **create** the first one — `spt subnet create <name>` (this
     node becomes the seed-holder; prints code/URI/QR) — or **join** an existing one —
     `spt subnet join <name> --code <code>`. Skip if single-machine use is fine.
   - Full verb guidance (status/create/show-code/join + lifecycle) lives in **/sptc:subnet** — route
     there rather than re-explaining.
   - **Elevation:** `create`/`join`/`show-code` are **OS-elevation-gated** (seed-reveal /
     machine-enrollment). Run where elevation can be granted: **Windows** → an elevated (UAC) shell;
     **Linux desktop** → pkexec/polkit or a sudo-capable terminal; **Linux TTY** → inline `sudo`;
     **headless / no-TTY** → print the exact command for the user to run elevated. (Automated
     context-aware elevation is a deeper wave; today, surface the requirement + the exact command.)

   <!-- [doc->REQ-SETUP-SUBNET] -->

After this initial bootstrap + activation, `spt update` handles signed self-updates automatically —
the user does not run setup again. The whole flow is idempotent and safe to re-run.


/grill-with-docs i noticed that the skills here are not well written. they're bloated with too much inessential information. please rewrite them all using the following references: -reference /write-a…


Update Claude-spt adapter configuration and flags


All 20 files rewritten + spec doc + DOCS-STRATEGY ref. Running gates.


Bash

command -v traceable-reqs >/dev/null 2>&1 && { traceable-reqs check >/tmp/tr.txt 2>&1; echo "traceable exit=$?"; grep -iE 'FAIL|error|missing|invalid' /tmp/tr.txt | head; }; echo "=== unit sweep ==="; pass=0; for t in tests/*.sh; do if sh "$t" >/dev/null 2>&1; then pass=$((pass+1)); else echo "FAIL $t"; sh "$t" 2>&1 | grep -iE 'fail|missing' | head -3; fi; done; echo "unit: $pass/9 ok"

Run traceable-reqs + unit sweep after skill rewrites


traceable exit=1
       Deterministic gates (shell-syntax + unit tests + traceable-reqs check + manifest-schema + docs-drift), each a binary pass/fail, runnable as one command
  [must] parse_error docs/SKILL-AUTHORING.md:55 — Tag-shaped token does not match [stage->REQ-ID]
  [must] parse_error docs/SKILL-AUTHORING.md:67 — Tag-shaped token does not match [stage->REQ-ID]
  [must] parse_error docs/SKILL-AUTHORING.md:92 — Tag-shaped token does not match [stage->REQ-ID]
=== unit sweep ===
unit: 9/9 ok


Scanner flags my doc's illustrative tags as real evidence (lines 55/67/92). Fix per the repo convention — angle-bracket the stage word so they read as examples. Locating them.


55:<!-- [doc->REQ-<…>] -->   # keep the traceability tag if this body is doc evidence
67:- **Keep `<!-- [doc->REQ-*] -->` tags** — they are traceability evidence; place them on/above the
92:- [ ] Traceability `[doc->REQ-*]` tags preserved.


Edit

<!-- [doc->REQ-<…>] -->   # keep the traceability tag if this body is doc evidence

<!-- [<doc>->REQ-NAME] -->   # keep the traceability tag if this body is doc evidence


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

# Skill authoring

> How `/sptc:*` skills are written in this repo. Skills live on **two surfaces** (ADR-0001's
> thin-skeleton split). Keep both lean: the plugin file is a stub, the adapter file is the operative
> instructions. Bloat — provenance notes, requirement ids, ADR/finding citations, rationale the
> running agent doesn't need — does not belong in either.

## The two surfaces

| Surface | File | Role | Audience |
|---|---|---|---|
| **Plugin skeleton** | `plugin/sptc/skills/<name>/SKILL.md` | Thin stub shipped on cplugs. Frontmatter `description` is the routing surface; body is a fixed note. | The model deciding *which* skill to load. |
| **Adapter body** | `adapter/strings/skills/<name>.md` | The operative instructions, UPS-injected at invocation from the adapter `[strings]`. | The agent *running* the skill. |

The plugin skeleton carries **no operative steps** — those are injected from the adapter body at call
time. The two never duplicate instructions.

## Plugin SKILL.md template

```md
---
name: <name>
description: |
  <One sentence: what it does.> Use when the user says "<trigger>", "<trigger>", or
  wants to <intent>.
argument-hint: "<args>"        # omit if none
allowed-tools: [Bash]          # the minimum the skill needs (Bash/Read/Write/Monitor)
---

# /sptc:<name>

> **Skeleton — thin by design.** Operative instructions for this skill are delivered by the
> `sptc` adapter at invocation time. Look out for the UserPromptSubmit additionalContext.
>
> **Operative.** If injection ever no-ops (spt absent / adapter unregistered), check
> SPT's installation status using the skill `sptc:setup`. Otherwise, avoid additional steps.

<One line naming what the skill does.>
```

The skeleton note above is **verbatim and identical** across every skill (except `setup` — see
below). Do not re-add ADR/finding/requirement citations to it.

## Adapter body template

```md
# /sptc:<name> — operative instructions

**Goal:** <one line — the outcome the agent is producing>.

**Do this:**

1. <step>
2. <step>
<!-- [doc->REQ-<…>] -->   # keep the traceability tag if this body is doc evidence
```

Rules for the body:

- **No provenance preamble.** Do not open with "Delivered file-backed via the adapter `[strings]`…"
  — the running agent does not need to know its own delivery mechanism.
- **Self-contained.** Inline the operative steps; do **not** redirect to `spt how-to <topic>`. (A
  verb's own `spt <verb> --help` is fine to cite as the live source of truth where the surface is
  large, e.g. `subnet`.)
- **Concise.** Commands, the must-do sequence, the reply/output shape — nothing else. Cut rationale,
  repeated warnings, and history.
- **Keep `<!-- [doc->REQ-*] -->` tags** — they are traceability evidence; place them on/above the
  real evidence.

## `description` rules (from write-a-skill)

The `description` is the only thing the model sees when choosing a skill. Per
`write-a-skill`: third person, **what it does** then **"Use when [triggers]"**, ≤1024 chars, no
time-sensitive info, consistent terms. Route phrases reference **`/sptc:`** (the shipped plugin
name; the `s/sptc/spt/` succession flip renames them later). The legacy `claude_skill_owl`
descriptions are the basis for the trigger phrasing — adapt them, dropping legacy internals
(`$OWL`/`$LIVE`/`info.json`).

## The `setup` exception

`setup` is **self-contained on both surfaces**: it runs precisely when spt-core may be **absent**,
so UPS-injection (which needs `spt adapter get-string`) can no-op. Its plugin SKILL.md therefore
keeps the operative steps as the floor, and the adapter body mirrors them for the spt-present repair
path. Tighten `setup` for concision, but do **not** reduce it to a stub.

## Checklist

- [ ] `description` is third-person, has "Use when …" triggers, routes via `/sptc:`.
- [ ] Plugin SKILL.md uses the verbatim skeleton note + one what-it-does line (except `setup`).
- [ ] Adapter body has no provenance preamble, is self-contained, ≤ ~40 lines (large surfaces aside).
- [ ] `allowed-tools` is the minimum the skill needs.
- [ ] Traceability `[doc->REQ-*]` tags preserved.

-<!-- [doc->REQ-<…>] -->   # keep the traceability tag if this body is doc evidence

+<!-- [<doc>->REQ-NAME] -->   # keep the traceability tag if this body is doc evidence


- **Keep `<!-- [doc->REQ-*] -->` tags** — they are traceability evidence; place them on/above the

- **Keep `[<doc>->REQ-*]` HTML-comment tags** — they are traceability evidence; place them on/above the


# Skill authoring

> How `/sptc:*` skills are written in this repo. Skills live on **two surfaces** (ADR-0001's
> thin-skeleton split). Keep both lean: the plugin file is a stub, the adapter file is the operative
> instructions. Bloat — provenance notes, requirement ids, ADR/finding citations, rationale the
> running agent doesn't need — does not belong in either.

## The two surfaces

| Surface | File | Role | Audience |
|---|---|---|---|
| **Plugin skeleton** | `plugin/sptc/skills/<name>/SKILL.md` | Thin stub shipped on cplugs. Frontmatter `description` is the routing surface; body is a fixed note. | The model deciding *which* skill to load. |
| **Adapter body** | `adapter/strings/skills/<name>.md` | The operative instructions, UPS-injected at invocation from the adapter `[strings]`. | The agent *running* the skill. |

The plugin skeleton carries **no operative steps** — those are injected from the adapter body at call
time. The two never duplicate instructions.

## Plugin SKILL.md template

```md
---
name: <name>
description: |
  <One sentence: what it does.> Use when the user says "<trigger>", "<trigger>", or
  wants to <intent>.
argument-hint: "<args>"        # omit if none
allowed-tools: [Bash]          # the minimum the skill needs (Bash/Read/Write/Monitor)
---

# /sptc:<name>

> **Skeleton — thin by design.** Operative instructions for this skill are delivered by the
> `sptc` adapter at invocation time. Look out for the UserPromptSubmit additionalContext.
>
> **Operative.** If injection ever no-ops (spt absent / adapter unregistered), check
> SPT's installation status using the skill `sptc:setup`. Otherwise, avoid additional steps.

<One line naming what the skill does.>
```

The skeleton note above is **verbatim and identical** across every skill (except `setup` — see
below). Do not re-add ADR/finding/requirement citations to it.

## Adapter body template

```md
# /sptc:<name> — operative instructions

**Goal:** <one line — the outcome the agent is producing>.

**Do this:**

1. <step>
2. <step>
<!-- [<doc>->REQ-NAME] -->   # keep the traceability tag if this body is doc evidence
```

Rules for the body:

- **No provenance preamble.** Do not open with "Delivered file-backed via the adapter `[strings]`…"
  — the running agent does not need to know its own delivery mechanism.
- **Self-contained.** Inline the operative steps; do **not** redirect to `spt how-to <topic>`. (A
  verb's own `spt <verb> --help` is fine to cite as the live source of truth where the surface is
  large, e.g. `subnet`.)
- **Concise.** Commands, the must-do sequence, the reply/output shape — nothing else. Cut rationale,
  repeated warnings, and history.
- **Keep `<!-- [doc->REQ-*] -->` tags** — they are traceability evidence; place them on/above the
  real evidence.

## `description` rules (from write-a-skill)

The `description` is the only thing the model sees when choosing a skill. Per
`write-a-skill`: third person, **what it does** then **"Use when [triggers]"**, ≤1024 chars, no
time-sensitive info, consistent terms. Route phrases reference **`/sptc:`** (the shipped plugin
name; the `s/sptc/spt/` succession flip renames them later). The legacy `claude_skill_owl`
descriptions are the basis for the trigger phrasing — adapt them, dropping legacy internals
(`$OWL`/`$LIVE`/`info.json`).

## The `setup` exception

`setup` is **self-contained on both surfaces**: it runs precisely when spt-core may be **absent**,
so UPS-injection (which needs `spt adapter get-string`) can no-op. Its plugin SKILL.md therefore
keeps the operative steps as the floor, and the adapter body mirrors them for the spt-present repair
path. Tighten `setup` for concision, but do **not** reduce it to a stub.

## Checklist

- [ ] `description` is third-person, has "Use when …" triggers, routes via `/sptc:`.
- [ ] Plugin SKILL.md uses the verbatim skeleton note + one what-it-does line (except `setup`).
- [ ] Adapter body has no provenance preamble, is self-contained, ≤ ~40 lines (large surfaces aside).
- [ ] `allowed-tools` is the minimum the skill needs.
- [ ] Traceability `[doc->REQ-*]` tags preserved.

-- **Keep `<!-- [doc->REQ-*] -->` tags** — they are traceability evidence; place them on/above the

+- **Keep `[<doc>->REQ-*]` HTML-comment tags** — they are traceability evidence; place them on/above the


- [ ] Traceability `[doc->REQ-*]` tags preserved.

- [ ] Traceability `[<doc>->REQ-*]` tags preserved.


# Skill authoring

> How `/sptc:*` skills are written in this repo. Skills live on **two surfaces** (ADR-0001's
> thin-skeleton split). Keep both lean: the plugin file is a stub, the adapter file is the operative
> instructions. Bloat — provenance notes, requirement ids, ADR/finding citations, rationale the
> running agent doesn't need — does not belong in either.

## The two surfaces

| Surface | File | Role | Audience |
|---|---|---|---|
| **Plugin skeleton** | `plugin/sptc/skills/<name>/SKILL.md` | Thin stub shipped on cplugs. Frontmatter `description` is the routing surface; body is a fixed note. | The model deciding *which* skill to load. |
| **Adapter body** | `adapter/strings/skills/<name>.md` | The operative instructions, UPS-injected at invocation from the adapter `[strings]`. | The agent *running* the skill. |

The plugin skeleton carries **no operative steps** — those are injected from the adapter body at call
time. The two never duplicate instructions.

## Plugin SKILL.md template

```md
---
name: <name>
description: |
  <One sentence: what it does.> Use when the user says "<trigger>", "<trigger>", or
  wants to <intent>.
argument-hint: "<args>"        # omit if none
allowed-tools: [Bash]          # the minimum the skill needs (Bash/Read/Write/Monitor)
---

# /sptc:<name>

> **Skeleton — thin by design.** Operative instructions for this skill are delivered by the
> `sptc` adapter at invocation time. Look out for the UserPromptSubmit additionalContext.
>
> **Operative.** If injection ever no-ops (spt absent / adapter unregistered), check
> SPT's installation status using the skill `sptc:setup`. Otherwise, avoid additional steps.

<One line naming what the skill does.>
```

The skeleton note above is **verbatim and identical** across every skill (except `setup` — see
below). Do not re-add ADR/finding/requirement citations to it.

## Adapter body template

```md
# /sptc:<name> — operative instructions

**Goal:** <one line — the outcome the agent is producing>.

**Do this:**

1. <step>
2. <step>
<!-- [<doc>->REQ-NAME] -->   # keep the traceability tag if this body is doc evidence
```

Rules for the body:

- **No provenance preamble.** Do not open with "Delivered file-backed via the adapter `[strings]`…"
  — the running agent does not need to know its own delivery mechanism.
- **Self-contained.** Inline the operative steps; do **not** redirect to `spt how-to <topic>`. (A
  verb's own `spt <verb> --help` is fine to cite as the live source of truth where the surface is
  large, e.g. `subnet`.)
- **Concise.** Commands, the must-do sequence, the reply/output shape — nothing else. Cut rationale,
  repeated warnings, and history.
- **Keep `[<doc>->REQ-*]` HTML-comment tags** — they are traceability evidence; place them on/above the
  real evidence.

## `description` rules (from write-a-skill)

The `description` is the only thing the model sees when choosing a skill. Per
`write-a-skill`: third person, **what it does** then **"Use when [triggers]"**, ≤1024 chars, no
time-sensitive info, consistent terms. Route phrases reference **`/sptc:`** (the shipped plugin
name; the `s/sptc/spt/` succession flip renames them later). The legacy `claude_skill_owl`
descriptions are the basis for the trigger phrasing — adapt them, dropping legacy internals
(`$OWL`/`$LIVE`/`info.json`).

## The `setup` exception

`setup` is **self-contained on both surfaces**: it runs precisely when spt-core may be **absent**,
so UPS-injection (which needs `spt adapter get-string`) can no-op. Its plugin SKILL.md therefore
keeps the operative steps as the floor, and the adapter body mirrors them for the spt-present repair
path. Tighten `setup` for concision, but do **not** reduce it to a stub.

## Checklist

- [ ] `description` is third-person, has "Use when …" triggers, routes via `/sptc:`.
- [ ] Plugin SKILL.md uses the verbatim skeleton note + one what-it-does line (except `setup`).
- [ ] Adapter body has no provenance preamble, is self-contained, ≤ ~40 lines (large surfaces aside).
- [ ] `allowed-tools` is the minimum the skill needs.
- [ ] Traceability `[doc->REQ-*]` tags preserved.

-- [ ] Traceability `[doc->REQ-*]` tags preserved.

+- [ ] Traceability `[<doc>->REQ-*]` tags preserved.


Re-running traceable + the docs-drift gate (new doc file may affect generated output):


Bash

command -v traceable-reqs >/dev/null 2>&1 && { traceable-reqs check >/tmp/tr.txt 2>&1; echo "traceable exit=$?"; grep -iE 'parse_error|FAIL|missing|invalid' /tmp/tr.txt | head; }; echo "=== docs-gen drift ==="; sh tests/docs-gen.sh 2>&1 | tail -3

Re-run traceable + docs drift gate


traceable exit=0
       Deterministic gates (shell-syntax + unit tests + traceable-reqs check + manifest-schema + docs-drift), each a binary pass/fail, runnable as one command
=== docs-gen drift ===
ok   has summary blockquote
ok   check-docs valid shell
DOCS-GEN OK


All green (traceable 0, docs-gen OK, unit 9/9). Final consistency sweep — no residual preambles or stray `/spt:` (non-sptc):


echo "=== residual 'Delivered file-backed' preambles? ==="; grep -rl 'Delivered file-backed' adapter/strings/skills/ || echo "NONE"
echo "=== stray /spt: (should be /sptc:) in skill files? ==="; grep -rnE '/spt:[a-z]' plugin/sptc/skills/ adapter/strings/skills/ | grep -v '/sptc:' || echo "NONE"
echo "=== adapter body first lines (registration-int prefix check) ==="; for f in ready commune force-stop live subnet; do head -1 adapter/strings/skills/$f.md; done
echo "=== sizes after ==="; wc -l adapter/strings/skills/*.md | tail -1; wc -l plugin/sptc/skills/*/SKILL.md | tail -1

Verify no residual preamble/stray prefix + body prefixes


=== residual 'Delivered file-backed' preambles? ===
NONE
=== stray /spt: (should be /sptc:) in skill files? ===
NONE
=== adapter body first lines (registration-int prefix check) ===
# /sptc:ready — operative instructions
# /sptc:commune — operative instructions
# /sptc:force-stop — operative instructions
# /sptc:live — operative instructions
# /sptc:subnet — operative instructions
=== sizes after ===
  244 total
  258 total


Clean: preambles gone, no stray `/spt:`, body prefixes satisfy registration-int. Adapter bodies 369→244 lines (−34%).

One correctness fix on your `live` reference: `allowed-tools: [Monitor, Read]` omits `Bash`, but the body runs `spt whoami` / `spt send` — adding Bash (the "minor edit" you allowed):


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

---
name: live
description: |
  Run a live agent session. For past sessions, restores a summarized context.

  EXPLICIT START phrases (route to /sptc:live <id>):
  - "live as"
  - "start live"
  - "go live"
  - "start a live agent"

  AUTO-RESUME phrases (route to /sptc:live --auto, resumes most-recently-active live agent):
  - continue live work
  - resume live work
  - continue live agent
  - resume live agent
  - live agent continue
  - live agent resume
  - live work continue
  - live work resume

  Does NOT route here (too ambiguous — require BOTH "live" AND ("agent" or "work")):
  - "keep going"
  - "resume work"
  - "continue" (bare)
argument-hint: "[<id>] [--auto]"
allowed-tools: [Monitor, Read]
---

# /sptc:live

> **Skeleton — thin by design.** Operative instructions for this skill are delivered by the
> `sptc` adapter at invocation time. Look out for the UserPromptSubmit additionalContext.
>
> **Operative.** If injection ever no-ops (spt absent / adapter unregistered), check
> SPT's installation status using the skill `sptc:setup`. Otherwise, avoid additional steps.

Upgrades THIS session to a LiveAgent (Psyche-backed).

- "resume work"
- "continue" (bare)
argument-hint: "[<id>] [--auto]"
-allowed-tools: [Monitor, Read]
+allowed-tools: [Bash, Monitor, Read]
---
# /sptc:live


Committing the rewrite.


git add plugin/sptc/skills/ adapter/strings/skills/ docs/SKILL-AUTHORING.md docs/DOCS-STRATEGY.md
git commit -q -F - <<'EOF'
docs(skills): rewrite all /sptc:* skills lean; add SKILL-AUTHORING.md

The skill files carried bloat the running agent never needs: provenance preambles
("Delivered file-backed via the adapter [strings]…"), ADR/finding/requirement
citations in skeleton notes, and `spt how-to <topic>` redirects instead of
self-contained steps.

Both surfaces reworked against a single convention:
- plugin/sptc/skills/<n>/SKILL.md — thin skeleton: the verbatim skeleton note +
  an enriched `description` (what + "Use when" triggers, /sptc: routing, adapted
  from the legacy claude_skill_owl descriptions).
- adapter/strings/skills/<n>.md — operative body: provenance preamble cut,
  self-contained (no how-to redirect), trimmed to commands + sequence + reply
  shape. Adapter bodies 369 -> 244 lines.

`setup` kept self-contained on both surfaces (it runs when spt may be absent, so
injection can no-op) — only tightened. Traceability [doc->REQ-*] tags preserved.
Fixed live: /spt: -> /sptc: routing phrases + added Bash to allowed-tools.

New docs/SKILL-AUTHORING.md captures the two-surface shape, templates, and rules
(referenced from docs/DOCS-STRATEGY.md). Based on /write-a-skill best practices.

Gates: traceable-reqs check green; 9/9 unit; docs-drift OK.

Co-authored by: perri
EOF
git log -1 --format='%h %s' && git push 2>&1 | tail -2

Commit + push skill rewrite


4aa9284 docs(skills): rewrite all /sptc:* skills lean; add SKILL-AUTHORING.md
To https://github.com/SaberMage/spt-claude-code.git
   ba43a89..4aa9284  main -> main


Done. Pushed `4aa9284`.

## Skill rewrite shipped
All 20 skill files + a convention doc, one consistent shape:

**Plugin skeletons** (`plugin/sptc/skills/*/SKILL.md`) — verbatim thin-by-design note (dropped the ADR-0001/0002/F-003 citations), enriched `description`s with "Use when" triggers adapted from legacy owl, `/sptc:` routing throughout.

**Adapter bodies** (`adapter/strings/skills/*.md`) — cut every "Delivered file-backed via the adapter `[strings]`…" preamble, killed the `spt how-to X` redirects (now self-contained), trimmed to commands + sequence + reply shape. **369 → 244 lines (−34%)**; `live` 82→55, `setup` 105→55.

**Exceptions/fixes:** `setup` kept self-contained both surfaces (runs when spt may be absent), only tightened. `live`: fixed `/spt:`→`/sptc:` routing + added `Bash` to allowed-tools (it runs `spt whoami`/`send`). All `[doc->REQ-*]` tags preserved.

**New `docs/SKILL-AUTHORING.md`** — the two-surface contract + templates + lean rules (from /write-a-skill), referenced in DOCS-STRATEGY.md.

Gates: traceable-reqs ✅ (fixed my doc's example tags tripping the scanner) · 9/9 unit · docs-drift ✅.

## Ship caveat
The adapter bodies are bundled into `dist/*.spt`. The shipped **v0.4.0** assets carry the *old bloated* bodies — these lean ones reach users only on the next `.spt` rebuild (same pattern as the psyche binary before v0.4.0).

Fold into a **v0.4.1** (rebuild + re-release both assets now), or hold for more changes?


more changes. some notes: -there was still too much information that a live agent simply doesn't need to know. for example, it doesn't need to know the inner workings of the plugin. see my changes to `skills/live.md`. -an excerpt from that skill, "On a session boundary, re-fire the same relay (`spt api listen <id>`) — the seed bridges the new session to the same perch." is simply not true. the relay persists across boundaries. -it was missing some style choices from legacy, like "« spt event »" for the Monitor name. --- please ground yourself in CONTEXT.md, observe the changes i made, and ripple them to other relevant docs.


6
7	## Bringup — do this
8
9	1. **Pick the perch id.** Use a short lowercase id from the user, or reuse this session's id from
10	   `spt whoami`. Call it `<id>`. SessionStart already seeded this session's perch — do not re-seed.
11	2. **Run the relay as a single PERSISTENT background task** via the **Monitor** tool. One resident
12	   process IS the live delivery pipe. The body is one bare command:
13
14	   ### Invocation (Monitor)
15
16	   Invoke `spt api listen <id>` via the Monitor tool with:
17	   - `command: "spt api listen <id>"`
18	   - `persistent: true`
19	   - `description: "« spt event »"`
20
21	   - `spt api listen` enters the poll loop inline; the stream stays alive across messages and emits
22	   one `<EVENT type="msg|alarm|echo_commune|init_signoff" ...>body</EVENT>` line per delivery.
23	   - It **blocks for the session's life**: backlog drains first, then each delivery streams to stdout.
24	3. **Readiness.** The relay output will show `BOUND:<id>`, then `READY:<id>`. Check it only if
25	   connectivity complications are encountered.
26	4. **Reply.** Inbound messages arrive as `<EVENT type="msg" from="<sender>">body</EVENT>` (body
27	   HTML-escaped, newlines `<br>`). To reply, pipe the message body as stdin to `spt send <sender-id>`.
28	5. **Across boundaries.** Use `/sptc:commune` to push a context delta after significant bodies of work.
29	   To go offline gracefully, use `/sptc:signoff`.
30
31	## Output — what the user sees
32
33	The relay emits machine markers (`BOUND:<id>`, `READY:<id>`, raw tokens). **Read them to drive
34	bringup; never echo them to the user.** The only user-facing surface is the LIVE block below — emit
35	it verbatim (substituting `<id>`), and nothing else from bringup:
36
37	```
38	**LIVE.** Now running as `<id>`.
39	- Reachable — other agents reach me with `/sptc:send <id>`.
40	- Inbound — messages arrive via the Monitor.
41	- Across resets — `/sptc:commune` before a `/clear`/`/compact`; `/sptc:signoff` to go offline.
42	```
43
44	If bringup fails, report a short plain-language failure and the likely cause (run `/sptc:setup`),
45	still without dumping the raw markers.
46	<!-- [doc->REQ-SKILL-LIVE] -->


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


more changes. some notes: -there was still too much information that a live agent simply doesn't need to know. for example, it doesn't need to know the inner workings of the plugin. see my changes to `skills/live.md`. -an excerpt from that skill, "On a session boundary, re-fire the same relay (`spt api listen <id>`) — the seed bridges the new session to the same perch." is simply not true. the relay persists across boundaries. -it was missing some style choices from legacy, like "« spt event »" for the Monitor name. --- note that we should not use skill body injection for `send,` `commune,` or `signoff`, so agents can know how to use them without the user invoking them directly. so their actual skills should have full-fat skill bodies. --- other skills should reference their `spt how-to` or `spt ... --help` equivalents so the agent can self-drive them, if they need to. --- please ground yourself in CONTEXT.md, observe the changes i made, and ripple similar + relevant changes to other skill docs.


Grounding in your changes + CONTEXT before rippling. Reading the live diffs and the glossary.


echo "=== commits since my rewrite ==="; git log --oneline 4aa9284..HEAD; echo "=== uncommitted? ==="; git status --short; echo "=== diff of live files since 4aa9284 ==="; git diff 4aa9284 -- plugin/sptc/skills/live/SKILL.md adapter/strings/skills/live.md

See user's changes to live skill files since my commit


=== commits since my rewrite ===
72e45c5 Edit for conciseness, remove unnecessary details
=== uncommitted? ===
=== diff of live files since 4aa9284 ===
diff --git a/adapter/strings/skills/live.md b/adapter/strings/skills/live.md
index d57c01c..40bec16 100644
--- a/adapter/strings/skills/live.md
+++ b/adapter/strings/skills/live.md
@@ -11,42 +11,36 @@ via commune deltas). This makes the session you are in right now live.
 2. **Run the relay as a single PERSISTENT background task** via the **Monitor** tool. One resident
    process IS the live delivery pipe. The body is one bare command:

-   ```sh
-   spt api listen <id>
-   ```
+   ### Invocation (Monitor)

-   - No `--adapter`, no `--manifest`, no seed step. `spt api listen` resolves the owning adapter from
-     the seed's parent pid and stamps the perch `state=live_agent`, which tells the daemon to host
-     the Psyche.
+   Invoke `spt api listen <id>` via the Monitor tool with:
+   - `command: "spt api listen <id>"`
+   - `persistent: true`
+   - `description: "« spt event »"`
+
+   - `spt api listen` enters the poll loop inline; the stream stays alive across messages and emits
+   one `<EVENT type="msg|alarm|echo_commune|init_signoff" ...>body</EVENT>` line per delivery.
    - It **blocks for the session's life**: backlog drains first, then each delivery streams to stdout.
-   - Do **not** use `--once` — it drains and forwards a single delivery then exits; it never sustains
-     a live session.
-3. **Readiness.** Watch the relay output for `BOUND:<id>` then `READY:<id>`. Only once `READY:<id>`
-   appears is the pipe up — do not announce LIVE before then.
-4. **Single pipe.** While the relay is up it is the *only* delivery path — the `UserPromptSubmit`
-   `api poll` hook no-ops and resumes only if the relay goes down.
-5. **Reply.** Inbound arrives as `<EVENT type="msg" from="<sender>">body</EVENT>` (body
-   HTML-escaped, newlines `<br>`). To reply, pipe the body to `spt send --reply-to <sender>`.
-6. **Across boundaries.** Use `/sptc:commune` to push a context delta before a `/clear` or compact.
-   On a session boundary, re-fire the same relay (`spt api listen <id>`) — the seed bridges the new
-   session to the same perch. To go offline gracefully (tears the Psyche down), use `/sptc:force-stop`.
+3. **Readiness.** The relay output will show `BOUND:<id>`, then `READY:<id>`. Check it only if
+   connectivity complications are encountered.
+4. **Reply.** Inbound messages arrive as `<EVENT type="msg" from="<sender>">body</EVENT>` (body
+   HTML-escaped, newlines `<br>`). To reply, pipe the message body as stdin to `spt send <sender-id>`.
+5. **Across boundaries.** Use `/sptc:commune` to push a context delta after significant bodies of work.
+   To go offline gracefully, use `/sptc:signoff`.

 ## Output — what the user sees

 The relay emits machine markers (`BOUND:<id>`, `READY:<id>`, raw tokens). **Read them to drive
 bringup; never echo them to the user.** The only user-facing surface is the LIVE block below — emit
-it verbatim (substituting `<id>`) once `READY:<id>` is observed, and nothing else from bringup:
+it verbatim (substituting `<id>`), and nothing else from bringup:

 ```
-**LIVE.** Session `<id>` is now a LiveAgent (Psyche-backed).
-- Perch `<id>` — status online; Psyche companion hosted by the daemon.
-- Reachable — other agents reach you with `/sptc:send <id>`.
-- Inbound — streams into this session live via the Monitor relay.
-- Reply — pipe a reply body to `spt send --reply-to <sender>`.
-- Across resets — `/sptc:commune` before a `/clear`/compact; `/sptc:force-stop` to go offline.
+**LIVE.** Now running as `<id>`.
+- Reachable — other agents reach me with `/sptc:send <id>`.
+- Inbound — messages arrive via the Monitor.
+- Across resets — `/sptc:commune` before a `/clear`/`/compact`; `/sptc:signoff` to go offline.
 ```

-If bringup fails (no `READY:<id>` within ~25s), do NOT show the LIVE block — report a short
-plain-language failure and the likely cause (run `/sptc:setup`, or confirm spt-core ≥ 0.9.0), still
-without dumping the raw markers.
+If bringup fails, report a short plain-language failure and the likely cause (run `/sptc:setup`),
+still without dumping the raw markers.
 <!-- [doc->REQ-SKILL-LIVE] -->


more changes. some notes: -there was still too much information that a live agent simply doesn't need to know. for example, it doesn't need to know the inner workings of the plugin. see my changes to…


Their live.md edits are clear — key signals:
1. **Cut plumbing** (`--adapter`/seed/parent-pid resolution, `state=live_agent`, `--once`, daemon-hosting) — agent doesn't need it.
2. **Legacy Monitor style restored**: `description: "« spt event »"` + the `<EVENT type=...>` envelope catalog.
3. **Removed the false** "re-fire relay / seed bridges new session" — relay persists.
4. Reply via `spt send <sender-id>`; offline via `/sptc:signoff` (not force-stop).

Before rippling — the full-fat-3 change touches the manifest + ints + traceability, and I must verify `how-to`/`--help` anchors actually exist (public-surface rule). Investigating.


echo "=== spt how-to topics ==="; spt how-to 2>&1 | head -40; echo "EXIT=$?"

List available spt how-to topics


=== spt how-to topics ===
Topics (`spt how-to <topic>`):
  ready   receive messages: listener guidance + the --once fallback loop
  send    deliver messages: send vs ring, replies, SENT vs QUEUED
  subnet  pair machines: create vs join, the 6-digit code, reaching remote agents
  live    run as a live agent: the persistent listen relay, --once is NOT it, the Psyche seam
EXIT=0


1	---
2	name: live
3	description: |
4	  Run a live agent session. For past sessions, restores a summarized context.
5
6	  EXPLICIT START phrases (route to /sptc:live <id>):
7	  - "live as"
8	  - "start live"
9	  - "go live"
10	  - "start a live agent"
11
12	  AUTO-RESUME phrases (route to /sptc:live --auto, resumes most-recently-active live agent):
13	  - continue live work
14	  - resume live work
15	  - continue live agent
16	  - resume live agent
17	  - live agent continue
18	  - live agent resume
19	  - live work continue
20	  - live work resume
21
22	  Does NOT route here (too ambiguous — require BOTH "live" AND ("agent" or "work")):
23	  - "keep going"
24	  - "resume work"
25	  - "continue" (bare)
26	argument-hint: "[<id>] [--auto]"
27	allowed-tools: [Bash, Monitor, Read]
28	---
29
30	# /sptc:live
31
32	> **Skeleton — thin by design.** Operative instructions for this skill are delivered by the
33	> `sptc` adapter at invocation time. Look out for the UserPromptSubmit additionalContext.
34	>
35	> **Operative.** If injection ever no-ops (spt absent / adapter unregistered), check
36	> SPT's installation status using the skill `sptc:setup`. Otherwise, avoid additional steps.
37
38	Upgrades THIS session to a LiveAgent (Psyche-backed).
39

---
name: live
description: |
  Run a live agent session. For past sessions, restores a summarized context.

  EXPLICIT START phrases (route to /sptc:live <id>):
  - "live as"
  - "start live"
  - "go live"
  - "start a live agent"

  AUTO-RESUME phrases (route to /sptc:live --auto, resumes most-recently-active live agent):
  - continue live work
  - resume live work
  - continue live agent
  - resume live agent
  - live agent continue
  - live agent resume
  - live work continue
  - live work resume

  Does NOT route here (too ambiguous — require BOTH "live" AND ("agent" or "work")):
  - "keep going"
  - "resume work"
  - "continue" (bare)
argument-hint: "[<id>] [--auto]"
allowed-tools: [Bash, Monitor, Read]
---

# /sptc:live

> **Skeleton — thin by design.** Operative instructions for this skill are delivered by the
> `sptc` adapter at invocation time. Look out for the UserPromptSubmit additionalContext.
>
> **Operative.** If injection ever no-ops (spt absent / adapter unregistered), check
> SPT's installation status using the skill `sptc:setup`. Otherwise, avoid additional steps.

Upgrades THIS session to a LiveAgent (Psyche-backed).


1	# shellcheck shell=sh
2	# sptc hook common helpers — sourced by each hook wrapper.
3	# DRAFT (pending throwaway-CC validation: Windows-shell, env-file timing, whoami-in-hook).
4	# spt-core is harness-agnostic; this is the CC adapter glue that maps CC hook input -> `spt api`.
5
6	ADAPTER=claude-spt
7
8	# CC spills additionalContext over ~10,000 chars to a file (dropping it from the inline context the
9	# agent sees). We pre-empt below this with margin for the marker + CC's own framing. Override-able
10	# for tests. (ADR-0002 Open #2.)
11	SPTC_CTX_CAP="${SPTC_CTX_CAP:-9000}"
12
13	# Resolve the spt binary: PATH first (post-bootstrap), then known install locations.
14	spt_bin() {
15	  if command -v spt >/dev/null 2>&1; then printf 'spt'; return 0; fi
16	  for p in \
17	    "$HOME/.local/bin/spt" \
18	    "$LOCALAPPDATA/spt-core/bin/spt.exe" \
19	    "$HOME/AppData/Local/spt-core/bin/spt.exe"; do
20	    [ -x "$p" ] && { printf '%s' "$p"; return 0; }
21	  done
22	  printf 'spt'  # last resort; caller tolerates failure
23	}
24
25	# Extract a top-level string field from a flat JSON object on stdin payload ($1=json, $2=key).
26	# CC hook input is a flat object for the fields we need (session_id, source, prompt, agent_id).
27	json_str() {
28	  printf '%s' "$1" | sed -n "s/.*\"$2\"[[:space:]]*:[[:space:]]*\"\([^\"]*\)\".*/\1/p" | head -n1
29	}
30
31	# Decide the SessionStart registration verb for this spawn ($1 = CC hook `source`; reads env
32	# $SPT_ENDPOINT_ID). Pure — no spt/CC. [impl->REQ-DIST-SHORTCUT-BASENAME]
33	#   boundary — a /clear or /compact within a live session (rebind the perch to the new session id)
34	#   bind     — spt-hosted: `spt endpoint run` spawned us via [session.self] + injected the endpoint
35	#              id into $SPT_ENDPOINT_ID; the perch already exists, self-register post-spawn
36	#   seed     — harness-hosted: user-launched CC; record an ephemeral seed for /sptc:ready|live
37	sptc_register_verb() {
38	  case "$1" in
39	    clear|compact) printf boundary ;;
40	    *) if [ -n "${SPT_ENDPOINT_ID:-}" ]; then printf bind; else printf seed; fi ;;
41	  esac
42	}
43
44	# Resolve this session's perch id via spt whoami (off $OWL_SESSION_ID / $SPT_AGENT_ID).
45	# Empty => no perch yet (session never readied) => caller no-ops.
46	sptc_self_id() {
47	  _sid="$1"; _spt="$(spt_bin)"
48	  OWL_SESSION_ID="${OWL_SESSION_ID:-$_sid}" "$_spt" whoami 2>/dev/null | head -n1
49	}
50
51	# Decode an spt envelope body to plain text: literal `<br>` -> newline, then HTML entities
52	# (< > " then & LAST, to avoid double-decoding). Exactly the live-agent
53	# body-parsing rule (spt-proto::event, ADR-0001 grammar).
54	sptc_unescape() {
55	  printf '%s' "$1" | sed \
56	    -e 's/
/\
57	/g' \
58	    -e 's/</</g' -e 's/>/>/g' -e 's/"/"/g' -e 's/&/\&/g'
59	}
60
61	# Render an `api poll` drain ($1) for CC. Canonical format: every message is a
62	# self-delimiting `<EVENT type="msg" from="<sender>">body</EVENT>` envelope (spt-proto::event) —
63	# the same grammar the live listener emits. Multi-message drains split cleanly on `</EVENT>`.
64	# Sender is preserved as `from=` (reply-correlation). NOTE: targets canonical <EVENT>; the current
65	# 0.6.0 binary still emits a `__REPLY_TO__` relic at the poll surface until the REQ-MSG-ENVELOPE
66	# refactor lands — finalize/validate against poll only post-refactor. [unit->REQ-UPS-INJECTION]
67	render_frames() {
68	  _in="$1"
69	  [ -z "$_in" ] && return 0
70	  # Normalise to one <EVENT>…</EVENT> per line (body newlines are
-escaped, so each envelope
71	  # is single-line), then parse each.
72	  printf '%s' "$_in" | sed 's#</EVENT>#</EVENT>\
73	#g' | while IFS= read -r _ev; do
74	    case "$_ev" in
75	      *"<EVENT"*"</EVENT>"*) ;;
76	      *) continue ;;
77	    esac
78	    _sender=$(printf '%s' "$_ev" | sed -n 's/.*<EVENT[^>]* from="\([^"]*\)".*/\1/p')
79	    _raw=$(printf '%s' "$_ev" | sed -n 's#.*<EVENT[^>]*>\(.*\)</EVENT>.*#\1#p')
80	    _body=$(sptc_unescape "$_raw")
81	    if [ -n "$_sender" ]; then
82	      printf '<sptc_messages from="%s">\n%s\n</sptc_messages>\n' "$_sender" "$_body"
83	    else
84	      printf '<sptc_messages>\n%s\n</sptc_messages>\n' "$_body"
85	    fi
86	  done
87	}
88
89	# Extract the skill name from a `/sptc:<skill>` slash-command prompt ($1=prompt). UPS fires on a
90	# slash-command with the token intact (ADR-0002 validation 2026-06-15: `prompt:"/sptc:send doyle"`),
91	# so the wrapper detects the command here. Leading-only (after optional whitespace) to avoid firing
92	# on prose that merely mentions `/sptc:x` mid-sentence. Empty => not a sptc slash-command.
93	# [unit->REQ-UPS-INJECTION]
94	sptc_skill_key() {
95	  printf '%s' "$1" | sed -n 's#^[[:space:]]*/sptc:\([a-z][a-z0-9-]*\).*#\1#p' | head -n1
96	}
97
98	# Inject a skill's operative instructions ($1=skill name) as additionalContext. Resolves the
99	# file-backed/inline body from the adapter `[strings.skills].<skill>` via `spt adapter get-string`
100	# (F-003: pointer values resolve to file contents at read time). No-op (silent) if spt is absent,
101	# the adapter is unregistered, or the key is unset — the thin SKILL.md skeleton still loaded by CC
102	# is the floor. The injected body is what the agent follows for this `/sptc:<skill>` invocation.
103	# [impl->REQ-UPS-INJECTION]
104	sptc_inject_skill() {
105	  _skill="$1"; [ -z "$_skill" ] && return 0
106	  _spt="$(spt_bin)"
107	  _body=$("$_spt" adapter get-string "$ADAPTER" "skills.$_skill" 2>/dev/null) || return 0
108	  [ -z "$_body" ] && return 0
109	  printf '<sptc_skill name="%s">\n%s\n</sptc_skill>\n' "$_skill" "$_body"
110	}
111
112	# Emit additionalContext under CC's ~10k spill threshold ($1=text, $2=cap, $3=spill_path). Under the
113	# cap -> emit as-is. Over -> spill the FULL text to a file the agent can Read and emit ONLY a concise
114	# pointer marker (never a partial inline — a head-cut would split a <sptc_messages>/<EVENT> block and
115	# lose a message silently). The agent reads the spill file to see everything; nothing is dropped. CC
116	# would otherwise spill oversized additionalContext itself, evicting it from the inline context.
117	# [impl->REQ-UPS-INJECTION]
118	sptc_cap_output() {
119	  _text="$1"; _cap="$2"; _spill="$3"
120	  [ -z "$_text" ] && return 0
121	  _len=$(printf '%s' "$_text" | wc -c | tr -d ' ')
122	  if [ "$_len" -le "$_cap" ]; then
123	    printf '%s' "$_text"
124	    return 0
125	  fi
126	  printf '%s' "$_text" > "$_spill" 2>/dev/null || _spill="(spill failed; content too large to inline)"
127	  printf '<sptc_overflow bytes="%s" cap="%s" spilled_to="%s">\nDelivery exceeded CC'\''s additionalContext cap. The full content (skill instructions and/or %s message bytes) was written to the file above — read it now to see everything; it is NOT inlined here to avoid silently dropping a message.\n</sptc_overflow>\n' \
128	    "$_len" "$_cap" "$_spill" "$_len"
129	}
130

# shellcheck shell=sh
# sptc hook common helpers — sourced by each hook wrapper.
# DRAFT (pending throwaway-CC validation: Windows-shell, env-file timing, whoami-in-hook).
# spt-core is harness-agnostic; this is the CC adapter glue that maps CC hook input -> `spt api`.

ADAPTER=claude-spt

# CC spills additionalContext over ~10,000 chars to a file (dropping it from the inline context the
# agent sees). We pre-empt below this with margin for the marker + CC's own framing. Override-able
# for tests. (ADR-0002 Open #2.)
SPTC_CTX_CAP="${SPTC_CTX_CAP:-9000}"

# Resolve the spt binary: PATH first (post-bootstrap), then known install locations.
spt_bin() {
  if command -v spt >/dev/null 2>&1; then printf 'spt'; return 0; fi
  for p in \
    "$HOME/.local/bin/spt" \
    "$LOCALAPPDATA/spt-core/bin/spt.exe" \
    "$HOME/AppData/Local/spt-core/bin/spt.exe"; do
    [ -x "$p" ] && { printf '%s' "$p"; return 0; }
  done
  printf 'spt'  # last resort; caller tolerates failure
}

# Extract a top-level string field from a flat JSON object on stdin payload ($1=json, $2=key).
# CC hook input is a flat object for the fields we need (session_id, source, prompt, agent_id).
json_str() {
  printf '%s' "$1" | sed -n "s/.*\"$2\"[[:space:]]*:[[:space:]]*\"\([^\"]*\)\".*/\1/p" | head -n1
}

# Decide the SessionStart registration verb for this spawn ($1 = CC hook `source`; reads env
# $SPT_ENDPOINT_ID). Pure — no spt/CC. [impl->REQ-DIST-SHORTCUT-BASENAME]
#   boundary — a /clear or /compact within a live session (rebind the perch to the new session id)
#   bind     — spt-hosted: `spt endpoint run` spawned us via [session.self] + injected the endpoint
#              id into $SPT_ENDPOINT_ID; the perch already exists, self-register post-spawn
#   seed     — harness-hosted: user-launched CC; record an ephemeral seed for /sptc:ready|live
sptc_register_verb() {
  case "$1" in
    clear|compact) printf boundary ;;
    *) if [ -n "${SPT_ENDPOINT_ID:-}" ]; then printf bind; else printf seed; fi ;;
  esac
}

# Resolve this session's perch id via spt whoami (off $OWL_SESSION_ID / $SPT_AGENT_ID).
# Empty => no perch yet (session never readied) => caller no-ops.
sptc_self_id() {
  _sid="$1"; _spt="$(spt_bin)"
  OWL_SESSION_ID="${OWL_SESSION_ID:-$_sid}" "$_spt" whoami 2>/dev/null | head -n1
}

# Decode an spt envelope body to plain text: literal `<br>` -> newline, then HTML entities
# (< > " then & LAST, to avoid double-decoding). Exactly the live-agent
# body-parsing rule (spt-proto::event, ADR-0001 grammar).
sptc_unescape() {
  printf '%s' "$1" | sed \
    -e 's/
/\
/g' \
    -e 's/</</g' -e 's/>/>/g' -e 's/"/"/g' -e 's/&/\&/g'
}

# Render an `api poll` drain ($1) for CC. Canonical format: every message is a
# self-delimiting `<EVENT type="msg" from="<sender>">body</EVENT>` envelope (spt-proto::event) —
# the same grammar the live listener emits. Multi-message drains split cleanly on `</EVENT>`.
# Sender is preserved as `from=` (reply-correlation). NOTE: targets canonical <EVENT>; the current
# 0.6.0 binary still emits a `__REPLY_TO__` relic at the poll surface until the REQ-MSG-ENVELOPE
# refactor lands — finalize/validate against poll only post-refactor. [unit->REQ-UPS-INJECTION]
render_frames() {
  _in="$1"
  [ -z "$_in" ] && return 0
  # Normalise to one <EVENT>…</EVENT> per line (body newlines are
-escaped, so each envelope
  # is single-line), then parse each.
  printf '%s' "$_in" | sed 's#</EVENT>#</EVENT>\
#g' | while IFS= read -r _ev; do
    case "$_ev" in
      *"<EVENT"*"</EVENT>"*) ;;
      *) continue ;;
    esac
    _sender=$(printf '%s' "$_ev" | sed -n 's/.*<EVENT[^>]* from="\([^"]*\)".*/\1/p')
    _raw=$(printf '%s' "$_ev" | sed -n 's#.*<EVENT[^>]*>\(.*\)</EVENT>.*#\1#p')
    _body=$(sptc_unescape "$_raw")
    if [ -n "$_sender" ]; then
      printf '<sptc_messages from="%s">\n%s\n</sptc_messages>\n' "$_sender" "$_body"
    else
      printf '<sptc_messages>\n%s\n</sptc_messages>\n' "$_body"
    fi
  done
}

# Extract the skill name from a `/sptc:<skill>` slash-command prompt ($1=prompt). UPS fires on a
# slash-command with the token intact (ADR-0002 validation 2026-06-15: `prompt:"/sptc:send doyle"`),
# so the wrapper detects the command here. Leading-only (after optional whitespace) to avoid firing
# on prose that merely mentions `/sptc:x` mid-sentence. Empty => not a sptc slash-command.
# [unit->REQ-UPS-INJECTION]
sptc_skill_key() {
  printf '%s' "$1" | sed -n 's#^[[:space:]]*/sptc:\([a-z][a-z0-9-]*\).*#\1#p' | head -n1
}

# Inject a skill's operative instructions ($1=skill name) as additionalContext. Resolves the
# file-backed/inline body from the adapter `[strings.skills].<skill>` via `spt adapter get-string`
# (F-003: pointer values resolve to file contents at read time). No-op (silent) if spt is absent,
# the adapter is unregistered, or the key is unset — the thin SKILL.md skeleton still loaded by CC
# is the floor. The injected body is what the agent follows for this `/sptc:<skill>` invocation.
# [impl->REQ-UPS-INJECTION]
sptc_inject_skill() {
  _skill="$1"; [ -z "$_skill" ] && return 0
  _spt="$(spt_bin)"
  _body=$("$_spt" adapter get-string "$ADAPTER" "skills.$_skill" 2>/dev/null) || return 0
  [ -z "$_body" ] && return 0
  printf '<sptc_skill name="%s">\n%s\n</sptc_skill>\n' "$_skill" "$_body"
}

# Emit additionalContext under CC's ~10k spill threshold ($1=text, $2=cap, $3=spill_path). Under the
# cap -> emit as-is. Over -> spill the FULL text to a file the agent can Read and emit ONLY a concise
# pointer marker (never a partial inline — a head-cut would split a <sptc_messages>/<EVENT> block and
# lose a message silently). The agent reads the spill file to see everything; nothing is dropped. CC
# would otherwise spill oversized additionalContext itself, evicting it from the inline context.
# [impl->REQ-UPS-INJECTION]
sptc_cap_output() {
  _text="$1"; _cap="$2"; _spill="$3"
  [ -z "$_text" ] && return 0
  _len=$(printf '%s' "$_text" | wc -c | tr -d ' ')
  if [ "$_len" -le "$_cap" ]; then
    printf '%s' "$_text"
    return 0
  fi
  printf '%s' "$_text" > "$_spill" 2>/dev/null || _spill="(spill failed; content too large to inline)"
  printf '<sptc_overflow bytes="%s" cap="%s" spilled_to="%s">\nDelivery exceeded CC'\''s additionalContext cap. The full content (skill instructions and/or %s message bytes) was written to the file above — read it now to see everything; it is NOT inlined here to avoid silently dropping a message.\n</sptc_overflow>\n' \
    "$_len" "$_cap" "$_spill" "$_len"
}


when you think you know the "why" behind each of my edits, please share the reasons you perceive so we can confirm we're on the same page.


Critical findings: `spt how-to` exists for **ready, send, subnet, live** only (not list-agents/version/force-stop/commune/signoff → those use `--help`). And `sptc_inject_skill` **no-ops gracefully** when a manifest `[strings.skills]` entry is absent — so dropping send/commune/signoff from the manifest cleanly disables their injection; the full-fat SKILL.md becomes the carrier. No hook change needed.

Grounding in CONTEXT + checking what the full-fat-3 change ripples into (manifest, ints, traceability).


1	# spt-claude-code — glossary
2
3	> Authoritative for meaning (grill-with-docs convention). Glossary only — no
4	> implementation detail. Decisions/rationale live in `SCOPE.md` and `docs/adr/`.
5
6	**spt-claude-code** — the rebuilt Claude Code harness adapter. The `claude-spt`
7	adapter in spt-core terms. Simultaneously spt-core's v1 acceptance proof (legacy
8	parity), its first casual-end-user entrypoint (a CC plugin), and an invisible spt-core
9	installer. Built by maintainer perri from the public spt-releases surface only.
10
11	**claude-spt** — the adapter_name spt-claude-code registers under (rides every `api`
12	invocation + the manifest). The CC adapter's identity inside spt-core.
13
14	**legacy spt / `claude_skill_owl`** — the sister project; today's shipped CC integration
15	(owl.exe + `spt` plugin, v1.11.25). The parity *target* (user-facing features), not a
16	1:1 port — most of its machinery now lives in spt.exe.
17
18	**skeleton plugin** — the thin marketplace artifact on `SaberMage/cplugs`: namespaced
19	`/spt:*` skill stubs + hooks + a SessionStart bootstrap that installs spt-core. Low-churn;
20	the volatile bulk (binary + manifest) is spt-core-conducted, not in the plugin.
21
22	**fetch-stub skill** — a `/spt:X` SKILL.md that is a 2-line stub fetching its real
23	instructions at runtime from the adapter `[strings]` (`spt adapter get-string`/`skill-help`).
24	Keeps skill files static while instructions update via spt-core. Distinct from a `[hints]`
25	entry (proactive, keyword-triggered, UPS-hook-delivered).
26
27	**ccs profile** — a profile under spt-claude-code (`claude-spt:glm`, `claude-spt:kimi`)
28	that leaf-replaces the launch command + history/digest log dir to use the `ccs` backend.
29	NOT its own adapter — ccs is structurally Claude Code.
30
31	**`cc` launcher (capsule-style)** — a generated `cc`/`cc <id>` script at project root that
32	spawns-or-attaches a CC endpoint via spt-core's spt-hosted topology (broker PTY + inject +
33	attach). The spt-core realization of legacy's unbuilt "Capsule" milestone. _Avoid_: equating
34	it with psmux/sendkeys — spt-core's broker is the terminal host.
35
36	**Psyche** — a LiveAgent's detached *companion* process. When a session goes live
37	(`/sptc:live`), spt-core's daemon hosts a Psyche alongside it: the Psyche owns its own
38	perch (`<parent>-psyche`), is woken by daemon *pulses*, and on each pulse authors a
39	*commune*. It never replies or notifies (that is the echo-commune, a different actor) and
40	exits at session end. A *ready* agent has no Psyche — live-vs-ready is the command, not a
41	profile. (Realized here by the `claude-spt-psyche` runner.)
42
43	**commune** — the context-delta a Psyche writes on each pulse: a brief that lets the
44	parent agent resume coherently after a context wipe (`/clear` / compact). A file-drop the
45	daemon ingests, not an `api` verb.
46
47	**psyche sandbox** — the constrained surface a Psyche's `claude` turns run under:
48	Read/Edit/Write tools only, slash-commands disabled, permissions auto-approved, cheap
49	pinned model. Deliberately narrower than the parent agent (which is unconstrained). Mirrors
50	legacy owl's psyche box; see `docs/adr/0003-*`.
51
52	**casual end user** — a user who *uses* an spt-powered system mostly-invisibly, vs the
53	adapter/shell *developer* who is spt-core's nominal target. spt-claude-code serves casual
54	users: install the plugin, get spt-core for free.
55
56	**experimplate** — the standalone reusable project-workflow template (its own sibling repo)
57	extracted from spt-core's working style. spt-claude-code is its first consumer. Carries
58	traceable-reqs gating, JIT plans, grill-with-docs scaffolding, release/changelog, and
59	same-repo published-docs. Defined in its own folder, not here.
60

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

**Psyche** — a LiveAgent's detached *companion* process. When a session goes live
(`/sptc:live`), spt-core's daemon hosts a Psyche alongside it: the Psyche owns its own
perch (`<parent>-psyche`), is woken by daemon *pulses*, and on each pulse authors a
*commune*. It never replies or notifies (that is the echo-commune, a different actor) and
exits at session end. A *ready* agent has no Psyche — live-vs-ready is the command, not a
profile. (Realized here by the `claude-spt-psyche` runner.)

**commune** — the context-delta a Psyche writes on each pulse: a brief that lets the
parent agent resume coherently after a context wipe (`/clear` / compact). A file-drop the
daemon ingests, not an `api` verb.

**psyche sandbox** — the constrained surface a Psyche's `claude` turns run under:
Read/Edit/Write tools only, slash-commands disabled, permissions auto-approved, cheap
pinned model. Deliberately narrower than the parent agent (which is unconstrained). Mirrors
legacy owl's psyche box; see `docs/adr/0003-*`.

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


echo "=== traceable refs to send/commune/signoff ==="; grep -niE 'signoff|commune|skills\.send|/sptc:send' traceable-reqs.toml | head
echo "=== registration-int skill assertions ==="; grep -nE 'skills\.|get-string claude-spt skills' ci/manifest/registration-int.sh
echo "=== manifest [strings.skills] entries ==="; grep -nE '^(setup|ready|send|version|signoff|list-agents|commune|force-stop|subnet|live) =' adapter/claude-spt.toml

Ground: CONTEXT + traceability/int/manifest refs to the 3 full-fat skills


=== traceable refs to send/commune/signoff ===
176:required_stages = ["doc", "int"]  # doc: adapter/strings/skills/subnet.md (one /sptc:subnet skill covering status/create/show-code/join — mirrors the single `spt subnet` verb-family CLI). int: ci/manifest/registration-int.sh file-backed-resolve assertion (skills.subnet -> body) on live spt — the wiring proof. No separate `impl`/`unit` stage: a file-backed skill has no unit-testable code of its own (the manifest [strings.skills].subnet pointer + plugin stub are config, and the int proves they resolve end-to-end through the live registry — same model as the commune/force-stop skills, which carry no per-skill impl). (No `spt how-to subnet` topic exists — minor published-guidance gap noted in docs/SPT-CORE-FINDINGS.md; the skill wraps `spt subnet --help` as canonical.)
=== registration-int skill assertions ===
54:body=$(spt adapter get-string claude-spt skills.ready 2>&1)
55:case "$body" in "# /sptc:ready"*) ok "file-backed string resolves: skills.ready -> body" ;; *) bad "skills.ready not resolved to file body: '$(printf %.40s "$body")'" ;; esac
57:cbody=$(spt adapter get-string claude-spt skills.commune 2>&1)
58:case "$cbody" in "# /sptc:commune"*) ok "file-backed string resolves: skills.commune -> body" ;; *) bad "skills.commune not resolved to file body: '$(printf %.40s "$cbody")'" ;; esac
59:fbody=$(spt adapter get-string claude-spt "skills.force-stop" 2>&1)
60:case "$fbody" in "# /sptc:force-stop"*) ok "file-backed string resolves: skills.force-stop -> body" ;; *) bad "skills.force-stop not resolved to file body: '$(printf %.40s "$fbody")'" ;; esac
63:lbody=$(spt adapter get-string claude-spt skills.live 2>&1)
64:case "$lbody" in "# /sptc:live"*) ok "file-backed string resolves: skills.live -> body" ;; *) bad "skills.live not resolved to file body: '$(printf %.40s "$lbody")'" ;; esac
66:sbody=$(spt adapter get-string claude-spt skills.subnet 2>&1)
67:case "$sbody" in "# /sptc:subnet"*) ok "file-backed string resolves: skills.subnet -> body" ;; *) bad "skills.subnet not resolved to file body: '$(printf %.40s "$sbody")'" ;; esac
=== manifest [strings.skills] entries ===
31:version = "0.4.0"
276:setup = { file = "skills/setup.md" }
277:ready = { file = "skills/ready.md" }
278:send = { file = "skills/send.md" }
279:version = { file = "skills/version.md" }
280:signoff = { file = "skills/signoff.md" }       # -> spt endpoint shutdown (graceful + final save)
281:list-agents = { file = "skills/list-agents.md" } # -> spt endpoint list (the roster)
282:commune = { file = "skills/commune.md" }       # -> file-drop <id>-commune.md into [session].commune_dir
283:force-stop = { file = "skills/force-stop.md" } # -> spt endpoint shutdown (graceful, tears down Psyche)
284:subnet = { file = "skills/subnet.md" }         # -> spt subnet {status,create,show-code,join} (cross-machine); REQ-SKILL-SUBNET
289:live = { file = "skills/live.md" }             # -> bare `spt api listen <id>` + Monitor relay (LiveAgent)


Prompt: when you think you know the "why" behind each of my edits, please share the reasons you perceive so we can confirm we're on the same page.


Holding execution — you asked me to confirm the "why" first. Here's what I read behind each `live.md` edit:

## Why behind your `live.md` edits

1. **Cut the resolution plumbing** ("no `--adapter`/`--manifest`/seed", "resolves from parent pid", "stamps `state=live_agent`", "tells the daemon to host the Psyche") → the agent doesn't need to know *how* spt-core wires the perch. Inner workings, not operating instructions.

2. **Added the structured Monitor block + `« spt event »`** → the agent *does* need concrete invocation params (command/persistent/description), and `« spt event »` is the legacy Monitor-task convention. Restoring useful operational style.

3. **Added the `<EVENT type="msg|alarm|echo_commune|init_signoff">` catalog** → the envelope *types* it will actually receive are the agent's concern (it handles them); the daemon plumbing isn't.

4. **Dropped the `--once` "don't use" caveat + the poll/relay-reconcile bullet** → warning about a flag it was never told to use, and how the UPS poll hook coordinates with the relay, are both internals. Noise.

5. **Readiness softened** ("check it only if connectivity complications") → don't make the agent babysit `BOUND`/`READY` markers in the normal path. Less ceremony.

6. **Removed "re-fire the same relay / the seed bridges the new session"** → it was **factually wrong**: the persistent Monitor relay *survives* `/clear`/compact; there's no re-fire and no seed-bridge step. And reframed commune as a habit ("after significant bodies of work") rather than tied to a boundary mechanic.

7. **Offline = `/sptc:signoff`, not `/sptc:force-stop`** → signoff is the agent's own graceful exit; force-stop reads as a kill (and is aimed at stopping agents, possibly others).

8. **Reply = `spt send <sender-id>`** (dropped `--reply-to`) → simplest correct form; the from-correlation flag is a nicety the agent doesn't need.

9. **LIVE block de-jargoned** ("Now running as `<id>`"; dropped Perch/Psyche/daemon/"LiveAgent") → the *user-facing* surface shouldn't leak internal concepts. And dropped the ~25s / "≥ 0.9.0" specifics from the failure path — brittle internals; "failed, run `/sptc:setup`" suffices.

**The throughline:** the agent gets *what to do + what it'll see + how to act*, never *how the plugin/daemon implements it*; user-facing text carries zero internals; fix anything untrue; keep the legacy operational tells (`« spt event »`, the EVENT catalog).

## How I'd ripple it

- **`send`, `commune`, `signoff` → full-fat SKILL.md, injection dropped.** Move operative bodies into the plugin `SKILL.md`; remove their `[strings.skills]` entries from the manifest + delete the adapter bodies (the hook no-ops gracefully when the entry is absent — verified). Update `registration-int.sh` (drop the `skills.commune` resolve assertion; `force-stop`/`ready`/`live`/`subnet` stay). **Why:** a live agent must self-drive reply/commune/signoff *without* the user typing `/sptc:…`, so injection-on-prompt-detection is the wrong delivery — the instructions must always be loadable.
- **`ready`, `subnet` (have `how-to`) + `list-agents`, `version`, `force-stop` (`--help` only)** → keep thin+injected, but make each lean body **reference its `spt how-to X` / `spt … --help`** as the authoritative self-drive anchor. Verified topics exist for ready/send/subnet/live only; the rest get `--help`.
- **`live`** → already your reference shape; leave (self-contained, no how-to ref).
- **`setup`** → leave (self-contained floor).
- Apply the de-internals + de-jargon + correctness sweep across all bodies; `« spt event »` wherever Monitor is used (live, ready).

**One thing to confirm:** does "full-fat → no injection" mean I should **delete** the adapter `send/commune/signoff.md` files + drop their manifest entries (my plan), or keep them as a fallback floor? I'll delete unless you say keep.

Aligned, or did I misread any edit?


1. confirm 2. confirm 3. confirm 4. confirm 5. confirm. the point is to reduce perceived friction for the end user, who is waiting on the agent to finish their perch bringup. absolute minimum number of agent actions/agent-induced delays. 6. confirm 7. confirm 8. confirm, and it's already a detail carried with the message envelope via perch resolution 9. confirm. --- throughline: exactly. please carry these concepts into a revision for the skill bringup `docs/` doc. -your ripple: agree. -confirm on deleting the adapter files for those skills. --- proceed


All confirmed. Key principle locked: **bringup = absolute minimum agent actions/delays** (end user is waiting). Proceeding. Reading the manifest strings block fresh to edit precisely.


258	# Opaque adapter data (spt-core never executes it), dot-path-readable via `spt adapter get-string`.
259	# Seed only this slice — the file-backed skill-instruction BODIES (UPS-injection source) land in
260	# the M12 file-backed-strings parity slice. A profile may leaf-replace any key here.
261	[strings]
262	adapter_label = "Claude Code (spt)"
263
264	[strings.notice]
265	not_installed = "spt-core not found on PATH — run /sptc:setup to install it."
266
267	[strings.skills]
268	# Operative UPS-injection skill bodies. File-backed values (`{ file = "skills/<x>.md" }`) live in the
269	# adapter aux dir `adapter/strings/skills/` (copied to `adapters/<adapter>/strings/` on `adapter add`,
270	# resolved lazily at `spt adapter get-string` — proven vs live v0.7.0, F-003). File-backed so the
271	# manifest does not bloat (ADR-0001). Skills not yet authored keep a one-line inline summary until
272	# their body lands; converting an inline summary to a `{ file }` pointer is the per-skill increment.
273	# whoami SKILL dropped (SCOPE LOCKED parity-trim; operator-confirmed 2026-06-15): core `spt whoami`
274	# stays in the hot path (-> M12 `endpoint list` alias), so the adapter ships no whoami skill. The
275	# "who am i" hint below points at the core CLI. (docs/PARITY.md.)
276	setup = { file = "skills/setup.md" }
277	ready = { file = "skills/ready.md" }
278	send = { file = "skills/send.md" }
279	version = { file = "skills/version.md" }
280	signoff = { file = "skills/signoff.md" }       # -> spt endpoint shutdown (graceful + final save)
281	list-agents = { file = "skills/list-agents.md" } # -> spt endpoint list (the roster)
282	commune = { file = "skills/commune.md" }       # -> file-drop <id>-commune.md into [session].commune_dir
283	force-stop = { file = "skills/force-stop.md" } # -> spt endpoint shutdown (graceful, tears down Psyche)
284	subnet = { file = "skills/subnet.md" }         # -> spt subnet {status,create,show-code,join} (cross-machine); REQ-SKILL-SUBNET
285	# `live` -> upgrade THIS session to a LiveAgent (Option A, 2026-06-17): base claude-spt is live-capable
286	# ([session.psyche_init] in base), so going live is just the COMMAND — bare `spt api listen <id>` under
287	# a Monitor relay. The live listen path stamps the perch state=live_agent → the daemon livehost hosts
288	# the Psyche (livehost.rs:282 gates on live_agent state, doyle). No `:live` composite, no --adapter.
289	live = { file = "skills/live.md" }             # -> bare `spt api listen <id>` + Monitor relay (LiveAgent)
290	# `new-alarm` -> EXPLICIT OUT OF SCOPE for v1: no core `spt` alarm/timed-pulse primitive exists
291	# (legacy $LIVE TIMED PULSE is owl/Psyche-layer, not lifted into core; adapters don't add core
292	# features). doyle carries a parity-gap finding to mint a core deferred-pulse primitive; the skill
293	# lands only after that ships. No `[strings.skills].new-alarm` entry by design (visible-not-silent).
294
295	# ── [[hints]] ──────────────────────────────────────────────────────────────────────────────
296	# Once-per-session keyword hints (order significant, first match wins; case-insensitive substrings).
297	[[hints]]

# Opaque adapter data (spt-core never executes it), dot-path-readable via `spt adapter get-string`.
# Seed only this slice — the file-backed skill-instruction BODIES (UPS-injection source) land in
# the M12 file-backed-strings parity slice. A profile may leaf-replace any key here.
[strings]
adapter_label = "Claude Code (spt)"

[strings.notice]
not_installed = "spt-core not found on PATH — run /sptc:setup to install it."

[strings.skills]
# Operative UPS-injection skill bodies. File-backed values (`{ file = "skills/<x>.md" }`) live in the
# adapter aux dir `adapter/strings/skills/` (copied to `adapters/<adapter>/strings/` on `adapter add`,
# resolved lazily at `spt adapter get-string` — proven vs live v0.7.0, F-003). File-backed so the
# manifest does not bloat (ADR-0001). Skills not yet authored keep a one-line inline summary until
# their body lands; converting an inline summary to a `{ file }` pointer is the per-skill increment.
# whoami SKILL dropped (SCOPE LOCKED parity-trim; operator-confirmed 2026-06-15): core `spt whoami`
# stays in the hot path (-> M12 `endpoint list` alias), so the adapter ships no whoami skill. The
# "who am i" hint below points at the core CLI. (docs/PARITY.md.)
setup = { file = "skills/setup.md" }
ready = { file = "skills/ready.md" }
send = { file = "skills/send.md" }
version = { file = "skills/version.md" }
signoff = { file = "skills/signoff.md" }       # -> spt endpoint shutdown (graceful + final save)
list-agents = { file = "skills/list-agents.md" } # -> spt endpoint list (the roster)
commune = { file = "skills/commune.md" }       # -> file-drop <id>-commune.md into [session].commune_dir
force-stop = { file = "skills/force-stop.md" } # -> spt endpoint shutdown (graceful, tears down Psyche)
subnet = { file = "skills/subnet.md" }         # -> spt subnet {status,create,show-code,join} (cross-machine); REQ-SKILL-SUBNET
# `live` -> upgrade THIS session to a LiveAgent (Option A, 2026-06-17): base claude-spt is live-capable
# ([session.psyche_init] in base), so going live is just the COMMAND — bare `spt api listen <id>` under
# a Monitor relay. The live listen path stamps the perch state=live_agent → the daemon livehost hosts
# the Psyche (livehost.rs:282 gates on live_agent state, doyle). No `:live` composite, no --adapter.
live = { file = "skills/live.md" }             # -> bare `spt api listen <id>` + Monitor relay (LiveAgent)
# `new-alarm` -> EXPLICIT OUT OF SCOPE for v1: no core `spt` alarm/timed-pulse primitive exists
# (legacy $LIVE TIMED PULSE is owl/Psyche-layer, not lifted into core; adapters don't add core
# features). doyle carries a parity-gap finding to mint a core deferred-pulse primitive; the skill
# lands only after that ships. No `[strings.skills].new-alarm` entry by design (visible-not-silent).

# ── [[hints]] ──────────────────────────────────────────────────────────────────────────────
# Once-per-session keyword hints (order significant, first match wins; case-insensitive substrings).
[[hints]]


1. confirm 2. confirm 3. confirm 4. confirm 5. confirm. the point is to reduce perceived friction for the end user, who is waiting on the agent to finish their perch bringup. absolute minimum number o…


Editing manifest — remove send/signoff/commune from injection, document why:


Edit

setup = { file = "skills/setup.md" }
ready = { file = "skills/ready.md" }
send = { file = "skills/send.md" }
version = { file = "skills/version.md" }
signoff = { file = "skills/signoff.md" }       # -> spt endpoint shutdown (graceful + final save)
list-agents = { file = "skills/list-agents.md" } # -> spt endpoint list (the roster)
commune = { file = "skills/commune.md" }       # -> file-drop <id>-commune.md into [session].commune_dir
force-stop = { file = "skills/force-stop.md" } # -> spt endpoint shutdown (graceful, tears down Psyche)
subnet = { file = "skills/subnet.md" }         # -> spt subnet {status,create,show-code,join} (cross-machine); REQ-SKILL-SUBNET

setup = { file = "skills/setup.md" }
ready = { file = "skills/ready.md" }
version = { file = "skills/version.md" }
list-agents = { file = "skills/list-agents.md" } # -> spt endpoint list (the roster)
force-stop = { file = "skills/force-stop.md" } # -> spt endpoint shutdown (graceful, tears down Psyche)
subnet = { file = "skills/subnet.md" }         # -> spt subnet {status,create,show-code,join} (cross-machine); REQ-SKILL-SUBNET
# `send` / `commune` / `signoff` are DELIBERATELY NOT injected here (2026-06-19). A live agent uses
# them REACTIVELY — replying to a message, briefing its Psyche, signing off — WITHOUT the user typing
# `/sptc:<skill>`, so UPS-injection (which fires only on that slash-command in the prompt) is the wrong
# delivery. Their full operative bodies live in the plugin SKILL.md (full-fat, always model-loadable);
# there is no `[strings.skills]` entry and no adapter aux body for them. (sptc_inject_skill no-ops
# silently on the absent key — the full SKILL.md is the single source.)