feat(launcher): per-project Claude volume override (.scc/config.ini volume=) #55
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "dev"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Adds a fourth field to
.scc/config.ini(and matches the existing env / project / default resolution pattern):volume = ...lets a project opt into its own Docker named volume for the Claude install instead of sharing the globalscc-claude.Motivation: the shared
scc-claudevolume holds whichever Claude binary the FIRST flavor installed. Switching to a flavor with a substantially different runtime (e.g. fedora/android-flutter, no Node) silently re-execs the cached binary from the previous flavor — which can fail withcannot execute: required file not foundif the runtime layout drifted.Per-project pin → per-project volume → fresh, flavor-appropriate Claude install.
Resolution
SCC_CLAUDE_VOLUMEenv >.scc/config.inivolume=> defaultscc-claude. Symmetric with the existing image/platform plumbing.Not part of trust
A project pinning a different cached binary is no greater risk than
image=(which already gates and writes the binary in the first place); the existingSCC_CLAUDE_VOLUMEenv path doesn't gate either. Addingvolumeto the trust hash would be inconsistent. Existing trust files keep working unchanged.Test plan
volume = scc-claude-android-flutterinto videoguard-app/.scc/config.ini, run scc, expect fresh Claude install in the isolated volume and no "required file not found" from cross-flavor binary reuseUntil now scc only installed Claude once, then served the cached binary from the scc-claude volume forever — no version check, no nudge when Anthropic shipped a fix. The only refresh path was the user knowing to set SCC_FORCE_REINSTALL=1. This adds a once-per-day check mirroring the existing scc.sh self-update flow: scc.sh GETs @anthropic-ai/claude-code/latest from npm (~1 KB, 1 s timeout), compares it to the version cached in the volume, and warns + prompts when upstream is newer. Decisions are remembered per upstream version so users don't get re-prompted for the same release. Plumbing: - scc-entrypoint.sh writes `claude --version` into both /opt/scc-claude/version (canonical, lives with the binary) and /scc-meta/claude_version (bind-mounted from ~/.scc/volume-meta/, so the host launcher can read it without a docker-exec roundtrip). Re-captured after every reinstall; idempotent on the fast path. - scc.sh adds the /scc-meta mount alongside the existing volume mount. Older launchers don't mount /scc-meta; the entrypoint silently skips the mirror in that case, so a new image works with an old launcher. - New check_for_claude_update() in scc.sh: 24h-cached fetch, semver comparison via sort -V, per-version ack file at ~/.scc/claude-update-check. Fail-closed: non-TTY runs note and continue, never auto-update. Three new env vars: - SCC_AUTO_UPDATE_CLAUDE=1 skip the prompt, auto-set SCC_FORCE_REINSTALL=1 on detection. - SCC_NO_CLAUDE_UPDATE_CHECK=1 skip the daily probe entirely. - (existing SCC_FORCE_REINSTALL=1 still works; suppresses the check when set, since reinstall is already happening.) Tests: - tests/feature/helpers.bash exports SCC_NO_CLAUDE_UPDATE_CHECK=1 alongside SCC_NO_UPDATE_CHECK=1 so the daily curl never fires under test. All 56 existing bats tests pass; no new tests added (the new function is HTTP-bound and matches the established pattern). README "Claude binary handling" section gains a "Daily Claude update check" subsection documenting the prompt, the env vars, and where the metadata lives. scc.sh.version bumped 1.1.2 → 1.2.0. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>Adds a third configurable field next to image and claude_args: a docker --platform pin. Use case: running the new fedora/android-flutter image (amd64-only, since Google ships no arm64 Android SDK) on Apple Silicon under Rosetta-for-Linux. Without --platform, docker warns about arch mismatch and Rosetta's behavior is implicit; with --platform=linux/amd64 the launcher tells docker exactly what to pull + run. Resolution order matches the existing image plumbing: SCC_PLATFORM env > .scc/config.ini platform= > (omit, docker chooses) Wired through both `docker pull` and `docker run` via a shared platform_args array. The status line prints "(--platform linux/amd64)" when set so you can tell at a glance whether emulation is in play. Validation is minimal — `^[a-z0-9]+/[a-z0-9/.-]+$` catches the obvious typo (`amd64` without the `linux/` prefix) but otherwise trusts docker to error on garbage. Anything that looks like os/arch passes through. Trust gate extended: - require_project_trust() takes a 4th argument (platform). - Trust file format gains a `platform=` line. Old trust files without the line keep working because ini_get returns "" for missing keys and ""="" compares equal when the project also doesn't pin platform. Re-prompt only fires when a project NEWLY pins a platform that wasn't in the old trust file. - SCC_PLATFORM env is user-explicit and does NOT trigger the trust prompt, matching the SCC_IMAGE behavior. Tests: 3 new bats cases in project_config.bats: - platform = … in config.ini reaches docker run argv as `--platform linux/amd64` - SCC_PLATFORM env overrides the config.ini value - Malformed platform (`amd64`, no `linux/` prefix) rejected with rc=2 All 59/59 tests pass (was 56 before). README's "Schema" + "Trust prompt" sections updated to document the new field, the resolution order, and the bypass env vars. scc.sh.version bumped 1.2.0 → 1.3.0. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>The named volume `scc-claude` is shared across all image flavors — first image to install Claude wins, every subsequent flavor exec's that same binary. When two flavors have substantially different runtime layouts (e.g. default Fedora-with-Node vs android-flutter without it, or amd64 under Rosetta vs native arm64), the cached binary from flavor A can fail to exec under flavor B's environment. Add a project-pinnable override so each project can opt into its own Claude volume, matching the existing image= / claude_args= / platform= pattern: [scc] image = forge.stacktop.network/openstacktop/scc:android-flutter-fedora-latest volume = scc-claude-android-flutter Resolution: SCC_CLAUDE_VOLUME env > .scc/config.ini volume= > default "scc-claude". CLAUDE_VOLUME loses `readonly` so it can be reassigned after project-config parsing; the three downstream usages (status label, state label, bind mount) are unchanged. Not part of the trust gate: a project pointing at a different cached binary is no greater risk than image= itself (which already gates), and the existing SCC_CLAUDE_VOLUME env path doesn't gate either — adding it to the trust hash now would be asymmetric. Existing trust files keep working unchanged. Tests: - volume = … in config.ini → docker run argv contains `my-project-claude:/opt/scc-claude` and NOT `scc-claude:/opt/scc-claude` - SCC_CLAUDE_VOLUME env overrides the config.ini value All 61/61 bats tests pass (was 59 before). README schema + resolution-priority table updated; help text mentions the new field and the env precedence. scc.sh.version bumped 1.3.0 → 1.4.0. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>