ADR 0001: Runtime and Language — Node.js 20+ with TypeScript

Field Value
Status Accepted
Date Pre-alpha
Deciders Project maintainers
Supersedes
Superseded by
Related ADRs 0002 (Monorepo tooling), 0004 (Distribution)

Summary

aidokit is built in TypeScript targeting Node.js 20 LTS or later. All packages publish as ESM with .d.ts types. There is no plan to support older Node versions, alternative runtimes (Deno, Bun), or compiled-binary distribution within v1.0.


Context

aidokit is a scaffolding CLI with a specific operational shape:

Distribution must work cross-platform (macOS, Linux, Windows) with minimal friction. The target user already has Node.js installed in many cases (they use AI coding CLIs, which themselves often run on Node) and would invoke aidokit via npx.

There is also strong existing alignment:

We need a runtime that:

  1. Aligns with the existing emitted-code stack (Node-based hooks)
  2. Has a mature ecosystem for CLI conveniences (arg parsing, prompts, formatting, validation)
  3. Distributes universally with minimal friction
  4. Has a large enough contributor pool to support an open-source project
  5. Supports a strongly-typed adapter contract (third-party adapters need real type checking)
  6. Works cross-platform without weeks of Windows-specific debugging

Decision

Runtime

Language

Module format

Distribution

Type sharing


Consequences

Positive

Negative

Neutral


Alternatives considered

Alternative 1: Go

Pros

Cons

Reason rejected: ecosystem alignment outweighs performance for an interactive setup tool. The 100ms startup difference is invisible to users running a one-shot bootstrap command; the ecosystem cost of going against the grain is significant and permanent.

Alternative 2: Rust

Pros

Cons

Reason rejected: the contributor barrier is too high for an open-source project that depends on community adapters and stack packs. Rust's strengths (memory safety, parallelism) are not what this tool needs.

Alternative 3: Python

Pros

Cons

Reason rejected: distribution complexity is the deal-breaker. npx is universal in a way pip is not. Users would hit "wrong Python version" errors immediately.

Alternative 4: Bun

Pros

Cons

Reason rejected for v1.0: Bun is too new to be the primary target. We may add Bun as a supported runtime later (the code should mostly work) but Node is the primary. Revisit at v2.0.

Alternative 5: Deno

Pros

Cons

Reason rejected: Deno is technically excellent but ecosystem-isolated. The cost of being outside npm is too high.

Alternative 6: Shell scripts (Bash + Node mix)

Like the v4 kit's hook scripts in some places.

Pros

Cons

Reason rejected: unmaintainable at the scale of aidokit. Bash is fine for the emitted hook scripts; not for the CLI itself.


Implementation notes

Required tooling

package.json baseline for every package

{
  "name": "@aidokit/<package>",
  "version": "0.1.0",
  "type": "module",
  "engines": {
    "node": ">=20.0.0"
  },
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/index.js"
    }
  },
  "main": "./dist/index.js",
  "types": "./dist/index.d.ts",
  "files": ["dist", "README.md", "CHANGELOG.md"]
}

Imports

TypeScript with NodeNext resolution requires .js extension on imports even for .ts files:

// Correct
import { Adapter } from './contract.js';

// Incorrect (will break at runtime in ESM)
import { Adapter } from './contract';

Engines field enforcement

Every published package MUST include engines.node: ">=20.0.0". npm/pnpm emit a warning on install if the user's Node is older. CI runs against Node 20 and Node 22 to catch regressions.


Validation

This decision is validated when:


References