---
name: v090-d1-shipped
description: v0.9.0 D1 (hook logic → claude-spt hook binary) SHIPPED + published both targets
metadata: 
  node_type: memory
  type: project
  originSessionId: 7a919ad5-82a3-4e01-8754-d635c0702c15
---

**v0.9.0 SHIPPED 2026-06-28** (perri). D1 = hook logic moved off the cplugs plugin shell into the
consolidated binary: new `claude-spt hook <event>` subcommand (`tools/claude-spt/src/hook.rs`) —
faithful port of all 8 hook wrappers + `_common.sh`, with a `HookEnv` side-effect trait so handlers
are recorder-unit-testable. Plugin now ships only a STATIC-FOREVER `hooks.json` + thin `dispatch.sh`
that resolves the binary via lazily-substituted `[strings].hook_cmd = "{adapter_dir}/claude-spt hook"`
(caches `$SPTC_HOOK_BIN`, runs bootstrap on SessionStart, passes `--host-pid $PPID`). Deleted the 8
`.sh` wrappers + `_common.sh` + `tests/hooks-parse.sh`.

**Design = ADR-0006 ask #1 → RESOLVE-NOT-EXECUTE** (doyle, [[v074-follow-ups]] lineage): NOT `spt api
run-hook`. Two spt-core v0.16.0 primitives carry it (BOTH verified live on 0.16.0 via throwaway
probe-d1): (a) `{adapter_dir}`/`{adapter_name}` subst keys; (b) lazy `[strings]` subst at `get-string`
read time. min_spt_core stays 0.16.0 (no new seam). Behaviour-preserving refactor.

Bootstrap STAYS in the plugin (dispatch.sh): the binary can't exist before spt-core + the adapter
install; pre-/sptc:setup the get-string yields nothing → dispatch no-ops (the pre-readiness no-op).
Windows: git-bash resolves bare `claude-spt` → `.exe`; Rust std has no portable getppid so dispatch
passes the seed pid explicitly.

PUBLISHED: GitHub release **v0.9.0** on SaberMage/claude-spt (commit d7fb440) w/ fat `adapter.spt`
(win+linux; downloaded-asset verified: version 0.9.0 + hook_cmd) + cplugs **sptc 0.1.8** (commit
2989326). 89 crate tests, all local gates green (no GH Actions in repo — local gates ARE the CI).
New REQ-DIST-HOOK-BINARY (doc/impl/unit). CHANGELOG [0.9.0].

DEFERRED: on-node `spt adapter update claude-spt` ×2 ([update.post] double-update nuance) — skipped
to avoid mutating THIS live node's registration mid-session. poll-int live binary-drain e2e blocked
here (node holds 2 subnets → bind needs --subnet); the drain/render is covered by hook.rs unit tests
+ a live skill-injection dogfood. Next deferred-queue candidate after D1 = D4 (sptc→spt succession,
owl-retire gated) or the harness-glue E2Es. See [[v074-follow-ups]], [[prep4-v030-parity-closed]].
