⚡ En 30 segundos
chezmoi (de twpayne, escrito en Go, MIT) gestiona tus dotfiles —.bashrc, .gitconfig, claves SSH…— a través de varias máquinas distintas y de forma segura. Guardas una sola copia versionada en git (el source state), y chezmoi calcula y aplica los ficheros reales en cada máquina (el target state), resolviendo las diferencias por host con plantillas Go y guardando los secretos cifrados.
Por qué importa: no es un repo de IA-agentes, pero es un caso de estudio precioso de motor declarativo de reconciliación de estado (el mismo patrón que Terraform o Kubernetes, aplicado a tu home). El diseño —System componible, estado en SHA256, atributos codificados en el nombre del fichero— es directamente robable para cualquier herramienta que tenga que "llevar un sistema de un estado A a un estado deseado B".
Para quién: cualquiera con >1 portátil/servidor; y para ti, Raúl, como plantilla mental de arquitectura idempotente que reusar en tus micro-SaaS.
chezmoi documentados🧠 El problema que resuelve
Tienes un portátil personal, uno del trabajo y un par de servidores. Quieres el mismo .zshrc en todos… pero no exactamente el mismo: tu email de git cambia entre personal y trabajo, en el server no quieres tu config de GUI, y tu clave SSH privada no puede acabar en texto plano en un repo público de GitHub.
Las soluciones caseras (un repo de dotfiles + symlinks con stow, o un script de bash) se rompen justo en esos tres puntos: variación por máquina, secretos y idempotencia (volver a correr el script sin romper nada ni preguntar dos veces). chezmoi resuelve los tres como ciudadanos de primera clase:
- Variación → cada fichero puede ser una plantilla Go (
.tmpl) con datos del host (.chezmoi.os, hostname, etc.). - Secretos → integración con age y gpg; en el estado persistente solo guarda el SHA256, nunca el contenido.
- Idempotencia → modela el problema como reconciliación de estado: calcula el destino deseado, lee el real y aplica solo el delta mínimo.
La idea central, citando el doc de arquitectura: "chezmoi evalúa el source state para computar un target state del destino, lo compara con el estado real y aplica los cambios necesarios". Es Terraform para tu $HOME.
🏗 Arquitectura
Lectura del diagrama: el source state (tu repo git) se transforma en el target state ejecutando plantillas y descifrando. chezmoi lee el actual state (lo que hay en disco), calcula el delta mínimo y solo escribe lo que difiere (no reescribe ficheros idénticos). El persistent state guarda el SHA256 de cada entry escrito: así detecta si un tercero modificó un fichero desde la última vez (y avisa antes de pisarlo), y decide si re-ejecutar los scripts run_once_ / run_onchange_.
🔑 Conceptos / técnicas clave
SourceStateEntry, TargetStateEntry, ActualStateEntry, PersistentState. Entender estos cuatro = entender el 80% del repo.dot_bashrc → .bashrc; private_ quita permisos de grupo/mundo; executable_ pone el bit +x; encrypted_ está cifrado; .tmpl es plantilla; exact_ en un dir borra lo no declarado. Parseados por FileAttr / DirAttr. Truco elegante: el sistema de ficheros es la base de datos.System componible (decorator pattern) — toda interacción con el SO pasa por la interfaz System. El real es RealSystem; --dry-run lo envuelve en DryRunSystem (lee de verdad, descarta escrituras); --debug lo envuelve en DebugSystem (loguea cada llamada). Añadir un modo nuevo = un wrapper nuevo, cero cambios en el core. Patrón clave a robar..tmpl se ejecuta con datos del host (.chezmoi.os, hostname, variables de config). Así un único dot_gitconfig.tmpl rinde tu email personal en un host y el del trabajo en otro. chezmoi execute-template y chezmoi data sirven para depurarlas.run_ idempotentes — ficheros con prefijo run_ se ejecutan en cada apply. run_once_ solo si su SHA256 no se ha visto antes (instalación inicial). run_onchange_ solo si su contenido cambió (re-aplicar al editar). Modificadores before_/after_ controlan el orden. El registro vive en el bucket scriptState/entryState del estado persistente.Encryption con dos implementaciones, AGEEncryption y GPGEncryption (y un DebugEncryption que loguea). Como el estado persistente solo guarda hashes SHA256 y no contenidos, los secretos nunca tocan la DB de chezmoi.AbsPath vs RelPath vs SourceRelPath vs ExtPath son tipos Go distintos, así el compilador impide bugs como unir dos paths absolutos. Todo se normaliza a forward-slashes internamente. Disciplina de tipos que evita una clase entera de errores cross-platform.Comandos que de verdad usas a diario
| Comando | Qué hace |
|---|---|
chezmoi init $USER | Clona tu repo de dotfiles de GitHub al source dir (con --apply lo aplica de una). El "bootstrap de máquina nueva". |
chezmoi add $FILE | Mete un fichero de tu home al source state (con --template lo añade como plantilla). |
chezmoi edit $FILE | Abre el editor sobre la versión source del fichero (--apply lo aplica al guardar). |
chezmoi diff | Muestra el delta que haría apply, sin tocar nada. |
chezmoi status | Resumen rápido de qué cambiaría. |
chezmoi apply | Reconcilia: pone tu home igual al target state. |
chezmoi update | git pull del remoto + apply. El "sincroniza esta máquina". |
chezmoi doctor | Diagnostica problemas comunes. Lo primero a correr si algo va raro. |
chezmoi execute-template | Ejecuta una plantilla suelta para testear/depurar. |
chezmoi managed / unmanaged | Lista qué controla (o no controla) chezmoi. |
🗂 Mapa de ficheros importantes
| Ruta | Para qué sirve |
|---|---|
internal/chezmoi/ | El core. Aquí viven System, SourceState, los *StateEntry, Encryption, el persistent state y el manejo de paths. Si quieres entender el motor, empieza aquí. |
internal/cmd/*cmd.go | Un fichero por subcomando (applycmd.go, addcmd.go…). Los comandos son métodos del struct Config, que centraliza toda la configuración. |
internal/cmd/*templatefuncs.go | Funciones de plantilla disponibles dentro de los .tmpl. |
internal/cmd/testdata/scripts/*.txtar | Tests end-to-end con testscript: cada .txtar es un guion ejecutable que monta un FS falso y verifica comandos reales. Oro para ver comportamiento esperado sin leer código. |
assets/chezmoi.io/docs/ | Única fuente de verdad de la documentación: la web chezmoi.io, el help y los ejemplos se generan de aquí. 91 de los ficheros del repo son .md. |
assets/chezmoi.io/docs/developer-guide/architecture.md | El doc que resume toda la arquitectura en una página. Léelo si vas a contribuir. |
assets/chezmoi.io/docs/reference/target-types.md | La referencia de TODOS los prefijos de fichero (dot_, private_, run_once_, exact_, symlink_…). Tu chuleta para nombrar ficheros. |
.config/goreleaser.yaml · golangci.yml | Release multiplataforma y linting. Pipeline de un proyecto Go serio. |
🎯 Qué puedes aplicar tú
- Usa chezmoi de verdad para tu propio setup solo-founder: el mismo
.zshrc, config de git, claves SSH (cifradas con age) y dotfiles de Claude Code replicados con unchezmoi init --applyen cada máquina o VM nueva. Bootstrap de entorno en un comando. - Roba el patrón de los 4 estados para cualquier herramienta tuya que tenga que "llevar un sistema de A a B": separa deseado / real / memoria y aplica solo el delta. Es el núcleo de todo motor idempotente (cron de ingesta, sync de posiciones de cartera, publicación de la biblioteca).
- Copia el decorator
System: define una interfaz para el efecto secundario (FS, API, DB) y envuélvela para tener--dry-runy--debuggratis. Para tus scripts que tocan D1/Cloudflare, unDryRunSystemequivalente te ahorra sustos. - Guarda hashes, no contenidos, en cualquier estado persistente que pueda rozar secretos. El truco del SHA256 evita filtrar credenciales aunque alguien lea tu DB de estado.
- Codifica intención en el nombre cuando el filesystem es tu fuente de verdad (lo haces ya con
ideas/{slug}/,run_once_de chezmoi es la versión madura de esa idea). - Mira los
.txtarde testscript como modelo de tests E2E declarativos para CLIs: montas un FS falso, corres comandos, aseveras el output. Aplicable a testear tus propios scripts de pipeline.
⚠️ Limitaciones / cuándo NO usarlo
- No es un repo de IA-agentes. Si tu objetivo es estudiar harnesses de agentes o generación de startups, chezmoi es relevante solo como patrón arquitectónico (motor declarativo idempotente), no como ejemplo de orquestación de LLMs. No hay agentes, skills ni prompts aquí.
- Curva de aprendizaje real: los prefijos mágicos en nombres de fichero (
private_dot_,encrypted_,run_onchange_before_…) son potentes pero crípticos al principio. Necesitastarget-types.mda mano. - Sensible a mayúsculas: el doc avisa de que chezmoi es case-sensitive internamente y no intenta manejar sistemas de ficheros case-insensitive/case-preserving — puede morder en algunos setups de macOS/Windows.
- Sobredimensionado para una sola máquina: si solo tienes un portátil y nunca lo reinstalas, un repo de dotfiles con symlinks (
stow) o cuatrocpte bastan. El valor de chezmoi aparece con variación entre hosts + secretos + máquinas nuevas frecuentes. - Atado a git y a su modelo: asume flujo git (commit/push/pull). Si no quieres versionar tus dotfiles, no es para ti.