Saltar al contenido

Lección 03 · 24 en la ruta · 4 min de lectura · Nivel 1

Homebrew y shell

Homebrew, Claude Code, gh, PATH que sirve también por SSH

La historia detrás de esta lección Homebrew y el archivo del shell que decide si SSH funciona

Instalar Homebrew en una Mac es de las cosas más rutinarias que existen. Lo que no es rutinario es instalarlo pensando en que el que va a usar esas herramientas no soy yo sentado frente a la Terminal, sino un agente que entra por SSH. Ese cambio de punto de vista me enseñó una diferencia de zsh que no conocía. Los comandos exactos están en el paso Homebrew y shell de la guía.

La instalación

El instalador oficial de Homebrew instala por su cuenta las Xcode Command Line Tools si faltan, y pide la contraseña de administrador. Esa parte la hice yo a mano. Es una regla de esta serie: todo lo que pide contraseña lo hago yo, no un agente.

Después instalé Claude Code con su instalador nativo y gh, el cliente de GitHub. Y ahí vino el primer tropiezo: claude: command not found justo después de instalarlo. El instalador deja el binario en ~/.local/bin, que no está en el PATH.

El concepto: qué archivo lee zsh y cuándo

La solución obvia es agregar el PATH al ~/.zshrc. Es lo que hace casi toda la documentación. Pero tiene una trampa que solo se ve cuando llega un comando remoto.

zsh lee archivos distintos según cómo se abra:

ArchivoTerminal de la Macssh mac "comando"
~/.zshenvsísí
~/.zprofilesí (es login)no
~/.zshrcsí (es interactiva)no

Cuando ejecuto ssh mac "comando", zsh arranca como shell no interactivo y no-login. Ese tipo de shell solo lee ~/.zshenv. Si el PATH está en .zshrc, todo funciona en la Terminal de la Mac y todo falla por SSH con command not found. Es un fallo que engaña: pruebas sentado en la Mac, ves que funciona y concluyes que está bien.

Por eso mi ~/.zshenv tiene dos líneas: una que agrega ~/.local/bin al PATH y otra con brew shellenv. La prueba de que quedó bien fue correr desde Windows ssh mac 'command -v git jq tmux shellcheck gh' y ver que cada herramienta se resolvía a su ruta en /opt/homebrew/bin.

Herramientas base, sin reinstalar nada

Los scripts que despachan trabajo necesitan jq, tmux, coreutils, un bash moderno y shellcheck. Si falta una, la tarea falla a mitad de camino y sin nadie mirando. Por eso, antes de instalar, comprobé qué había con brew list --versions. En mi Mac ya estaban todas, así que no instalé nada. Instalar solo lo que falta es lo que hace repetible el procedimiento: otra persona puede correr los mismos comandos y no pisa lo que ya tiene.

Dos avisos más que conviene conocer:

  • brew trust. Para instalar deskflow hubo que confiar explícitamente en su tap de terceros.
  • brew doctor avisó que las Command Line Tools estaban desactualizadas. Se arregla desde Actualización de software, y es el tema del post 05.

Carpetas simétricas

Creé en la Mac la misma estructura de carpetas que tengo en Windows: Documents/Portfolio/<repo>. Varias herramientas resuelven rutas relativas a esa carpeta, y mantener las dos máquinas simétricas me ahorra una clase entera de errores.

El login que caducó

El último tropiezo de esta etapa fue que gh auth status en la Mac decía “The token in default is invalid”. En ese momento lo tomé por un token caducado. Más adelante resultó ser otra cosa: el token estaba guardado en el llavero de macOS, al que una sesión SSH no puede entrar. Esa historia es la parte central de Una noche con un agente desatendido.

Lo que me llevo

Si una herramienta tiene que funcionar para quien llega por SSH, el PATH va en ~/.zshenv. Y cuando pruebes algo en un nodo remoto, pruébalo como lo va a usar el agente: con ssh mac "comando", no sentado en la Terminal.

Siguiente: la llave SSH, y el error que cometí por pegar un bloque de comandos que tenía una contraseña de por medio.

Objetivo

La Mac con Homebrew, Claude Code, gh y las herramientas base, todas visibles también para los comandos que llegan por SSH (ssh mac 'git --version' responde, no dice command not found).

Por qué

Homebrew es el gestor de paquetes de facto en macOS. Las herramientas base (jq, tmux, coreutils, un bash moderno, shellcheck) son las que usan los scripts que despachan trabajo: si falta una, la tarea falla a mitad de camino y sin nadie mirando.

Y hay un concepto que decide si todo funciona por SSH: zsh lee archivos distintos según cómo se abra. Un comando remoto (ssh mac "cmd") abre un zsh no interactivo y no-login, que solo lee ~/.zshenv:

