Tech Stack

Complete reference of tools and libraries used in the maltty CLI framework.

Core Dependencies

TypeScript & Build

ToolPurposeVersionDocumentation
TypeScriptType system^5.xHandbook
tsdownBundler^0.xllms.txt | llms-full.txt
pnpmPackage manager^9.xDocs
TurboMonorepo orchestration^2.xDocs

Functional Programming

ToolPurposeCritical RulesDocumentation
ts-patternPattern matchingRequired for all conditionals with 2+ branches. No switch statements allowed.GitHub
es-toolkitFunctional utilitiesCheck before implementing custom helpers. Use pipe, map, filter, reduce from es-toolkit.GitHub

Validation & Types

ToolPurposeCritical RulesDocumentation
ZodSchema validationRequired at all boundaries (config, CLI args, API inputs).llms-full.txt
type-festType utilitiesUse for advanced type patterns (DeepReadonly, PartialDeep, etc.).GitHub

CLI Framework

ToolPurposeUsageDocumentation
yargsCLI argument parsingUsed in packages/maltty for argv parsing and command routing.GitHub
@clack/promptsCLI prompts & outputUsed for interactive prompts, spinners, and formatted terminal output.GitHub

Testing

ToolPurposeConfigurationDocumentation
VitestTesting frameworkWorkspace mode, unit tests colocated as *.test.ts, integration tests in test/integration/.GitHub

Linting & Formatting

ToolPurposeConfigurationDocumentation
OXC (oxlint)Linting.oxlintrc.json with strict functional programming rules.llms.txt
OXC (oxfmt)Formatting.oxfmtrc.json for code formatting.llms.txt

Versioning & Publishing

ToolPurposeUsageDocumentation
ChangesetsVersioning & changelogRun pnpm changeset to create changesets. GitHub Actions handles version bumps and npm publishing.GitHub

AI & Code Review

ToolPurposeConfigurationDocumentation
CodeRabbitAI code review.coderabbit.yaml with functional programming enforcement.Docs
Claude CodeAI coding assistantAGENTS.md (source of truth), CLAUDE.md (symlink).Anthropic

Design Rationale

Why ts-pattern?

TypeScript's switch statements don't provide exhaustive type narrowing. ts-pattern gives us:

  • Exhaustive matching enforced at compile time
  • Type narrowing based on discriminated unions
  • Expression-based (returns values, not statements)
  • Cleaner syntax for complex conditionals

Example:

import { match } from 'ts-pattern'

type Result<T, E> = { success: true; value: T } | { success: false; error: E }

const result = match(response)
  .with({ success: true }, ({ value }) => value)
  .with({ success: false }, ({ error }) => handleError(error))
  .exhaustive() // Compile error if cases missing

Why es-toolkit?

Lodash is imperative and mutable. Ramda is powerful but has a steep learning curve. es-toolkit provides:

  • Tree-shakeable ESM modules (smaller bundles)
  • TypeScript-first design (better inference)
  • Functional patterns without the Ramda complexity
  • Modern ESNext features (uses native methods when available)

Example:

import { pipe, map, filter, groupBy } from 'es-toolkit'

const result = pipe(
  users,
  filter((u) => u.active),
  map((u) => ({ ...u, name: u.name.toUpperCase() })),
  groupBy((u) => u.role)
)

Why Zod?

Runtime validation is critical for config files, CLI arguments, and API boundaries. Zod provides:

  • Static type inference from schemas (no duplication)
  • Composable validators (.refine(), .transform())
  • Readable error messages
  • Integration with Result types for error handling

Example:

import { z } from 'zod'

const configSchema = z.object({
  apiUrl: z.string().url(),
  timeout: z.number().positive().default(5000),
})

type Config = z.infer<typeof configSchema> // Inferred type

Why Vitest?

Jest is slow and requires heavy configuration. Vitest provides:

  • Native ESM support (no transpilation needed)
  • Blazing fast with Vite's transformation pipeline
  • Compatible with Jest's API (easy migration)
  • First-class TypeScript support
  • Watch mode that actually works

Why OXC?

ESLint is slow on large codebases. OXC (Oxidation Compiler) is:

  • Written in Rust (50-100x faster than ESLint)
  • Drop-in replacement for ESLint
  • Better error messages
  • Lower memory usage
  • Active development by the Rspack team

Version Requirements

RequirementMinimum VersionReason
Node.js22.xNative ES2022 features, import.meta, top-level await
pnpm9.xWorkspace protocol, catalog protocol, better lockfile
TypeScript5.7.xisolatedDeclarations, improved type inference

Excluded Technologies

These technologies are not used in this codebase:

TechnologyReason for Exclusion
ClassesViolates functional programming persona. Use factory functions.
LodashImperative, mutable. Use es-toolkit.
RamdaOverly complex for this use case. Use es-toolkit.
ESLintToo slow. Use oxlint.
PrettierUse oxfmt (faster, Rust-based).
JestToo slow, poor ESM support. Use Vitest.
BabelNot needed with modern TypeScript + tsdown.
WebpackUse tsdown (faster, simpler).

References