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 -ginstala algo que rompe otra herramienta ya existente. - Una máquina nueva requiere recordar 15 comandos distintos de instalación.
curl | bashejecuta 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.
| Herramienta | Por qué en Homebrew |
|---|---|
mise | El gestor de versiones en sí debe estar en el sistema |
git-flow-next | Extiende git — herramienta del sistema |
glab | CLI 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 installsin--cask: En Homebrew moderno no es necesario especificar--caskexplícitamente. Homebrew resuelve automáticamente si el paquete es una formula (CLI/librería) o un cask (app de escritorio). El flag--casksigue 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
pnpmestá 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
| Prioridad | Backend | Cuándo usarlo |
|---|---|---|
| 1º | aqua | Siempre que esté disponible. Es el registro curado de mise con checksums verificados. |
| 2º | npm | CLI de npm que no tiene sentido en package.json (herramienta global de proyecto, no dependencia). |
| 3º | pipx | CLIs de Python que no van en pyproject.toml. |
| 4º | cargo | Herramientas Rust no disponibles en aqua. |
| 5º | asdf | Solo 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.
| Herramienta | D ónde va | Por qué |
|---|---|---|
prettier | package.json devDependencies | Es una dep JS — se instala con bun install, se versiona con el proyecto |
eslint | package.json devDependencies | Ídem |
typescript | package.json devDependencies | Ídem |
ruff | pyproject.toml o mise.toml | Herramienta Python — ambas opciones válidas |
mypy | pyproject.toml o mise.toml | Ídem |
golangci-lint | mise.toml ✅ (ver excepción Go) | No puede ir en go.mod |
lefthook | mise.toml | Git hook runner — versión exacta por proyecto, fuera del ecosistema JS/Go/Python |
taplo | mise.toml | Formateador TOML — no pertenece a ningún ecosistema concreto |
terraform | mise.toml | CLI 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:
- Verificar que la herramienta no está en Homebrew:
brew search <herramienta>+ buscar en formulae.brew.sh - Solicitar autorización al TL con justificación: por qué se necesita, de dónde se instala, qué permisos requiere
- El TL autoriza y documenta la excepción en la nota de la herramienta dentro del vault
- La instalación queda registrada en el
CLAUDE.mdo 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
- Documentación oficial
- mise-versions.jdx.dev — catálogo de herramientas y backends
- mise-lock — lockfiles para reproducibilidad
- mise exec — ejecutar comandos con entorno aislado
- Tasks — runner de tareas integrado
- Trusted configs — modelo de seguridad
- Registry de herramientas soportadas
- Backends disponibles (aqua, npm, pipx, cargo, asdf)
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