Saltar al contenido principal

Gestión de herramientas — Homebrew + mise

"Un lugar para cada cosa, y cada cosa en su lugar."

En Wiedii toda herramienta tiene un nivel definido. La arquitectura es de 3 niveles, cada uno con responsabilidad clara:

Homebrew instala herramientas del sistema. mise global gestiona runtimes de lenguaje disponibles en toda la máquina. mise por proyecto fija las versiones exactas de cada repo.


El problema que este estándar resuelve

Sin una política clara de instalación, los entornos se degradan:

  • Dev A tiene bun 1.1.0 global, dev B tiene bun 1.2.0. El mismo comando produce resultados distintos.
  • Un npm install -g instala algo que rompe otra herramienta ya existente.
  • Una máquina nueva requiere recordar 15 comandos distintos de instalación.
  • curl | bash ejecuta código de internet sin revisión, con privilegios de tu usuario.

Este estándar elimina todos esos problemas con tres niveles y una regla por nivel.


Nivel 1 — Homebrew: herramientas del sistema

Herramientas que pertenecen al sistema operativo y no tienen versión por proyecto: CLIs de trabajo, aplicaciones de escritorio, utilidades del sistema.

HerramientaPor qué en Homebrew
miseEl gestor de versiones en sí debe estar en el sistema
git-flow-nextExtiende git — herramienta del sistema
glabCLI de GitLab — herramienta de trabajo
bat, eza, fd, ripgrep...Utilidades de terminal — disponibles en todo el sistema
OrbStack, Visual Studio Code, Microsoft Teams...Aplicaciones de escritorio
brew install mise git-flow-next glab
brew install bat eza fd ripgrep sd starship
brew install orbstack visual-studio-code microsoft-teams

brew install sin --cask: En Homebrew moderno no es necesario especificar --cask explícitamente. Homebrew resuelve automáticamente si el paquete es una formula (CLI/librería) o un cask (app de escritorio). El flag --cask sigue siendo válido pero genera acoplamiento innecesario con la estructura interna del repositorio de Homebrew, que puede cambiar. brew install <nombre> siempre funciona.

Homebrew nunca instala runtimes de lenguaje en Wiedii:

# ❌ Nunca — los runtimes van en mise
brew install bun
brew install node
brew install python

Nivel 2 — mise global: runtimes de lenguaje

Runtimes de lenguaje disponibles en todo el sistema como versión base o fallback cuando un proyecto no especifica la suya. Se configuran en ~/.config/mise/config.toml.

Config global de Wiedii (~/.config/mise/config.toml):

[tools]
bun = "1.3.14"
node = "24.16.0"
pnpm = "11.2.2"
python = "3.14.5"
uv = "0.11.16"

[settings]
lockfile = true # genera mise.lock para reproducibilidad

Estos runtimes están disponibles en cualquier directorio, incluso fuera de un proyecto:

cd ~
bun --version # ✅ 1.3.14 (desde mise global)
node --version # ✅ v24.16.0
python --version # ✅ Python 3.14.5

Para actualizar una versión global:

mise use --global bun@1.3.14
mise use --global node@24.16.0

pnpm está disponible globalmente pero los proyectos Wiedii usan bun. pnpm queda como fallback de compatibilidad.


Nivel 3 — mise por proyecto: versiones exactas

Cada repo declara en mise.toml las versiones exactas que necesita. Al entrar al directorio, mise activa esas versiones sobreescribiendo las del nivel global.

# mise.toml en un repo Wiedii
[tools]
bun = "1.2.5" # sobreescribe el 1.3.14 global
lefthook = "1.9.0" # solo disponible en este directorio

[tasks.setup]
run = [
"mise trust",
"mise install --yes",
"bun install",
"lefthook install"
]
description = "Configura el entorno completo del proyecto"
# Prioridad en acción:
cd proyecto-alpha && bun --version # 1.2.5 (del mise.toml del proyecto)
cd proyecto-beta && bun --version # 1.1.8 (del mise.toml del proyecto)
cd ~ && bun --version # 1.3.14 (del mise global)

Contaminación cero entre proyectos. El proyecto siempre gana sobre el global.


Agregar herramientas a mise: elegir el backend correcto

Cuando una herramienta va en mise.toml, la siguiente pregunta es: ¿qué backend usar?

El registro de mise

mise-versions.jdx.dev es el catálogo oficial de herramientas disponibles en mise con todos sus backends. Antes de declarar cualquier herramienta en un mise.toml, verificar en este registro qué backends tiene disponibles.

Ejemplo: terraform tiene múltiples backends — mise-versions.jdx.dev/tools/terraform. Siempre se elige aqua si está disponible.

Prioridad de backends

PrioridadBackendCuándo usarlo
aquaSiempre que esté disponible. Es el registro curado de mise con checksums verificados.
npmCLI de npm que no tiene sentido en package.json (herramienta global de proyecto, no dependencia).
pipxCLIs de Python que no van en pyproject.toml.
cargoHerramientas Rust no disponibles en aqua.
asdfSolo si ningún otro backend está disponible. Es la opción heredada.
# Ejemplo: terraform usa aqua (backend preferido)
[tools]
terraform = "1.8.0" # aqua por defecto si está en el registro

# Si la herramienta solo existe en cargo:
"cargo:taplo-cli" = "latest"

# Si la herramienta solo existe como npm package sin sentido en package.json:
"npm:@anthropic/claude-cli" = "latest"

📄 Registro completo de herramientas


La regla del package manager nativo

Si una herramienta pertenece al ecosistema del lenguaje del proyecto, va en el gestor de paquetes nativo — no en mise.toml.

El criterio: ¿esta herramienta se instala con bun install, pip install, go get? Si sí, va en el archivo de dependencias del proyecto, no en mise.

HerramientaDónde vaPor qué
prettierpackage.json devDependenciesEs una dep JS — se instala con bun install, se versiona con el proyecto
eslintpackage.json devDependenciesÍdem
typescriptpackage.json devDependenciesÍdem
ruffpyproject.toml o mise.tomlHerramienta Python — ambas opciones válidas
mypypyproject.toml o mise.tomlÍdem
golangci-lintmise.toml ✅ (ver excepción Go)No puede ir en go.mod
lefthookmise.tomlGit hook runner — versión exacta por proyecto, fuera del ecosistema JS/Go/Python
taplomise.tomlFormateador TOML — no pertenece a ningún ecosistema concreto
terraformmise.tomlCLI de infraestructura — sin relación con el lenguaje del proyecto
# ❌ No: prettier en mise.toml
[tools]
prettier = "3.2.5" # prettier pertenece al package.json

# ✅ Correcto: prettier en package.json
# "devDependencies": { "prettier": "^3.2.5" }
# Se instala con: bun install
# Se ejecuta con: bun prettier

La razón es práctica: prettier en package.json significa que todos los devs lo obtienen con bun install, tiene lockfile de bun, se puede ejecutar con bun prettier sin PATH magic, y el CI lo instala en el mismo paso que las demás dependencias.


La excepción de Go

En proyectos Go, go.mod solo registra librerías que se importan en el código. Go es estricto en esto por diseño: si un paquete no tiene un import en el código, go mod tidy lo elimina del go.mod.

Esto significa que las herramientas de desarrollo de Go (linters, generadores de código, herramientas de migración…) no pueden ir en go.mod aunque estén escritas en Go. Son ejecutables, no librerías.

Por eso, todas las CLIs de Go que el proyecto necesita van en mise.toml:

# mise.toml — proyecto Go
[tools]
go = "1.22.0"

# ← Herramientas Go que NO pueden ir en go.mod (son executables, no imports):
golangci-lint = "1.57.2" # linter
migrate = "4.17.0" # golang-migrate — migraciones de DB
mockgen = "0.3.0" # generador de mocks
air = "1.51.0" # live reload para desarrollo

Verificar el backend disponible para cada una antes de agregarla:


La regla de instalación — árbol de decisión

¿Es una herramienta que usaré en cualquier directorio del sistema?

├── SÍ → ¿Es un runtime de lenguaje (bun, node, python, uv…)?
│ ├── SÍ → mise use --global <tool>@<version>
│ │ (en ~/.config/mise/config.toml)
│ └── NO → ¿Existe en Homebrew?
│ ├── SÍ → brew install <herramienta>
│ └── NO → Solicitar autorización al TL
│ → Instalar por método oficial del proveedor
│ → Documentar excepción en el vault

└── NO → Es una herramienta específica de un proyecto

├── ¿Pertenece al ecosistema del lenguaje del proyecto?
│ (prettier/eslint en JS, ruff/mypy en Python…)
│ │
│ ├── SÍ → ¿Es un proyecto Go?
│ │ ├── SÍ → mise.toml (go.mod no acepta executables)
│ │ └── NO → package.json / pyproject.toml / etc.
│ │ (bun install / uv sync / etc.)
│ │
│ └── NO → mise.toml del repo
│ └── Verificar backend en mise-versions.jdx.dev
│ (prioridad: aqua > npm > pipx > cargo > asdf)

└── mise install --yes (o mise run setup)

