# Plan: Instalar Claude Code system-wide (username-agnostic, última versión) en el Dockerfile ## Context El [Dockerfile](Dockerfile) instala Claude Code vía el repo apt oficial (`claude-code`, líneas 147‑155) desde el commit `7096b11`. Eso provocó dos problemas: 1. **Versión vieja**: el canal apt `stable` va por detrás del canal `latest`. En este contenedor hay `2.1.197`, mientras que `latest` ya está en `2.1.207`. 2. **MCPs no cargan**: verificado que es *estructural*, no de versión. El usuario declaró sus MCPs (gitea, docmost, github-personal, penpot, atlassian) bajo la clave `mcpServers` dentro de `~/.claude/settings.json`, pero **Claude Code no lee `mcpServers` desde `settings.json`**. `claude mcp list` lo confirmó: solo aparecen los conectores de claude.ai, ninguno de los del usuario. Los MCPs de usuario viven en `~/.claude.json` (archivo hermano de `.claude/`, no dentro), en `.mcp.json` de proyecto, o en `/etc/claude-code/managed-mcp.json` (enterprise). Intentos previos y por qué fallaron: - `curl … install.sh | bash` (commit original): deja el binario en `~/.local/bin` del usuario que instala (root) → inalcanzable para otros HOME_USER. - `HOME=/usr/local/claude … install.sh` (`be1a141`): el binario resuelve su home por el registro del SO, ignoró el override y volvió a caer en `/root`. - apt `claude-code` (`7096b11`): quedó en `/usr/bin` (bien para multi-usuario) pero atado al canal `stable` desactualizado. **Objetivo**: que `claude` esté disponible por defecto para **cualquier nombre de usuario** del SO, siempre en la **última versión**, con **auto-update en runtime** funcionando, y sin depender de trucos de `$HOME`/`.bashrc`. ## Alcance (confirmado con el usuario) - **Este repo (Dockerfile)**: SOLO arreglar la instalación de Claude Code. - **MCPs**: NO se toca la imagen. Se documenta la guía para que el usuario los reubique vía sus volúmenes (sección "Guía MCPs" abajo). ## Enfoque recomendado Descargar el binario nativo standalone directamente del canal oficial `latest` (el mismo artefacto que `install.sh` usa internamente), verificar su checksum, y colocarlo en `/usr/local/bin/claude` (modo 0755, root). Esa ruta ya está en el PATH por defecto de todo usuario (igual que `gh`, `kubectl`, `docker`), así que es completamente independiente del nombre de usuario y no necesita exports en `.bashrc`. El auto-update en runtime sigue funcionando **por usuario**: el updater nativo descarga nuevas versiones en el propio `~/.local/share/claude/versions/` de cada usuario, independiente del binario root de `/usr/local/bin`. La línea existente `export PATH="$HOME/.local/bin:$PATH"` (línea 176) hace que esa copia actualizada por usuario tome precedencia. El binario base de la imagen se refresca además en cada build de CI. ## Cambios en [Dockerfile](Dockerfile) ### 1. Reemplazar el bloque apt (líneas 147‑155) por descarga directa del binario `latest` `python3` ya está disponible en esta etapa (viene de `python3-pip`), así que se usa para parsear el `manifest.json` de forma robusta. El base es Debian/glibc → variante `linux-` (no musl). ```dockerfile # Installing Claude Code (system-wide, latest native build, accessible by any user) # Pull the standalone native binary straight from the official 'latest' release # channel (the same artifact install.sh uses internally) and drop it on the # system PATH at /usr/local/bin -- already on every user's PATH, like gh/kubectl. # Avoids install.sh's per-user ~/.local/bin layout (unreachable for other users) # and the apt 'stable' channel lag that shipped an outdated build. Runtime # auto-update still works per user: the native updater writes new versions into # each user's own ~/.local/share/claude/versions. RUN set -eux; \ case "$(dpkg --print-architecture)" in \ amd64) CC_ARCH=x64 ;; \ arm64) CC_ARCH=arm64 ;; \ *) echo "unsupported architecture: $(dpkg --print-architecture)" >&2; exit 1 ;; \ esac; \ CC_BASE="https://downloads.claude.ai/claude-code-releases"; \ CC_VERSION="$(curl -fsSL "${CC_BASE}/latest")"; \ CC_CHECKSUM="$(curl -fsSL "${CC_BASE}/${CC_VERSION}/manifest.json" \ | python3 -c "import sys,json;print(json.load(sys.stdin)['platforms']['linux-${CC_ARCH}']['checksum'])")"; \ curl -fsSL "${CC_BASE}/${CC_VERSION}/linux-${CC_ARCH}/claude" -o /tmp/claude; \ echo "${CC_CHECKSUM} /tmp/claude" | sha256sum -c -; \ sudo install -m 0755 -o root -g root /tmp/claude /usr/local/bin/claude; \ rm -f /tmp/claude; \ claude --version ``` ### 2. Eliminar la línea de auto-update específica de apt (líneas 177‑178) ```dockerfile # Let Claude Code auto-upgrade its apt package in the background when a new version ships RUN echo 'export CLAUDE_CODE_PACKAGE_MANAGER_AUTO_UPDATE=1' | sudo tee -a /usr/bin/.bashrc ``` Ya no aplica (no es instalación apt). El auto-update nativo funciona por defecto sin esa env var. Se **conserva** la línea 176 (`export PATH="$HOME/.local/bin:$PATH"`) porque es de propósito general y ayuda a que el claude auto-actualizado por usuario tome precedencia. ### 3. Bump de versión en [README.md](README.md) `1.4.1` → `1.4.2` (mismo patrón que los commits previos). ## Guía MCPs (fuera de la imagen — lo aplica el usuario en sus volúmenes) Causa raíz: `mcpServers` en `~/.claude/settings.json` es ignorado. El resto de `settings.json` (`permissions`, `hooks`, `model`, `enabledPlugins`, `env`, `theme`, etc.) **sí es válido y se queda ahí**. Pasos: 1. Mover el bloque `mcpServers` de `~/.claude/settings.json` al archivo `~/.claude.json` (en el HOME, hermano del directorio `.claude/`), como clave top-level: ```json { "mcpServers": { "gitea": { "type": "http", "url": "…", "headers": { … } }, "docmost": { … } } } ``` 2. Persistir `~/.claude.json` en el volumen por usuario, montado **read-write** (Claude reescribe ese archivo con historial de proyectos; no debe ser read-only). El volumen actual que monta `~/.claude/` no lo cubre porque `~/.claude.json` está fuera de ese directorio. 3. Borrar el bloque `mcpServers` obsoleto de `settings.json` para evitar confusión. ## Verificación 1. **Build**: `docker build -t vscode-server:test .` (o vía el workflow de Gitea). Confirmar que el nuevo `RUN` imprime `claude --version` = `2.1.207` (o superior) sin error de checksum. 2. **Multi-arch**: el `case` cubre amd64/arm64; el build de CI es `linux/amd64,linux/arm64`. 3. **Username-agnostic**: correr el contenedor y, como el usuario por defecto y como otro usuario distinto, verificar `which claude` → `/usr/local/bin/claude` y que `claude --version` responde. 4. **Auto-update runtime**: tras un rato de uso, confirmar que aparece `~/.local/share/claude/versions/` en el home del usuario (update nativo por usuario) sin permisos root. 5. **MCPs** (tras aplicar la guía en el volumen): `claude mcp list` debe listar gitea/docmost/ github-personal/penpot/atlassian como `Connected`.