Skip to content

feat: suit inject — realtime component injection (proposal + increment 1)#66

Merged
danmestas merged 3 commits into
mainfrom
docs/inject-proposal
May 25, 2026
Merged

feat: suit inject — realtime component injection (proposal + increment 1)#66
danmestas merged 3 commits into
mainfrom
docs/inject-proposal

Conversation

@danmestas

@danmestas danmestas commented May 25, 2026

Copy link
Copy Markdown
Owner

Adds suit inject — materialize a wardrobe component into a worker's harness home so it loads on the worker's next turn, no restart. Per operator direction this PR carries the proposal + working implementation (landing as tested increments), not a proposal alone. Branched work has been merged onto v0.15.0.

Proposal

docs/proposals/2026-05-24-realtime-component-injection.md — CLI surface, conditional-reload model, lockfile-truthfulness contract, auth/trust model, failure-mode table, and the (a)–(f) slice plan. Open questions Q1–Q4 resolved per operator.

Increment 1 (shipping here)

suit inject (--accessory|--bundle) <name> [--home <dir>] [--from <path>] [--dry-run] [--no-reload] [--force] [--json]

  • Reuses the suit up pipeline (composeBundle → ProjectWriter → lockfile), so a single accessory/bundle materializes across all four harnesses (claude-code/codex/gemini/pi) through the existing adapters — verified: philosophy → 173 files.
  • New optional lockfile injected: [] list (distinct from up's resolution/files); minimal-lockfile creation when the target has none. Back-compat: absent field parses unchanged.
  • Idempotent: re-injecting an unchanged component reports unchanged and writes nothing — compared via recorded lock-entries (additive files use the stable marker-block sha, so CLAUDE.md/AGENTS.md/GEMINI.md don't defeat it).
  • Refuse-when-dirty (ADR-0012 contract): untracked or hand-edited targets refuse unless --force.
  • Conditional reload decision computed + reported (reload: not-required | restart-required): claude-code file-watched kinds → not-required; mcp/plugin + codex/gemini/pi → restart-required (conservative). No NATS signal fired this increment.
  • suit current now accepts --project/--home <dir> and surfaces injected components distinctly.
  • --target <owner>/<session> is parsed but exits 2 ("not yet implemented: use --home") — NATS discovery is increment 2.

Verification

  • npm run typecheck, npm run build, npm test618 tests pass locally (mirrors ci.yml).
  • Live smoke (real wardrobe, all 4 harnesses): 1st inject → injected (173 files); 2nd identical → unchanged; suit current lists the injected component.

Deferred to later increments (multi-session, per plan)

danmestas added 2 commits May 24, 2026 20:46
…arness home

Reuses the suit up pipeline (composeBundle -> ProjectWriter -> lockfile) to
materialize a single accessory/bundle's files across all four harness
adapters into a target home, recorded under a new optional lockfile
`injected:` list distinct from up's resolution/files.

- composeBundle accepts outfit: null for outfit-less (inject) composition
- idempotent re-inject + refuse-when-dirty, mirroring suit up
- reloadDecision() pure fn: claude-code file-watched kinds -> not-required,
  mcp/plugin + other harnesses -> restart-required (conservative)
- suit current surfaces injected components distinctly
- --home / $CLAUDE_PROJECT_DIR / cwd home resolution; --target deferred (exits 2)

NATS target discovery, the reload emit-side, and suit off injection-cleanup
are later increments.
- idempotency now compares the computed injected lock-entries against the
  prior injected[] entry for the same component (order-insensitive path/sha/
  mode) instead of an on-disk whole-file scan. Real accessories emit additive
  CLAUDE.md/AGENTS.md/GEMINI.md whose block-sha is stable across re-injects,
  so re-injecting an unchanged accessory now correctly reports 'unchanged'.
- suit current accepts --project/--home <dir> (was hard-coded to cwd), so the
  injected list at an inject target home is inspectable.
- regression tests: same-accessory-twice asserts no writes; additive-emitting
  accessory re-inject reports unchanged.
@danmestas danmestas changed the title docs: proposal for suit inject (realtime component injection) feat: suit inject — realtime component injection (proposal + increment 1) May 25, 2026
@danmestas danmestas merged commit fdfa3c8 into main May 25, 2026
1 check passed
@danmestas danmestas deleted the docs/inject-proposal branch May 25, 2026 10:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant