From 02f2e10fe32a4b6647795ccabdd3b90c9b61d720 Mon Sep 17 00:00:00 2001 From: Zahin Mohammad Date: Thu, 20 Aug 2026 23:38:03 -0400 Subject: [PATCH 1/3] Persist Claude Code credentials and document AI assistant support The editor uses the Open VSX registry, so GitHub Copilot cannot be installed, while the Claude Code extension can. Document both, including how to sign in from behind ingress, and persist ~/.claude in the add-on data folder so logins survive restarts and updates, matching what is already done for SSH and git. --- vscode/DOCS.md | 49 +++++++++++++++++++ .../etc/s6-overlay/s6-rc.d/init-user/run | 21 ++++++++ 2 files changed, 70 insertions(+) diff --git a/vscode/DOCS.md b/vscode/DOCS.md index 1acb9549f..0f85aa1cc 100644 --- a/vscode/DOCS.md +++ b/vscode/DOCS.md @@ -96,6 +96,53 @@ return to the defaults as delivered by this app, do the following: 1. Execute the following command in the terminal window: `reset-settings`. 1. Done! +## Using AI coding assistants + +This app is built on [code-server][code-server], which is a build of +VS Code that uses the [Open VSX][open-vsx] extension registry instead of the +Microsoft Marketplace. Microsoft only allows their marketplace to be used by +their own branded builds of Visual Studio Code, so which assistants you can +use is decided by what is published on Open VSX. + +- **GitHub Copilot is not available.** The `GitHub.copilot` and + `GitHub.copilot-chat` extensions are published exclusively on the Microsoft + Marketplace and are not on Open VSX, so they cannot be found or installed + from within this app. VS Code may still advertise its built-in AI + features; attempting to enable them fails with + `extension GitHub.copilot-chat not found`. +- **Claude Code works.** The `Anthropic.claude-code` extension is published on + Open VSX and can be installed from the Extensions view as usual. It bundles + its own `claude` binary, so no separate Node.js installation is needed. + +Because the app runs behind Home Assistant ingress, browser-based sign-in +flows that redirect back to a `vscode://` URL do not work. Sign in from a +terminal inside the editor instead: + +1. Open the Visual Studio Code editor. +1. Click on `Terminal` in the top menu bar and click on `New Terminal`. +1. Run `claude` and use the `/login` command, which prints a URL and asks you + to paste back the code it gives you. + +Your login is stored in `~/.claude`, which this app persists in its data +folder, so it survives app restarts and updates. + +The bundled `claude` binary lives inside the extension folder. If you want it +on your `PATH` for use in the terminal, add the following to the app's +`init_commands` option: + +```yaml +init_commands: + - for f in /data/vscode/extensions/anthropic.claude-code-*/resources/native-binary/claude; do test -x $f && ln -sf $f /usr/local/bin/claude; done; true +``` + +Claude Code's optional voice input needs ALSA, which the app does not ship. +Add it using the `packages` option if you want to use it: + +```yaml +packages: + - libasound2t64 +``` + ## Known issues and limitations - Can this app run on a Raspberry Pi? Yes, but only if you run a 64 bits @@ -181,12 +228,14 @@ SOFTWARE. [addon-badge]: https://my.home-assistant.io/badges/supervisor_addon.svg [addon]: https://my.home-assistant.io/redirect/supervisor_addon/?addon=a0d7b954_vscode&repository_url=https%3A%2F%2Fgithub.com%2Fhassio-addons%2Frepository +[code-server]: https://github.com/coder/code-server [contributors]: https://github.com/hassio-addons/app-vscode/graphs/contributors [discord-ha]: https://discord.gg/c5DvZ4e [discord]: https://discord.me/hassioaddons [forum]: https://community.home-assistant.io/t/home-assistant-community-add-on-visual-studio-code/107863?u=frenck [frenck]: https://github.com/frenck [issue]: https://github.com/hassio-addons/app-vscode/issues +[open-vsx]: https://open-vsx.org [reddit]: https://reddit.com/r/homeassistant [releases]: https://github.com/hassio-addons/app-vscode/releases [semver]: https://semver.org/spec/v2.0.0 diff --git a/vscode/rootfs/etc/s6-overlay/s6-rc.d/init-user/run b/vscode/rootfs/etc/s6-overlay/s6-rc.d/init-user/run index 4e1602060..33155ef58 100755 --- a/vscode/rootfs/etc/s6-overlay/s6-rc.d/init-user/run +++ b/vscode/rootfs/etc/s6-overlay/s6-rc.d/init-user/run @@ -5,6 +5,7 @@ # Persists user settings and installs custom user packages. # ============================================================================== readonly -a DIRECTORIES=(addon_configs addons backup homeassistant media share ssl) +readonly CLAUDE_USER_PATH=/data/claude readonly GIT_USER_PATH=/data/git readonly SSH_USER_PATH=/data/.ssh readonly ZSH_HISTORY_FILE=/root/.zsh_history @@ -69,6 +70,26 @@ if ! bashio::fs.file_exists "${GIT_USER_PATH}/.gitconfig"; then fi ln -s "${GIT_USER_PATH}/.gitconfig" ~/.gitconfig || bashio::log.warning "Failed linking .gitconfig" +# Store Claude Code settings & credentials in app data folder +if ! bashio::fs.directory_exists "${CLAUDE_USER_PATH}"; then + mkdir -p "${CLAUDE_USER_PATH}" \ + || bashio::exit.nok 'Failed to create a persistent Claude Code folder' + + chmod 700 "${CLAUDE_USER_PATH}" \ + || bashio::exit.nok \ + 'Failed setting permissions on persistent Claude Code folder' +fi + +# Migrate a non-persistent folder left behind by an older app version +if bashio::fs.directory_exists ~/.claude && [[ ! -L ~/.claude ]]; then + cp -a ~/.claude/. "${CLAUDE_USER_PATH}/" \ + || bashio::log.warning 'Failed migrating existing Claude Code folder' + + rm -rf ~/.claude \ + || bashio::log.warning 'Failed removing non-persistent Claude Code folder' +fi +ln -sfn "${CLAUDE_USER_PATH}" ~/.claude || bashio::log.warning "Failed linking .claude" + # Install user configured/requested packages if bashio::config.has_value 'packages'; then apt update \ From b9dc5309fb28b2422990eb01c1eaca23effe3480 Mon Sep 17 00:00:00 2001 From: Zahin Mohammad Date: Mon, 24 Aug 2026 02:06:29 -0400 Subject: [PATCH 2/3] Keep the Claude Code folder when migration fails A failed copy no longer falls through to removing the source folder, so a full disk or I/O error cannot destroy credentials that were not copied to /data. The symlink is now only created when nothing is left in its place, which also avoids nesting it inside a folder that was kept. --- .../etc/s6-overlay/s6-rc.d/init-user/run | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/vscode/rootfs/etc/s6-overlay/s6-rc.d/init-user/run b/vscode/rootfs/etc/s6-overlay/s6-rc.d/init-user/run index 33155ef58..c037cd57b 100755 --- a/vscode/rootfs/etc/s6-overlay/s6-rc.d/init-user/run +++ b/vscode/rootfs/etc/s6-overlay/s6-rc.d/init-user/run @@ -82,13 +82,22 @@ fi # Migrate a non-persistent folder left behind by an older app version if bashio::fs.directory_exists ~/.claude && [[ ! -L ~/.claude ]]; then - cp -a ~/.claude/. "${CLAUDE_USER_PATH}/" \ - || bashio::log.warning 'Failed migrating existing Claude Code folder' + if cp -a ~/.claude/. "${CLAUDE_USER_PATH}/"; then + rm -rf ~/.claude \ + || bashio::log.warning \ + 'Failed removing non-persistent Claude Code folder' + else + bashio::log.warning \ + 'Failed migrating Claude Code folder, leaving it in place' + fi +fi - rm -rf ~/.claude \ - || bashio::log.warning 'Failed removing non-persistent Claude Code folder' +# Only link when nothing is left in the way, as linking onto an existing +# folder would nest the link inside it +if [[ ! -e ~/.claude || -L ~/.claude ]]; then + ln -sfn "${CLAUDE_USER_PATH}" ~/.claude \ + || bashio::log.warning "Failed linking .claude" fi -ln -sfn "${CLAUDE_USER_PATH}" ~/.claude || bashio::log.warning "Failed linking .claude" # Install user configured/requested packages if bashio::config.has_value 'packages'; then From 15378ad1a9477577a1031f341edd4262a4e67781 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Fri, 28 Aug 2026 23:04:55 +0200 Subject: [PATCH 3/3] Persist the Claude Code state through CLAUDE_CONFIG_DIR Claude Code splits its state over two locations: `~/.claude`, holding the credentials and the user settings, and `~/.claude.json`, holding the global configuration. Linking only the folder therefore persisted the login but still lost the configuration on every update. Both locations collapse into one when `CLAUDE_CONFIG_DIR` is set, so export it for the code-server service instead. The extension host and the integrated terminals inherit it, which covers the extension as well as the bundled `claude` binary, and it removes the need to link anything into the home folder at all. Verified against the binary the extension ships (2.1.251, linux-x64). Without the variable, writing a user scoped setting creates both `/root/.claude.json` and `/root/.claude`. With it pointing at `/data/claude`, everything lands there and the home folder stays empty. The migration now copies both of the old locations, no longer overwrites files that are already persisted, and leaves the originals alone rather than removing them; they are simply no longer read. --- vscode/DOCS.md | 8 ++++-- .../etc/s6-overlay/s6-rc.d/code-server/run | 5 ++++ .../etc/s6-overlay/s6-rc.d/init-user/run | 28 ++++++++----------- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/vscode/DOCS.md b/vscode/DOCS.md index 0f85aa1cc..b2c903e60 100644 --- a/vscode/DOCS.md +++ b/vscode/DOCS.md @@ -123,8 +123,9 @@ terminal inside the editor instead: 1. Run `claude` and use the `/login` command, which prints a URL and asks you to paste back the code it gives you. -Your login is stored in `~/.claude`, which this app persists in its data -folder, so it survives app restarts and updates. +Claude Code keeps its settings and credentials in a configuration folder that +this app points at its own data folder, so your login survives app restarts +and updates. The bundled `claude` binary lives inside the extension folder. If you want it on your `PATH` for use in the terminal, add the following to the app's @@ -135,6 +136,9 @@ init_commands: - for f in /data/vscode/extensions/anthropic.claude-code-*/resources/native-binary/claude; do test -x $f && ln -sf $f /usr/local/bin/claude; done; true ``` +Init commands run before the editor starts, so the link appears after the +first restart following the installation of the extension. + Claude Code's optional voice input needs ALSA, which the app does not ship. Add it using the `packages` option if you want to use it: diff --git a/vscode/rootfs/etc/s6-overlay/s6-rc.d/code-server/run b/vscode/rootfs/etc/s6-overlay/s6-rc.d/code-server/run index 1d2b10361..2c791f808 100755 --- a/vscode/rootfs/etc/s6-overlay/s6-rc.d/code-server/run +++ b/vscode/rootfs/etc/s6-overlay/s6-rc.d/code-server/run @@ -28,6 +28,11 @@ options+=(--auth none) export HASS_SERVER="http://supervisor/core" export HASS_TOKEN="${SUPERVISOR_TOKEN:-}" +# Keep the Claude Code configuration in the persistent data folder. The +# extension host and the integrated terminals inherit this, so both the +# extension and the bundled claude binary use it. +export CLAUDE_CONFIG_DIR="/data/claude" + # Run the code server cd "${config_path}" || bashio::exit.nok "Could not change working directory" exec code-server "${options[@]}" "${config_path}" diff --git a/vscode/rootfs/etc/s6-overlay/s6-rc.d/init-user/run b/vscode/rootfs/etc/s6-overlay/s6-rc.d/init-user/run index c037cd57b..dcc20af9c 100755 --- a/vscode/rootfs/etc/s6-overlay/s6-rc.d/init-user/run +++ b/vscode/rootfs/etc/s6-overlay/s6-rc.d/init-user/run @@ -70,7 +70,9 @@ if ! bashio::fs.file_exists "${GIT_USER_PATH}/.gitconfig"; then fi ln -s "${GIT_USER_PATH}/.gitconfig" ~/.gitconfig || bashio::log.warning "Failed linking .gitconfig" -# Store Claude Code settings & credentials in app data folder +# Store Claude Code settings & credentials in app data folder. The service +# points Claude Code here through CLAUDE_CONFIG_DIR, which covers both of the +# locations it would otherwise use: ~/.claude and ~/.claude.json. if ! bashio::fs.directory_exists "${CLAUDE_USER_PATH}"; then mkdir -p "${CLAUDE_USER_PATH}" \ || bashio::exit.nok 'Failed to create a persistent Claude Code folder' @@ -80,23 +82,17 @@ if ! bashio::fs.directory_exists "${CLAUDE_USER_PATH}"; then 'Failed setting permissions on persistent Claude Code folder' fi -# Migrate a non-persistent folder left behind by an older app version -if bashio::fs.directory_exists ~/.claude && [[ ! -L ~/.claude ]]; then - if cp -a ~/.claude/. "${CLAUDE_USER_PATH}/"; then - rm -rf ~/.claude \ - || bashio::log.warning \ - 'Failed removing non-persistent Claude Code folder' - else - bashio::log.warning \ - 'Failed migrating Claude Code folder, leaving it in place' - fi +# Migrate the non-persistent locations left behind by an older app version. +# Existing files are never overwritten, and the originals are left alone; +# they are simply no longer read once CLAUDE_CONFIG_DIR is set. +if bashio::fs.directory_exists ~/.claude; then + cp -a -n ~/.claude/. "${CLAUDE_USER_PATH}/" \ + || bashio::log.warning 'Failed migrating the Claude Code folder' fi -# Only link when nothing is left in the way, as linking onto an existing -# folder would nest the link inside it -if [[ ! -e ~/.claude || -L ~/.claude ]]; then - ln -sfn "${CLAUDE_USER_PATH}" ~/.claude \ - || bashio::log.warning "Failed linking .claude" +if bashio::fs.file_exists ~/.claude.json; then + cp -a -n ~/.claude.json "${CLAUDE_USER_PATH}/.claude.json" \ + || bashio::log.warning 'Failed migrating the Claude Code configuration' fi # Install user configured/requested packages