Skip to content

Add a Claude-web skill for running the stack when registries are blocked - #6095

Merged
habdelra merged 2 commits into
mainfrom
claude/tender-cannon-s3aopm
Sep 13, 2026
Merged

habdelra merged 2 commits into
mainfrom
claude/tender-cannon-s3aopm

Conversation

@habdelra

@habdelra habdelra commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

The situation

A Claude Code web session is sometimes provisioned into an egress policy that denies every container-registry blob CDN at once:

What fails Denied host
docker pull postgres:16.3 production.cloudfront.docker.com
docker pull ghcr.io/cardstack/boxel/postgres:16.3 (the CI mirror) pkg-containers.githubusercontent.com
docker pull public.ecr.aws/docker/library/postgres:16.3 an ECR-public cloudfront host
curl https://mise.run mise.run
Fetching the boxel-index-cache artifact productionresultssa*.blob.core.windows.net

Registry manifests resolve and the pull then 403s on the layers, so each failure reads like a corrupt image rather than a policy denial — and looking for another mirror is wasted effort, because every mirror's blobs sit behind one of those CDNs. .devcontainer/claude-web-start.sh can't boot anything in that session: no postgres, no Synapse, no smtp4dev.

This came up while trying to run the host test suite for a PR whose host tests had never been executed. The suite does run in that session — the stack doesn't actually need those three containers to serve realms — but working out how took a while, so this is that path written down.

