Scaffolding a Coding Agent Monorepo with npm Workspaces and Strict TypeScript
A monorepo with strict ESM boundaries and explicit build ordering prevents the import chaos and type pollution that derail larger TypeScript projects. The setup shown here — exact dependency versions, `verbatimModuleSyntax`, and a single Biome pass before type-checking — catches errors early and keeps package contracts clean as the agent grows.
The `di-code` monorepo splits a coding agent into four packages — `ai`, `agent`, `coding-agent`, and `tui` — each an ESM-only npm workspace with its own build config. npm links local packages through the `workspaces` field so that `@di-code/agent` can import `@di-code/ai` as a normal dependency, avoiding fragile relative-path imports.
TypeScript configuration enforces strict mode, `NodeNext` module resolution, and `verbatimModuleSyntax` across the whole repo. A shared `tsconfig.base.json` sets the baseline, while each package's `tsconfig.build.json` extends it and emits declarations, source maps, and inline sources into a local `dist/` directory. The root `tsconfig.json` runs type-checking only, with `noEmit` enabled.
Biome replaces both ESLint and Prettier with a single tool, configured to format and lint all TypeScript and JSON files. The build script respects dependency order, running `tui` and `ai` before `agent` and `coding-agent`. A `check` script gates TypeScript on a passing Biome run, and tests are dispatched to any workspace that defines a `test` script.
Using `verbatimModuleSyntax` and `erasableSyntaxOnly` together signals a project that treats TypeScript as a type-checker on top of standard ESM, not a dialect — a stance that avoids whole categories of emit surprises.
Running Biome before TypeScript in the `check` script is a deliberate sequencing choice: formatting and linting failures are cheaper to fix and should block a full type-check, which is the more expensive operation.
Pinning all devDependencies to exact versions removes a source of non-determinism across machines; in a monorepo where multiple packages share the same toolchain, a single version drift can produce inconsistent builds.