Projects/Personal Site/Architecture Decisions

ADR 004: Mise En Place

Context

Modern projects depend on a plethora of tools: node, python, terraform, go, cloudflare-cli, etc. Managing these dependencies presents several challenges:

  • Documentation Rot: READMEs instructing users to "install Python 3.11" inevitably go out of date or fail to specify patch versions, leading to "it works on my machine" issues.
  • Inconsistent Environments: Developers and CI/CD agents need to run in the exact same environment.
  • Task Sprawl: Scripts for building, testing, and deploying are often scattered across package.json, Makefile, shell scripts, or GitHub Actions workflow files.

I need a tool that:

  • Codifies the Environment: The code itself should document exactly what tools and versions are required.
  • Standardizes Tasks: A single interface to run common tasks (build, test, deploy) regardless of the underlying language or toolchain.
  • Simplifies CI/CD: Reduce CI configuration to "install environment -> run task".
  • Manages Configuration: Uniform handling of .env files and environment variables across tools.

Decision

I decided to use mise for both tool version management and task running.

Mise replaces tools like asdf, nvm, pyenv, and Make. It uses a TOML configuration file to define the exact versions of tools required and the tasks available in the project.

Consequences

Pros

  • Code as Documentation: The mise.toml file is the source of truth. Running mise install guarantees the correct environment, eliminating stale setup docs.
  • Standardized Interface: I can swap out the implementation of a task (e.g., changing from npm run build to turbo build) without changing the developer command (mise run build).
  • Monorepo Tasks: Supports monorepo patterns where tasks can be defined globally and overridden or composed at the directory level.
  • Environment Management: Built-in .env file support with hierarchical overrides allows for clean separation of secrets and config.
  • CI/CD Simplification: Pipelines become generic. Instead of custom actions for every tool, the workflow is simply mise install && mise run ci.
  • Power & Modernity: It offers features superior to Make (better argument handling, parallel execution) and Taskfile (integrated tool management).

Cons

  • Abstraction Layer: It adds an extra layer. Developers might run mise run build without knowing if it's invoking pnpm, cargo, or a shell script.
  • Complexity: It introduces another tool to the stack, whereas Make is available almost everywhere by default.
  • Too New: LLMs aren't familiar with it, it is not broadly adopted, so coding agents regularly ignore it and try to focus on using the underlying tools it's abstracting, resulting in an inconsistent experience.