La regla se extiende a todo — incluyendo GUI apps

Homebrew gestiona todo lo que entra en el sistema. Esto incluye navegadores, editores, clientes de comunicación y aplicaciones de escritorio.

Nunca se descarga un instalador .dmg, .pkg o .zip de una página web en Wiedii.

# ✅ Correcto — navegadores, editores y apps por brew
brew install brave-browser
brew install visual-studio-code
brew install microsoft-teams
brew install nordvpn

# ❌ Nunca en Wiedii
# Ir a chrome.com → descargar .dmg → arrastrar a /Applications
# Ir a code.visualstudio.com → descargar .zip → instalar manualmente

brew bundle dump genera un Brewfile para replicar el entorno completo en una máquina nueva:

brew bundle dump --file=~/Brewfile --force # snapshot
brew bundle install --file=~/Brewfile # restaurar en máquina nueva

✅ Correcto vs ❌ Incorrecto

# ✅ CLI del sistema → Homebrew
brew install glab git-flow-next jq bat eza

# ✅ Aplicación de escritorio → Homebrew (resuelve formula o cask automáticamente)
brew install orbstack visual-studio-code microsoft-teams

# ✅ Runtime de lenguaje global → mise global
mise use --global bun@1.3.14
mise use --global node@24.16.0

# ✅ Herramienta de proyecto → mise.toml del repo
# (en mise.toml) bun = "1.2.5"
mise run setup

# ❌ Nunca curl | bash (salvo Homebrew en sí)
curl https://bun.sh/install | bash
curl https://mise.jdx.dev/install.sh | sh

# ❌ Nunca instalaciones globales de npm/bun
npm install -g typescript
bun install -g eslint

# ❌ Nunca runtimes de lenguaje por brew
brew install bun
brew install node

# ❌ Nunca binarios descargados a mano ni instaladores de webs (sin autorización del TL)
wget https://ejemplo.com/herramienta.tar.gz
# chrome.com → .dmg, teams.microsoft.com → .pkg, etc.

# ⚠️ Excepción — si la herramienta NO existe en Homebrew:
# Solicitar autorización al TL → documentar en el vault → instalar
# Ver sección "Excepciones documentadas" más abajo

Excepciones documentadas

Excepción 1 — Bootstrap de Homebrew: Homebrew mismo se instala con curl | bash porque no hay alternativa en macOS. Es el único curl | bash aceptado. Una vez instalado, todo lo demás va por sus 3 niveles.

Excepción 2 — Herramienta no disponible en Homebrew: Si una herramienta genuinamente no existe en Homebrew (ni como formula ni como cask), puede instalarse por el método que el proveedor oficial indique — pero únicamente con autorización explícita del TL antes de proceder.

El proceso:

  1. Verificar que la herramienta no está en Homebrew: brew search <herramienta> + buscar en formulae.brew.sh
  2. Solicitar autorización al TL con justificación: por qué se necesita, de dónde se instala, qué permisos requiere
  3. El TL autoriza y documenta la excepción en la nota de la herramienta dentro del vault
  4. La instalación queda registrada en el CLAUDE.md o en la nota correspondiente del proyecto

Sin autorización del TL, la política Homebrew-first aplica sin excepción. La duda es siempre razón para preguntar antes de instalar.


Por qué no npm install -g ni bun install -g

  • Quedan fuera del control de versiones — nadie sabe qué hay instalado ni por qué.
  • Pueden colisionar con otras herramientas globales.
  • No tienen lockfile — cada dev acaba con versiones distintas sin saberlo.
  • No se desinstalan limpiamente.

La alternativa correcta siempre es mise use --global (para runtimes) o declarar en mise.toml del proyecto.


Beneficios del modelo

Reproducibilidad: mise run setup en una máquina nueva produce exactamente el mismo entorno. Sin pasos manuales extra.

Prioridad clara: proyecto > global > sistema. Nunca hay ambigüedad sobre qué versión se usa.

Limpieza: brew list muestra herramientas del sistema. mise ls muestra runtimes activos. Inventario completo y auditable.

Seguridad: Homebrew y mise descargan con checksums verificados. curl | bash ejecuta código arbitrario sin verificación.

Onboarding predecible: brew install mise git-flow-next glab → configurar git y SSH → copiar ~/.config/mise/config.toml → clonar repo → mise run setup. Sin ambigüedad.


Referencias oficiales

mise

Homebrew


Documentos relacionados

  • mise — nota completa: bondades, features y comandos
  • guia-nuevo-dev — aplica este estándar paso a paso
  • mise-tooling — política detallada de mise.toml y comandos
  • KISS — el principio que inspira este estándar