Skip to content

⚡️ Drop the compiler, persist Claude Code, pull upstream fixes - #1239

Merged
elcajon merged 3 commits into
mainfrom
claude/eloquent-mccarthy-ew8l6k
Sep 18, 2026
Merged

elcajon merged 3 commits into
mainfrom
claude/eloquent-mccarthy-ew8l6k

Conversation

@elcajon

@elcajon elcajon commented Sep 18, 2026 •

Copy link
Copy Markdown
Owner

Proposed Changes

Dropping the compiler

build-essential and python3-dev were installed and purged again inside the
same layer, so they existed purely to compile Python packages during
pip install. Both are gone; their absence is the guard, since a dependency
that needs compiling now fails the build loudly.

Measured, cold cache both times:

with compiler without
Build amd64 (native, low noise) 3:40 2:43 −22%
Build aarch64 (QEMU) 9:54 9:29 within noise

Only the amd64 number is worth trusting: repeated aarch64 runs of the same tree
came in at 9:29 and 11:14, so QEMU throughput varies by more than this change
moves the needle there.

One behavioural change worth knowing: crcmod, esptool and paho-mqtt have
no aarch64 wheels and are built from sdists — that was already true before this
PR. They build fine without a compiler because the builds are pure Python, but
crcmod no longer builds its optional C accelerator (_crcfunext) and falls
back to the Python implementation. That affects checksum speed when flashing via
esptool, nothing else.

Claude Code configuration is persisted

Claude Code is not shipped in the image; users install the
Anthropic.claude-code extension from the Extensions view, which is published
on Open VSX and carries its own claude binary.

What this app adds is persistence, following upstream
(hassio-addons/app-vscode#1129): the service exports
CLAUDE_CONFIG_DIR=/data/claude, and the user init creates that folder and
migrates a login left behind in ~/.claude or ~/.claude.json, so logins and
settings survive restarts and updates. DOCS.md explains the installation, why
signing in has to happen from a terminal behind ingress, and where the bundled
binary sits for anyone who wants it on PATH.

Version constraints

wget and git-crypt lost their lower bounds in #1238: unquoted,
wget>=1.25.0-2 is a shell redirection; quoted, apt-get install splits at the
= and looks for a package called wget>. apt-get satisfy does take
relational constraints, so they now read

&& apt-get satisfy -y --no-install-recommends \
    "git-crypt (>= 0.7.0-0.1+b1)" \
    "wget (>= 1.25.0-2)" \

which is what #1224 wanted — git-crypt carries a different binNMU revision per
architecture (+b1 on amd64, +b2 on arm64), so an exact pin cannot cover both.
A second Renovate manager matches the "pkg (>= version)" spelling; verified
against the Dockerfile, 23 exact pins on the existing manager and 2 constraints
on the new one.

Fixes pulled from upstream app-vscode

  • The find cleanup bound its -exec to the last -o branch only, so only
    *.pyo files were ever removed — never the test, tests and __pycache__
    directories it lists.
  • 01-vs-mysql created /root/.config but writes the client config to
    /etc/mysql/conf.d/service.cnf, a directory it never created.
  • 01-vs-user linked ~/.ssh with ln -sn; when ~/.ssh exists as a real
    directory the link lands inside it as ~/.ssh/.ssh. It now clears that case,
    cleans up the nested link and uses ln -sfn (Fix SSH key symlink creating nested .ssh directory hassio-addons/app-vscode#1098).
  • 01-vs-mosquitto linked with plain ln -s, which fails on a re-run and
    reported nothing. Now ln -sf with a warning.
  • code-server/finish treated a stop by signal as a crash and never propagated
    an exit code to the container. It now reports the code, halts on SIGTERM and
    lets s6 restart only on a real crash.
  • code wrapper so files open in the running editor from a terminal, ha gets
    its zsh completion registered, and the esphome file association matches
    nested folders.

Deliberately not pulled, as discussed: the config_path option and /config as
the workspace, hassio_role: manager, the packages / init_commands options
(this app has custom services instead), the user-bundles.d layout,
python3-venv and /etc/motd (ha banner covers it).

Verification

hadolint 2.5.0, 2.8.0 and 2.14.0 clean; shellcheck clean on every changed
script, with no new findings; settings.json valid; the Renovate regexes run
against the Dockerfile; doc link references resolved both ways and added lines
within the 80-column limit. Both architectures built green on the previous two
heads.

Related Issues

Follow-up to #1238; restores the constraint intent from #1224.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Pwumst3pLFGsbbzLSxYQMv

`build-essential` and `python3-dev` were installed and purged again in
the same layer, so they existed purely to compile Python packages while
`pip install` ran. Installing them means dpkg unpacks and configures
some 50 extra packages, which on aarch64 happens under QEMU emulation
and is a large part of the ~290s dpkg phase.

Drop both. Their absence is the guard: a dependency that needs to be
compiled now fails the build loudly. `--only-binary=:all:` would be the
stricter version of the same idea, but it also rejects pure-Python
source distributions that install fine without a compiler, so it is left
out.

`wget` and `git-crypt` lost their version constraints in #1238 because
neither the unquoted nor the quoted `pkg>=version` spelling reaches apt.
`apt-get satisfy` does take relational constraints, so use it and give
them back the lower bounds #1224 asked for — git-crypt carries a
different binNMU revision per architecture (+b1 on amd64, +b2 on arm64),
which an exact pin cannot express. A second Renovate manager tracks the
`"pkg (>= version)"` spelling, so both are back on the dashboard.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pwumst3pLFGsbbzLSxYQMv
@elcajon elcajon added the performance Improving performance, not introducing new features. label Sep 18, 2026 — with Claude
Claude Code is installed into the image with the official installer and
linked into PATH, so `claude` works in every terminal. The service now
exports CLAUDE_CONFIG_DIR=/data/claude, and the user init creates that
folder and migrates a login left behind in ~/.claude or ~/.claude.json,
so logins and settings survive restarts and updates. Both the persistence
and the migration follow upstream's app-vscode.

Unlike everything else in this image, Claude Code is not version-pinned:
the installer is the only documented install path and it does not expose
a pinning interface that could be verified. It also updates itself at
runtime, into the container filesystem rather than /data, so a build-time
pin would say little about what is actually running.

Fixes pulled from upstream app-vscode:

- The `find` cleanup bound its `-exec` to the last `-o` branch only, so
  only *.pyo files were ever removed, never the test, tests and
  __pycache__ directories it lists.
- `01-vs-mysql` created /root/.config but writes the client config to
  /etc/mysql/conf.d/service.cnf, which it never created.
- `01-vs-user` linked ~/.ssh with `ln -sn`; when ~/.ssh exists as a real
  directory the link lands inside it as ~/.ssh/.ssh. It now clears that
  case, cleans up the nested link and uses `ln -sfn`.
- `01-vs-mosquitto` linked with plain `ln -s`, which fails on a re-run
  and reported nothing. Now `ln -sf` with a warning on failure.
- `code-server/finish` treated a stop by signal as a crash and never
  propagated an exit code to the container. It now reports the code,
  halts on SIGTERM and lets s6 restart only on a real crash.
- `code` is a wrapper so files open in the running editor from a
  terminal, `ha` gets its zsh completion registered, and the esphome file
  association matches nested folders.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pwumst3pLFGsbbzLSxYQMv
@elcajon elcajon changed the title ⚡️ Drop the compiler and express the deb constraints properly ✨ Pre-install Claude Code, drop the compiler, pull upstream fixes Sep 18, 2026
@elcajon elcajon added the new-feature New features or options. label Sep 18, 2026 — with Claude
Installing Claude Code into the image is dropped again; what stays is the
persistence, which is what upstream's app-vscode does.

Users install the `Anthropic.claude-code` extension themselves from the
Extensions view. It is published on Open VSX, the registry code-server
uses for extensions installed from inside the editor, and it carries its
own `claude` binary, so nothing has to be baked into the image. The
service keeps exporting CLAUDE_CONFIG_DIR=/data/claude and the user init
keeps creating and migrating that folder, so the login survives restarts
and updates either way.

The documentation follows: the app no longer claims to ship Claude Code,
and DOCS.md explains installing the extension, why signing in has to
happen from a terminal behind ingress, and where the bundled binary sits
for anyone who wants it on PATH.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pwumst3pLFGsbbzLSxYQMv
@elcajon elcajon changed the title ✨ Pre-install Claude Code, drop the compiler, pull upstream fixes ⚡️ Drop the compiler, persist Claude Code, pull upstream fixes Sep 18, 2026
@elcajon
elcajon marked this pull request as ready for review September 18, 2026 08:45
@elcajon
elcajon enabled auto-merge (squash) September 18, 2026 08:45
@elcajon
elcajon merged commit a0bc1cd into main Sep 18, 2026
11 checks passed
@elcajon
elcajon deleted the claude/eloquent-mccarthy-ew8l6k branch September 18, 2026 08:55
@github-actions github-actions Bot locked and limited conversation to collaborators Sep 19, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

new-feature New features or options. performance Improving performance, not introducing new features.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants