Skip to content

SDLC distribution — standalone apps/sdlc/ app, compiled bun binary

Status: open/accepted

  • SDLC becomes a standalone app at apps/sdlc/, and the repo root becomes a pure private workspace-root. Today the root doubles as the @sksizer/sdlc package, which forces the release to run a whole-repo bun test and tangles SDLC’s build/deps with the monorepo.
  • SDLC distributes as a compiled bun binary (bun build --compile), wrapped for npm / brew / curl. The binary embeds the runtime + all code + all deps; the Claude-facing harness surface is embedded and extracted on install.
  • This amends D-0014-cli-primary-npm-distribution: the plain-Node npm artifact was the interim; the binary is the target. Once the binary channel lands, the plain-Node build-artifact bundling and the runtime-agnostic gate are deleted.

D-0014’s plain-Node artifact forces every dependency to be resolvable under Node on a clean consumer install, forever. In a bun monorepo that keeps breaking — a vendored markdown-contract file: dep, a .ts-source @sksizer/agent-plugin workspace import, and any future workspace import — each caught only at release, each requiring a manual bundle-list entry. The runtime-agnostic gate is a standing tax to keep the code Node-compatible. A compiled binary makes SDLC just a bun program (what it naturally is): bun build --compile bundles everything, so consumer-side dependency resolution — and the whole class of failures — vanishes.

This is how comparable tools ship (esbuild, biome, turbo, Playwright): an npm package that is really a compiled binary, selected per platform via optionalDependencies.

AspectChoice
Repo layoutMove the SDLC tool plugin/apps/sdlc/; root is a pure workspace-root (T-1RLU-move-sdlc-tool-to-apps-sdlc).
Published-artifact inner prefix (during the move)Keep plugin/build-artifact relocates the tree, so consumer paths stay byte-identical; zero consumer churn.
In-code source-tree pathsOne pluginSourceDir() resolver, not ~15 hardcoded literals.
Distribution artifactA compiled bun binary, one per platform, wrapped in an npm package via optionalDependencies (+ brew/curl).
Harness surface (skills/conventions/manifests)Embedded in the binary, extracted to disk on harness install (Claude reads it from the filesystem).
Runtime assets (templates, definition.md)Embedded, read in-memory via pluginRootDir().
  • Deleted: the vendored-dep bundling in build-artifact, the runtime-agnostic gate, and the npm-vs-bun install divergence — the entire dependency-resolution surface for consumers.
  • New cost: per-platform binaries (a bun --compile cross-compile matrix) and a one-time asset-root refactor (module-relative reads → pluginRootDir()).
  • Feasibility is proven — a spike produced a 65 MB self-contained binary that runs with bun and node absent from PATH, rendering templates and extracting the harness surface (branch spike/bun-binary-compile; findings in the spike branch under docs/planning/notes/binary-spike-findings.md). The op-discovery blocker (runtime dynamic import()) is solved with a generated static op-manifest barrel.

Accepted. Phase -1 (the apps/sdlc/ move, T-1RLU-move-sdlc-tool-to-apps-sdlc) lands first, gated on a freeze window because a tree-rename conflicts with concurrent plugin/** edits. The binary productionization (cross-compile + npm wrapper + cache strategy) follows on the moved layout. The plain-Node path is removed last.


← Back to Decisions