SDLC distribution — standalone apps/sdlc/ app, compiled bun binary
Status: open/accepted
Summary
Section titled “Summary”- 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/sdlcpackage, which forces the release to run a whole-repobun testand tangles SDLC’s build/deps with the monorepo. - SDLC distributes as a compiled
bunbinary (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-artifactbundling and theruntime-agnosticgate 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.
Decision
Section titled “Decision”| Aspect | Choice |
|---|---|
| Repo layout | Move 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 paths | One pluginSourceDir() resolver, not ~15 hardcoded literals. |
| Distribution artifact | A 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(). |
Consequences
Section titled “Consequences”- Deleted: the vendored-dep bundling in
build-artifact, theruntime-agnosticgate, and the npm-vs-bun install divergence — the entire dependency-resolution surface for consumers. - New cost: per-platform binaries (a
bun --compilecross-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 underdocs/planning/notes/binary-spike-findings.md). The op-discovery blocker (runtime dynamicimport()) is solved with a generated static op-manifest barrel.
Status / sequencing
Section titled “Status / sequencing”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.