ArchivoTerminal de la Macssh mac "comando"
~/.zshenvsísí
~/.zprofilesí (es login)no
~/.zshrcsí (es interactiva)no

Si el PATH vive en .zshrc, todo funciona en la Terminal de la Mac y todo falla por SSH.

Pasos

1. Homebrew (a mano: pide tu contraseña)

mac$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

El instalador oficial instala por su cuenta las Xcode Command Line Tools si faltan, y pide la contraseña (sudo). Al terminar imprime unas líneas “Next steps”: no las pegues todavía, primero lee el paso 3.

2. Claude Code y GitHub CLI

mac$ curl -fsSL https://claude.ai/install.sh | bash
mac$ brew install gh

El login de gh se hace con navegador, en la Terminal de la Mac (no por SSH):

mac$ gh auth login -h github.com

(captura del entorno real: no se publica; ver docs/CAPTURAS.md para las del modo demo)

La captura muestra HTTPS, Login with a web browser, un código de un solo uso (tapado) y Logged in as …. Lo último que imprime es “You were already logged in to this account”: ya había un login previo. Ver “Qué salió mal” para por qué esto importa.

3. El PATH va en ~/.zshenv

mac$ cat ~/.zshenv
export PATH="$HOME/.local/bin:$PATH"
eval "$(/opt/homebrew/bin/brew shellenv zsh)"

Prueba, desde Windows, de que quedó bien:

PS> ssh mac 'command -v git jq tmux shellcheck gh'
/opt/homebrew/bin/git
/opt/homebrew/bin/jq
/opt/homebrew/bin/tmux
/opt/homebrew/bin/shellcheck
/opt/homebrew/bin/gh

4. Herramientas base (idempotente: primero se comprueba)

PS> ssh mac 'brew list --versions git jq bash coreutils tmux shellcheck gh'
PS> ssh mac 'brew list --cask --versions visual-studio-code ghostty deskflow'

Si falta alguno: brew install git jq bash coreutils tmux shellcheck y brew install --cask visual-studio-code ghostty. En esta Mac ya estaban todos:

(captura del entorno real: no se publica; ver docs/CAPTURAS.md para las del modo demo)

5. Carpetas simétricas

PS> ssh mac 'mkdir -p ~/Documents/Portfolio'

La Mac usa la misma estructura que Windows (Documents/Portfolio/<repo>), porque varias herramientas resuelven rutas relativas a esa carpeta.

Qué salió mal de verdad

  1. claude: command not found justo después de instalar Claude Code. El instalador lo pone en ~/.local/bin, que no estaba en el PATH. Arreglo: PATH y brew shellenv en ~/.zshenv, no en .zshrc (ver “Por qué”).
  2. brew install deskflow → “Refusing to load cask from untrusted tap”. Homebrew exige confiar explícitamente en los taps de terceros: brew trust deskflow/tap y luego instalar.
  3. brew doctor: “Your Command Line Tools are too outdated”. Se arregla desde Ajustes → General → Actualización de software (instala la versión nueva de las CLT). Reapareció tras actualizar macOS: ver 06-actualizar-macos.md.
  4. gh auth status por SSH: “The token in default is invalid”. La sesión 1 lo diagnosticó como “el login caducó”. Después se vio que probablemente era otra cosa: el token estaba bien, pero guardado en el llavero de macOS, que una sesión SSH no puede abrir. Evidencia: la captura 07 muestra un gh auth login exitoso en la Mac antes de esa sesión, y más tarde gh auth login respondió “ya estabas logueado”. Que ese login previo sea la causa del “invalid” es una inferencia; lo que sí está medido (en la corrida nocturna) es el bloqueo del llavero por SSH. Detalle y opciones en 09-agente-desatendido.md.

Cómo verificar

PS> ssh mac 'command -v git jq tmux shellcheck gh'

Debe imprimir cinco rutas bajo /opt/homebrew/bin/, y

PS> ssh mac 'claude --version'
2.1.289 (Claude Code)

(Versiones al 2026-10-04: Homebrew 7.0.7, Claude Code 2.1.289.)

Autoevaluación

  1. ¿Por qué el PATH va en ~/.zshenv y no en ~/.zshrc?
    Respuesta`ssh mac "cmd"` abre un zsh no interactivo y no-login, que solo lee `~/.zshenv`.
  2. ¿Qué significa “idempotente” en el paso 4?
    RespuestaSe comprueba antes de instalar y, si ya está, no se toca: correrlo dos veces da el mismo resultado que una.
  3. gh auth login funciona en la Terminal de la Mac pero falla por SSH. ¿Dónde buscas?
    RespuestaEn dónde se guardó el token: el llavero de macOS no se abre desde una sesión SSH.
Se guarda solo en este navegador.