What the skill covers

  • Diagnosis first, so an agent doesn't burn time on the wrong theory: curl -sS "$HTTPS_PROXY/__agentproxy/status" names the denied host, and a 403 from the proxy is a policy denial to report, not to route around.
  • Postgres from the server binaries the image already ships (/usr/lib/postgresql/16/bin) on port 5435 with the container's max_connections, in place of boxel-pg — plus which repo scripts (docker exec boxel-pg psql) stop working as a result.
  • A shell stand-in for mise. Every task under mise-tasks/ is a plain script whose only mise-specific parts are #MISE dir= / #MISE depends= and .mise.toml's [env] _.source hook, so reproducing those three makes the repo's own tasks run as written.
  • No Matrix. Nothing calls logInToMatrix at boot, so the realm-server serves realms normally; MATRIX_REGISTRATION_SHARED_SECRET has to be set by hand because the script that derives it reads Synapse's config.
  • Chrome and TLS: the google-chrome both env-vars.sh and testem look for, and the NSS database infra:ensure-dev-cert requires before it will run.
  • The service start order, CI=true being load-bearing for the test run (it's what passes --no-sandbox to a Chrome running as root), and rebuilding packages/host/dist before every run, since the suite reads the bundle rather than the source.
  • What this environment cannot run — anything driving a real login round trip against the realm server, Percy, index-cache-dependent assertions — so a failure here isn't mistaken for a real one.

Two opt-in scripts automate it: claude-web-no-docker-bootstrap.sh and claude-web-no-docker-start-stack.sh.

Local dev is untouched

This adds files under .claude/skills/ and modifies no task, script or config on the normal pathmise run dev and mise run test-services:host are byte-for-byte unchanged.

The scripts are named claude-web-* after the existing .devcontainer/claude-web-*.sh convention, and they enforce their own scope rather than relying on the name:

  • claude-web-no-docker-bootstrap.sh refuses to run unless it is root inside a Claude Code session container where docker pull is actually broken, pointing you at mise run dev otherwise (BOXEL_NO_DOCKER_BOOTSTRAP=1 overrides).
  • Nothing is installed system-wide. The mise shim goes to ~/.local/share/boxel/no-docker-bin/mise, which only the generated /tmp/boxel-env.sh puts on PATH; /usr/local/bin is never written. Inside a shell that sourced that file the shim does take precedence, and has to — MISE_SHIM_SKIP is the only way to no-op infra:ensure-pg, and a real mise would run that dependency and try to start the container that cannot be pulled here.
  • claude-web-no-docker-start-stack.sh refuses to run without the bootstrap's env file, and exits 2 rather than reporting the stack up when every realm but skills is ready.

Test plan

Written from a session in exactly this state, and every step verified there: the stack came up (base, skills, /test/, /node-test/ all reporting ready), and the host suite ran against it — Integration | search resource (54 tests), Integration | search correlation id (3), and a full 16-way CI shard (197 tests).

claude-web-no-docker-bootstrap.sh was then run end-to-end twice against that already-provisioned session to confirm it is idempotent — the second time after deleting the previously-installed shim, to confirm the scoped one it now installs is what . /tmp/boxel-env.sh && command -v mise resolves to, that mise run infra:ensure-pg reports itself skipped through it, and that a real task (mise run infra:ensure-dev-cert) still runs.

🤖 Generated with Claude Code

https://claude.ai/code/session_013y14qYwq5DWC5NouJ9eW4Z

A Claude Code web session is sometimes provisioned where the egress policy
denies every container-registry blob CDN — Docker Hub's, ECR Public's, GHCR's —
along with mise.run and the Azure storage the CI index-cache artifact lives in.
`docker pull` then gets as far as the layers and 403s, so it reads like a
corrupt image rather than a policy denial, and `.devcontainer/claude-web-start.sh`
cannot boot anything: no postgres, no Synapse, no smtp4dev.

The stack does not actually need those three to serve realms and run the host
test suite. This skill documents what each one is replaced with — postgres from
the server binaries the image already ships, a shell stand-in for mise (every
mise-task is a plain script with two headers), no Matrix at all (nothing calls
`logInToMatrix` at boot) — plus the service start order, and the list of tests
this environment genuinely cannot run, so a failure here is not mistaken for a
real one.

Nothing on the normal path changes: this adds files under `.claude/skills/` and
modifies no task, script or config that `mise run dev` touches. The two scripts
are opt-in and refuse to run outside a Claude Code session container whose
`docker pull` is broken, since their substitutions (a shimmed `mise` on the
system path, a cluster in /var/lib, a CA in the system trust store) suit a
disposable container and nowhere else. A real `mise` always wins over the shim.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013y14qYwq5DWC5NouJ9eW4Z
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 12, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-12T23:52:30.927179Z 4fff6d1 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@habdelra
habdelra requested a lite review from Copilot September 12, 2026 23:49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4fff6d1ae4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .claude/skills/claude-web-no-docker-stack/claude-web-no-docker-bootstrap.sh Outdated
Comment thread .claude/skills/claude-web-no-docker-stack/claude-web-no-docker-start-stack.sh Outdated
Comment thread .claude/skills/claude-web-no-docker-stack/claude-web-no-docker-start-stack.sh Outdated
…ale dist

Three things the review caught:

- The shim was installed to /usr/local/bin and skipped when a real mise was
  already present. That inverted the intent: a session with mise installed but
  registries blocked is exactly the case this skill is for, and a real mise
  knows nothing of MISE_SHIM_SKIP, so `services:realm-server` would run its
  `infra:ensure-pg` dependency and try to start a container that cannot be
  pulled. The shim now lives in its own directory that only the generated env
  file puts on PATH — it wins inside those shells, where it must, and nothing
  is installed system-wide at all, which is also a better answer for a machine
  that should never have been running this in the first place.
- The host dist was built only when missing, so a dist left over from another
  branch was silently what `ember test --path dist` tested. It is rebuilt every
  time now (BOXEL_SKIP_HOST_BUILD=1 opts out), and the documented test recipe
  leads with the build, per AGENTS.md.
- A skills realm that never finished indexing was swallowed by `|| true` and
  the stack announced itself up. Skills-dependent tests then fail with 404s
  that read as the code under test, so this now reports what it means and
  exits 2.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013y14qYwq5DWC5NouJ9eW4Z
@habdelra
habdelra requested a review from a team September 13, 2026 00:05
@habdelra
habdelra merged commit 5a18164 into main Sep 13, 2026
26 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants