Appearance
ADR-0002: Zero Runtime Dependencies
- Status: Accepted
- Date: 2026-04-14
- Supersedes: None
- Amendment: ADR-0006 permits
yaml@^2.8as a narrowly-scoped runtime dependency (2026-04-15).
Context and Problem Statement
package.json's dependencies block is the only way nubos-pilot can ship transitive complexity to end users through npx. Every runtime dependency is a three-headed cost: a supply-chain surface, a version-compatibility constraint, and an install-failure mode (Windows path quirks, corporate proxies, air-gapped networks, peer-dep conflicts, abandoned maintainers). The question: should nubos-pilot ever declare runtime dependencies?
Scope
This ADR is about package.json.dependencies specifically — the subset of package.json that ships to end users via npm install / npx:
- "Zero runtime deps" means:
package.json.dependencies === {}(empty object, not absent) — no library is pulled down at install time on an end-user machine. devDependenciesare explicitly permitted. Test runners, optional hook bundlers, and similar authoring-time tooling live there. They are never shipped to end users.- Environment assumptions are not dependencies.
git,node >=22, and the host agent CLI are assumed to exist on the user's machine — they are prerequisites, not thingsnubos-pilotships.
Decision Drivers
- Sufficiency of Node builtins — the full markdown-workflow surface (frontmatter parsing, readline prompts, file locking, ANSI output, child-process spawn) is reachable through
fs,path,os,child_process,readline,crypto, andutilalone. npxinstall reliability — zero deps ≈ zero failure modes on Windows, corporate networks, and air-gapped environments.- Patchability (Core Value) — users copy
.cjsfiles verbatim into.claude/nubos-pilot/and sometimes patch them locally; there is nonode_modules/tree to keep in sync. - Security — zero runtime deps ≈ zero supply-chain surface.
Considered Options
- Zero runtime dependencies — Node builtins + hand-rolled helpers. (CHOSEN)
- Rich dependency tree — adopt a broad runtime surface (coding-agent SDK,
playwright,sharp,chokidar,@modelcontextprotocol/sdk,chalk/picocolors). - Native Rust N-API engine — publish per-platform prebuilt binaries as
optionalDependencies. - Accept a single narrow dependency pragmatically — e.g.
yamlfor frontmatter parsing.
Decision Outcome
Chosen: "Zero runtime dependencies", because it is the only option that reinforces the Core-Value patchability story and minimizes install-failure modes on the weakest user environments simultaneously. The devDependencies escape hatch covers authoring-time needs without leaking into end-user installs.
Escape hatch for future exceptions: if a concrete future feature genuinely requires a runtime dep that builtins cannot satisfy, the exception is introduced by a new ADR that either supersedes ADR-0002 wholesale or amends it narrowly with a name-scoped exemption. The escape is deliberately bureaucratic so that "just add a dep" never becomes the reflex answer. (See ADR-0006 for the first exercise of this hatch.)
Consequences
- Good —
npm installis effectively a no-op for end users. - Good — supply-chain audits are trivial.
- Good — users can copy-patch
.cjsfiles without module-resolution confusion. - Good — the install-payload tree contains only
.cjsfiles and Markdown. - Bad — we reimplement small utilities (YAML frontmatter via hand-rolled parser, readline prompts, raw ANSI escapes). Accepted cost.
- Neutral —
devDependenciesare permitted and do not ship to users. - Neutral —
optionalDependenciesfor native prebuilt binaries is also rejected by this ADR — no accidental backdoor.
Pros and Cons of the Options
Zero runtime dependencies — chosen
- Good — Node builtins cover the entire markdown-workflow surface.
- Good — preserves the Core Value "markdown-only, multi-runtime, ohne eigenes Daemon".
- Bad — every small utility must be hand-rolled. Accepted.
Rich dependency tree — rejected
- Good —
chalk/picocolorsproduce nicer output;@clack/promptsproduces nicer Q&A flows. - Bad —
playwright,sharp,sql.js,chokidar, image addons target features we do not implement. - Bad —
@modelcontextprotocol/sdkas a runtime dep contradictsREQUIREMENTS.md§"Out of Scope". - Bad —
@anthropic-ai/claude-agent-sdkimplies we spawn agents — that's the daemon pattern ADR-0001 forbids. - Bad — every transitive node_module is an install-failure risk on the environments that most need
nubos-pilotto "just work".
Native Rust N-API engine — rejected
- Good — native binaries offer raw-speed
grep/ast-grep/syntax-highlighting. - Bad — requires per-platform prebuilt binaries with the associated CI/release plumbing.
- Bad — we have no TUI, no image pipeline, no watcher.
- Bad — Claude Code already exposes
Grep,Read,Bashas first-class tools. - Bad — introducing a binary-ship story violates patchability.
Accept a single narrow dependency pragmatically — rejected (for now)
- Good — one dep would make frontmatter parsing robust against multiline sequences and anchors.
- Bad — "just one dep" is a slippery slope.
- Bad — the escape-hatch route exists for exactly this situation.
(Update: see ADR-0006 — yaml@^2.8 was eventually accepted under the escape-hatch route.)
More Information
- Related ADR: ADR-0005 — the install-payload tree contains only
.cjs+ Markdown. - CLAUDE.md: §"Technology Stack" → "Installation"; §"External runtime dependencies"; §"Alternatives Considered".
- REQUIREMENTS.md: §"Out of Scope" → "Nubos-MCP als First-Class-Dependency".
This ADR does not describe CI enforcement. CI-gate enforcement of the zero-deps rule is deferred to a later deploy/CI phase per ROADMAP.md; current enforcement consists of human PR review and this ADR as the authoritative reference.
