Skip to content

T-ZEPK-harness-install-dev-link-mode

Status: closed/done · Impact: medium · Complexity: medium

Make the live-source dev loop (D-0014 point 12) a one-liner: from a source checkout, sdlc harness install claude in a peer project should register the harness against this checkout’s source dir so the peer’s skills track live edits — with no copy, no rebuild. Detect the source-vs-installed case automatically (the same signal the launcher already uses) and let an explicit --mode override it.

T-ZF8U-harness-install-claude-verb shipped sdlc harness install claude with two modes, both of which produce a portable, committable registration; neither points at a sibling source checkout, so live-source consumers can’t get the skills without copying.

LocationRole today
plugin/lib/services/harness/ops/install-claude.tsThe op: --mode copy (materialize into .sdlc/plugin/) / --mode node-modules (point at node_modules/@sksizer/sdlc/plugin); merges the sdlc marketplace + enabledPlugins["sdlc@sdlc"] into .claude/settings.json
plugin/lib/services/harness/ops/_install.ts#resolvePluginRootResolves the running harness root — the abstract anchor a link mode reuses
plugin/lib/util/runtime.ts#moduleExt.ts (source) vs .js (built artifact) — the dev-vs-installed signal, already used by the launcher
plugin/lib/services/project/ops/doctor.tsSame-install check: registered path’s version vs running CLI’s; copy-drift vs the stamp

A third --mode link (with --dev as sugar) registers the running harness root’s absolute path as a source: directory marketplace. The op auto-detects the default mode: running from source → link; from an installed artifact → copy. Because link writes a machine-specific path, its stanza goes in .claude/settings.local.json (gitignored), never the committed .claude/settings.json. Switching modes is idempotent and mutually exclusive. doctor treats a link install as always-current.

  1. Detect dev-vs-installed. Source when moduleExt(import.meta.url) is .ts OR resolvePluginRoot()’s path is not under a node_modules/ segment; else installed. Expose as a small helper so the op and doctor share it.
  2. --mode link (+ --dev alias). Marketplace path = the absolute path from resolvePluginRoot() (the abstract harness root — do NOT hardcode plugin/, so this survives the D-0001 plugin/ → per-target plugin/claude/ move). No file materialization, no stamp.
  3. Default = detected mode when --mode absent; explicit --mode overrides. Report the resolved mode + path (HARNESS: claude installed (link) at <abs path>).
  4. Route link config to .claude/settings.local.json (create if absent; same merge/preserve semantics as the committed file). copy / node-modules stay in .claude/settings.json. Ensure .gitignore covers settings.local.json if the project doesn’t already.
  5. Idempotent + mutually exclusive. On any install, remove a prior sdlc marketplace entry from both settings files before writing the chosen one, so switching copy↔link↔node-modules leaves exactly one registration. A no-op re-run makes zero changes.
  6. doctor. A link registration reports a healthy dev/linked state: version is the live source’s (always current), the copy-drift check is skipped. Unregistered stays neutral INFO.
  7. Tests + README: link install writes the local-settings stanza pointing at the source root; auto-detect picks link from a source run and copy from a simulated installed run; mode-switch removes the prior entry; doctor passes on a link install. Document the peer-project dev loop.
LocationKindChange
plugin/lib/services/harness/ops/install-claude.tsmodifylink mode + --dev; auto-detect default; local-settings routing; mode-switch cleanup
plugin/lib/services/harness/ops/_install.tsmodifyshared isSourceInstall() detection helper; local-settings path constant
plugin/lib/services/project/ops/doctor.tsmodifylink install → always-current dev/linked state
plugin/lib/services/harness/tests/modifylink mode, auto-detect both ways, mode-switch, local-settings target
plugin/lib/services/project/tests/modifydoctor on a link install
README.mdmodifythe peer-project live-source dev loop
  • AC-1: run from a source checkout with no --mode, harness install claude --project-root <peer> registers the checkout’s harness root as a source: directory marketplace in <peer>/.claude/settings.local.json (not settings.json), enables sdlc@sdlc, and prints the link marker.
  • AC-2: --mode copy from the same source run still produces the portable .sdlc/plugin/ copy install in the committed settings.json (explicit override wins).
  • AC-3: auto-detect picks copy when the op runs from an installed artifact (simulated: plugin root under node_modules, .js module).
  • AC-4: switching modes (copy→link and back) leaves exactly one sdlc marketplace registration across both settings files; a no-op re-run changes nothing.
  • AC-5: project doctor on a link install reports healthy (no drift), naming the linked source path.
  • AC-6: bunx tsc --noEmit, bun test plugin/lib/services/harness plugin/lib/services/project, and gate runtime-agnostic all clean.
  • The derived-plugin transform pipeline (D-0014 point 4): once plugin/claude is generated from a canonical agnostic source, link should point at the build output with freshness handling (rebuild-on-edit / doctor staleness). This task links the harness root as it resolves today (hand-authored); it must not hardcode plugin/, but building the transform + freshness is a later task.
  • The SDLC_HOME launcher override (D-0014 point 12) and a PATH-install helper (sdlc dev-link) — sibling live-source ergonomics, separate tasks.
  • Non-Claude harness targets.

← Back to Tasks