Skip to content

RFC: Extract commercial surface from @stackbilt/cli into @stackbilt/build #112

@stackbilt-admin

Description

@stackbilt-admin

Context

@stackbilt/cli is the OSS Charter package. It currently bundles two distinct surfaces in one binary:

Local governance (23 commands, purely local): validate, drift, blast, surface, audit, classify, score, doctor, init, setup, hook, bootstrap, telemetry, validate-ontology, why, serve, all adf-* subcommands. No network access, no credentials.

Commercial surface (4 commands, network-touching): login, architect, run, scaffold. These reach api.stackbilt.dev/engine and mcp.stackbilt.dev/api/scaffold, require a bearer token, and persist credentials to ~/.charter/credentials.json via charter login.

The bundling creates two problems:

  1. Identity mismatch — the package README and repo description position Charter as a local-first governance tool, but charter login solicits a bearer token and writes it to disk. For a security review at a regulated-company adopter, that's the line that gets flagged — not that the tool can call an external API, but that it asks for and persists credentials.
  2. OSS/commercial coupling — the OSS tarball contains commercial-endpoint URLs, bearer-token handling, and scaffold response types vendored from a contracts package. A fork that wants governance-only has non-trivial surgery to perform.

30-day telemetry signal (single active install): validate (14), doctor (7), adf.evidence (7), run (5), blast (5), audit (3), surface (3). architect and scaffold do not register. Commercial commands are ~10% of total usage — real, but not dominant enough to justify the identity coupling.

Proposal

Extract the commercial surface into a new npm package: @stackbilt/build.

Binary alias split at completion:

  • @stackbilt/clicharter binary only (governance)
  • @stackbilt/buildstackbilt binary only (creation)

Package name matches the existing engine /build REST endpoint naming and is short enough to type.

Concrete moves

Files to relocate from packages/cli/src/ into the new package:

  • commands/login.ts
  • commands/architect.ts
  • commands/run.ts
  • commands/scaffold.ts
  • credentials.ts
  • http-client.ts
  • types/scaffold-contract-types.ts (vendored from @stackbilt/contracts)

Plus the associated tests in __tests__/:

  • credentials.test.ts
  • login.test.ts
  • auth-wiring.test.ts

What stays in @stackbilt/cli

All 23 governance commands plus serve (local stdio MCP server). No network access, no credential handling, no commercial endpoints referenced.

Receiving-repo options

The receiving home for @stackbilt/build's source is TBD. Three candidates already exist on the org:

Repo Current purpose Fit
Stackbilt-dev/stackbilt-engine Deterministic stack builder — the /build endpoint's implementation Strongest. The CLI is a thin client of this repo's server. Colocating CLI + server simplifies type sharing.
Stackbilt-dev/stackbilt-mcp-gateway "OAuth + multi-product routing" Plausible. Houses the gateway that run calls. Less direct fit than stackbilt-engine.
New repo Dedicated CLI package Clean boundary. More publishing ceremony to stand up.

Proposed: stackbilt-engine. It's where the server side of architect/run/scaffold already lives; putting the CLI beside it removes a cross-repo coupling and matches the pattern other engine-embedded CLIs use (e.g., wrangler in workers-sdk).

Prerequisites

  • Env-var bridge (PR feat(cli): STACKBILT_API_KEY env var auth; deprecate charter login #111): STACKBILT_API_KEY + STACKBILT_API_BASE_URL support; charter login deprecation notice. Lets users migrate before the commands move packages.
  • Decide receiving repo (see options above).
  • Stand up publish pipeline for @stackbilt/build (matching Charter's release flow — workflow .github/workflows/release.yml, automated npm publish on tag, CHANGELOG discipline).

Migration phases

  1. Phase 1 — Env-var bridge (landed in feat(cli): STACKBILT_API_KEY env var auth; deprecate charter login #111). Additive; no breakage. charter login emits deprecation notice. STACKBILT_API_KEY is the documented primary path.

  2. Phase 2 — Stand up @stackbilt/build. New package in the chosen repo. Republish login, architect, run, scaffold there (with credentials.ts, http-client.ts, scaffold-contract-types). Initial version: 0.1.0 or match Charter's current versioning cadence. CLI binary: stackbilt. Tests port over.

  3. Phase 3 — Cross-reference deprecation in @stackbilt/cli. In Charter minor release (proposed: 0.12.0), the 4 commands print a stronger deprecation notice pointing users to npm install -g @stackbilt/build. Commands still work; the notice is informational.

  4. Phase 4 — Charter 1.0. Remove the 4 commands, credentials.ts, http-client.ts, and types/scaffold-contract-types.ts from @stackbilt/cli. Remove the stackbilt bin alias from packages/cli/package.json. Update CHANGELOG with migration guide. Major version bump.

Acceptance criteria for Charter 1.0

  • grep -r 'fetch(' packages/cli/src/ returns zero results (aside from test fixtures).
  • grep -r 'Authorization' packages/cli/src/ returns zero results.
  • No stackbilt.dev URL literals in @stackbilt/cli source.
  • packages/cli/package.json bin field contains only { "charter": "./dist/bin.js" }.
  • credentials.ts, http-client.ts, types/scaffold-contract-types.ts deleted.
  • Root README rewritten to lead with governance; scaffolding references redirect to @stackbilt/build.
  • CHANGELOG [1.0.0] entry documents the split and upgrade path.

Open questions

  1. Receiving repo: stackbilt-engine vs. stackbilt-mcp-gateway vs. new. Leaning stackbilt-engine (argued above).
  2. stackbilt bin alias: keep in @stackbilt/cli for one additional release after Phase 2 (as a warning-printing shim that execs @stackbilt/build if installed), or remove immediately in Phase 4? The shim adds complexity for one release's worth of migration grace.
  3. Versioning: does @stackbilt/build start at 0.1.0 or match Charter's current minor (e.g., 0.11.0)? Matching would signal "part of the same ecosystem"; starting at 0.1.0 would signal "new package."
  4. Timing: is there a deadline for 1.0, or is it "when it's ready"? The telemetry data suggests no urgency from usage pressure — architect and scaffold are unused; run is 10%. 1.0 can land when governance commands feel stable, independent of this extraction.

Non-goals

  • Deprecating the scaffolding feature itself. run/architect/scaffold stay supported; they just live in the right package.
  • Rewriting internals. This is a relocation, not a refactor. The Zod-Core-Out pattern from refactor(blast,cli,serve): Zod-Core-Out architecture — vertical slice for blast #109 is a separate, orthogonal improvement applied independently.
  • Changing REST contracts. /build and /api/scaffold behavior is unchanged; only the client lives elsewhere.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requesttype:refactorCode restructuring without behavior change

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions