feat(claude-cloud): provision web containers to local parity - #2227
feat(claude-cloud): provision web containers to local parity#2227BigSimmo wants to merge 15 commits into
Conversation
Claude Code on the web starts from a bare Linux container holding only the repository checkout, so a cloud session lost the operator's personal CLAUDE.md, their enabled user skills, this project's saved memories, the four user plugins, and — because nothing installed them — Playwright, Python/Tesseract, Deno and the GitHub CLI. Browser proof and worker checks could not run there at all. - .claude/cloud-profile/ carries the user-level configuration in-tree, since the repository cannot reach a Windows home directory. Windows-only entries (the Shellular notification hook, Desktop Commander permissions) are deliberately excluded and pinned out by test. - scripts/apply-claude-cloud-profile.mjs unpacks it into the container's ~/.claude. Settings are deep-merged so platform-written keys survive, memories are skip-if-present so container-written ones are never clobbered, and an existing CLAUDE.md is backed up once. - scripts/setup-claude-cloud.sh provisions the toolchain in marker-guarded, idempotent tiers. Registered as the second SessionStart hook via --session, which runs the cheap tiers inline and detaches the ten-minute browser/OCR ones. - Both refuse to run unless CLAUDE_CODE_REMOTE=true. The workstation's ~/.claude is the ORIGIN of the snapshot; provisioning it locally would overwrite the source of truth with a copy of itself. - .claude/settings.json also gains enabledMcpjsonServers, which settings.local.json is git-ignored and so cannot carry into a container. Verification: lint, typecheck, format:changed and whole-tree prettier --check all exit 0; tests/claude-cloud-profile.test.ts passes 14/14. The remaining unit-suite failures reproduce identically on a clean main worktree at a341832 (4 failed | 78 passed across the same three files) and are environmental on this Windows host. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Important Review skippedToo many files! This PR contains 539 files, which is 389 over the limit of 150. To get a review, reduce the PR to 150 files or fewer by splitting it into smaller PRs or changing its base branch. Upgrade to Pro+ to raise the limit. Usage-priced reviews support at most 300 files. ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (5)
📒 Files selected for processing (539)
You can disable this status message by setting the Comment |
This pull request has been ignored for the connected project Preview Branches by Supabase. |
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ttings-migration-bf4707 # Conflicts: # docs/scripts-index.md
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:da6088e70c
ℹ️ 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".
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
…ation-bf4707' into claude/local-cloud-settings-migration-bf4707
…ttings-migration-bf4707 # Conflicts: # docs/scripts-index.md
…ttings-migration-bf4707 # Conflicts: # docs/scripts-index.md
…gnore Gitleaks flagged two false positives in .claude/cloud-profile/ skill docs vendored verbatim for Claude Code web-container parity: an example fake API key shown as an anti-pattern to remove, and a mocked Playwright test token. Neither is a real secret (GitGuardian and Semgrep already pass on the same content). Add both fingerprints to .gitleaksignore following the existing documented-fingerprint convention.
Both are deliberately fake illustrative strings in third-party documentation, read line by line before pinning: an <!-- API Key: ... --> example inside a skill section teaching that credentials must not be left in markup, and a mockToken constant in a fully-mocked Playwright auth example. Neither is a credential and neither executes. Pinned per finding, matching this file's existing practice, rather than excluding the vendored path — a vendored directory is exactly where a real secret could hide. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ation-bf4707' into claude/local-cloud-settings-migration-bf4707 # Conflicts: # .gitleaksignore
…ttings-migration-bf4707 # Conflicts: # docs/scripts-index.md
Gitleaks flags two lines in the vendored tree, both deliberately fake illustrative strings in documentation prose: - clean-up-comments/references/rule.md:497 — an <!-- API Key: ... --> example sitting under a "Don't leave sensitive info in production" marker inside a "Remove Sensitive Information" section. The skill teaches the rule the scanner enforces, and the value is a sequential-digit placeholder. - playwright-best-practices/advanced/authentication-flows.md:54 — a mockToken constant in a "Fully Mocked Verification" test example, returned by a page.route stub that never reaches a real service. Both read line by line before pinning. Neither is a credential and neither is executed; GitGuardian passes on the same content. Pinned per finding rather than by path. A vendored directory is exactly where a real secret could otherwise hide unnoticed, so every other line of the tree stays scanned. A fingerprint is <commit>:<file>:<rule>:<line>, so these are re-derived from the run that actually failed rather than carried over from the superseded PR #2227: its fingerprints named commit da6088e, which exists on no branch here and would never have matched. Also corrects the .prettierignore rationale comment from ~500 upstream files to ~400, following the docx and xlsx exclusion. Kept byte-identical to the copy on the code branch so the two merge to a single block. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014vxCPHG35e1GRZPPXo9eiW
Superseded by the two-PR split and closed unmerged. Both halves have now landed on
main, so nothing here is lost, and the branch is left intact.CLAUDE.md/settings/memory snapshot, the contract doc and its tests — merged in feat(claude-cloud): provision web containers to local parity #2236.Verified on
mainby content rather than by PR state: both scripts present at mode100755, theSessionStarthook registered, 16 memory files, 402 skill files across 44 skills,docxandxlsxabsent as agreed, all three Gitleaks fingerprints in place, and exactly one.claude/cloud-profile/skills/entry in.prettierignore— the block that deliberately appeared in both PRs resolved to a single copy on merge, asgit merge-treepredicted it would.Why this was split. 543 files and 140,091 added lines, of which roughly 1,100 lines across 9 files were the actual work. CodeRabbit declines any pull request over 150 files, so the real code here received no automated review at all. Gitleaks flagged two false positives buried in vendored documentation, and
maindrifted 31 commits in a single session, costing four separate conflict resolutions on one generated line.Split, the code half became reviewable, and Codex immediately found five genuine defects in the provisioner — three P1, two P2 — every one of them fixed before it merged. Among them: the OCR tier could never install Python 3.12 on a container that already had an older interpreter, and the documented "confirm the background tier finished" command reported success while another run still held the lock. Those would have shipped. That is the entire argument for splitting, and it is not hypothetical.
Three things worth carrying forward, recorded here so they are not rediscovered:
<commit>:<file>:<rule>:<line>, so it cannot survive a re-commit. The two pinned here named commitda6088e70, which exists on neither replacement branch and would never have matched. They were re-derived from the scan that actually failed..gitleaksignorelike any other file, so a quoted value becomes a finding in that file — turning two findings into three. This repository had already learned that once; thed2b7b898entry exists for exactly that reason.branches: [main, "release/**"]—ci.yml,secret-scan.yml,sast.ymlandpr-policy.ymlalike — so a PR based on any other branch runs none of them and can never be shown green. The first attempt at the vendored half (chore(claude-cloud): vendor the user skill tree for web containers #2237) was stacked and had to be replaced by chore(claude-cloud): vendor the user skill tree for web containers #2238, cut frommain.Also dropped along the way: the
docxandxlsxskills, 114 files and ~46,700 lines of Office-document authoring guidance that a container doing code, tests, docs and review has no use for.docs/claude-cloud.mdrecords that exclusion in the snapshot-refresh instructions so a future wholesale copy does not silently drag them back.