---
name: harness-adapter-agnostic-resolution
description: "ADR-0021 harness-hosted adapter-agnostic seed + bind-time adapter/profile resolution (legacy parity: $LIVE start=$SPT listen, no mandatory --adapter). Grilled+locked w/ operator 2026-06-16. CONTEXT §170-186 + ADR-0021 authored. todlando builds (~v0.9.0), doyle gates, perri adapter fixes follow."
metadata: 
  node_type: memory
  type: project
  originSessionId: 9d0930b3-34c1-4dce-943f-72ccdc8fb726
---

**Harness-hosted adapter-agnostic seed + bind-time resolution** — /grill-with-docs locked w/ operator 2026-06-16. Triggered by perri's /sptc:live v0.2.0 being wrong vs legacy parity (screenshots: forced --adapter on seed AND listen, raw SEEDED:/NO_SEED:/BOUND: plumbing shown, redirected to how-to live). Design authored by doyle: **CONTEXT §170-186 rewritten + ADR-0021** (docs/adr/0021-...). Code = todlando (dispatched), doyle gates, deployah releases; perri adapter fixes follow on release.

**ROOT (confirmed code):** api/mod.rs ApiArgs.adapter:String = `--adapter` REQUIRED on every api call — but DEAD on listen (startup.rs bind_from_seed resolves adapter from seed by parent_pid, ignores the flag). Breaks parity ($LIVE start wall-a→$SPT listen wall-a carries no adapter).

**LOCKED DESIGN (4 decisions):**
1. **Agnostic seed**: api seed carries only parent_pid+session_id (no adapter_name). --adapter OPTIONAL across api group (dev override). Resolution is a bind-time READ (drift-free), covers ReadyAgent(poll)+LiveAgent(listen).
2. **Match-key = new `[adapter] host_binaries` Vec<String>** (manifest, additive/N-1-safe like shortcut_basename): bind-time pid→exe basename (case-insensitive,.exe-stripped) → candidate harness adapters declaring that basename; zero→friendly error naming binary + --adapter escape. (No existing field reusable: shortcut_basename=picker branding, [session.self]=spt-hosted launch direction.)
3. **Profile selection = explicit pointer → registered_at_ms fallback.** Pointer `$SPT_HOME/adapters/active-profiles.toml` (host_binary→adapter[:profile]) primary; UNSET→freshest candidate by **registered_at_ms** (record.toml field, sturdier than fs-mtime), BASE profile (a profile is ONLY ever chosen by pointer), name-asc tiebreak. Pointer written ONLY by `spt adapter use <adapter>[:profile]` (--clear drops); NEVER auto-written by install/update/add (that's the update-flips-default footgun we killed); stale self-heals+warns; pruned on adapter remove.
4. **Storage**: active-profiles.toml at registry ROOT, sibling to per-adapter <name>/ dirs (update only rewrites <name>/ → can't clobber). Asymmetry: seed=ephemeral/in-mem, pointer=durable/on-disk.
Plus: mdBook guides adapter devs to call `spt adapter use` per unique host binary; humanize DIRECT-USER CLI output (CODE:RESULT→prose) but DON'T break adapter-parsed bringup tokens (SEEDED/BOUND/READY/NO_SEED) — additive/porcelain split, flag dual-contract markers to doyle.

**REQ slate (todlando mints registry-first):** REQ-START-5 (agnostic seed+optional --adapter+bind resolution) · REQ-MANIFEST-8 (host_binaries) · REQ-INSTALL-12 (pointer + adapter use) · REQ-CLI-4 (humanize direct-user output). Branch v0.9.0-harness-resolution off main@v0.8.3, MINOR.

**perri (forwarded, split NOW vs BLOCKED):** NOW = (1) skill injection self-contained, remove how-to-live redirect; (2) humanize composed output, hide raw spt-core plumbing. PREP = (3) add host_binaries=["claude"] to manifest; (4) on release: bare `spt api seed --pid --session-id`, drop seed+listen-chain workaround, call `spt adapter use` in setup. doyle pings perri on ship. [[perri-question-triage-protocol]] [[spt-core-harness-boundary-and-grounding]].

STATUS: dispatched todlando + perri 2026-06-16. Awaiting todlando PR-ready → doyle gate → deployah release → ping perri.

**UPDATE 2026-06-17: v0.9.0 BUILT + GATED + MERGED → deployah cutting release (counter 21, MINOR 0.8.4→0.9.0).** todlando PR #21; doyle GATE = full code-read PASS (resolve.rs faithful to ADR-0021 + 9 units; live_resolve_e2e real 3-phase int non-vacuous: agnostic seed+no-adapter listen→freshest host_binaries stamp+online, pointer override, zero-match ADAPTER_UNRESOLVED+no phantom; cmd_listen wiring = explicit-override-else-resolve_bind_adapter feeding both info.json stamp + live_capable manifest; seed agnostic, --adapter Option; traceable START-5/MANIFEST-8/INSTALL-12 [doc,impl,unit,int], CLI-4 required_stages=[] deferred). MERGE-ORDERING: held #21 until v0.8.4 (ccs patch) shipped FIRST (else patch would carry minor features = wrong semver), then todlando re-synced main (v0.8.4 bump) → re-preflight green → I merged @4b1dc89. CI green both runners throughout. New impl files: spt-runtime/resolve.rs (resolver+pointer), spt-store/proc.rs (exe_basename Win QueryFullProcessImageNameW/Linux /proc/pid/exe). **PUBLISHED v0.9.0 2026-06-17 (counter 21, MINOR, publisher leg 15× clean): hashes linux d96105f5… win cae92e88…, bump c448b32, update-set v21, signed rel-primary-2026.** doyle hash-check ✓. **perri PINGED to ACTIVATE PREP-4** (bare SessionStart seed, drop --adapter+chain, $LIVE start→$SPT listen no --adapter, `spt adapter use claude-spt` in /sptc:setup, strip interim note). COMPAT FLAG to perri: bare-seed flow REQUIRES spt-core>=0.9.0 (older mandates --adapter) → either bump adapter min_spt_core_version=0.9.0 + hard-switch (lean), or version-detect fallback; perri's call. perri to verify /sptc:live end-to-end (no --adapter, perch stamps claude-spt+online, clean LIVE block). AWAITING perri wired+validated = closes the legacy-parity arc. READY/LIVE COEXISTENCE GUIDANCE (perri Q 2026-06-17, ADR-0021 underspecified): pointer = standing DEFAULT per host_binary; --adapter = PER-SESSION override (different axes). Ready-vs-live mapping is the ADAPTER's design choice. Recommended OPTION A: one live-capable base profile, COMMAND decides (listen=live+psyche / poll=ready+no-psyche), both --adapter-free → zero coexistence problem, fullest parity. OPTION B (only if base vs :live must differ+coexist on one binary): pointer = common default (--adapter-free), other type carries explicit --adapter override. INVARIANT: NEVER flip the pointer per-session (global side-effect changes every later resolve) — session-scoped choice = the override, not pointer mutation. perri compat = hard-bump min_spt_core_version→0.9.0 (no <0.9.0 users), her release likely v0.3.0 (structural session-start.sh → cplugs republish + plugin.json bump). ReadyAgent + picker REQ-PICKER-1 = stacked follow-ons. CLI-4 broad humanize = marker-audit follow-on (28 ADAPTER_* markers, 0 asserted in-repo; only perri greps → confirm which, --porcelain those).
