Files
qwen3-6-lora/data/raw/sanitized/plans/desde-que-cambiamos-la-wobbly-flame.md

6.9 KiB
Raw Permalink Blame History

Plan: Instalar Claude Code system-wide (username-agnostic, última versión) en el Dockerfile

Context

El Dockerfile instala Claude Code vía el repo apt oficial (claude-code, líneas 147155) 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

1. Reemplazar el bloque apt (líneas 147155) 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-<arch> (no musl).

# 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 177178)

# 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

1.4.11.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:
    { "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.