Skip to content

feat(cloud-environment): bake the repo's cloud-bootstrap at cache build - #391

Merged
kyle-sexton merged 2 commits into
feat/cloud-environment-componentfrom
claude/cloud-env-setup-script-qmrrls
Aug 15, 2026
Merged

feat(cloud-environment): bake the repo's cloud-bootstrap at cache build#391
kyle-sexton merged 2 commits into
feat/cloud-environment-componentfrom
claude/cloud-env-setup-script-qmrrls

Conversation

@kyle-sexton

@kyle-sexton kyle-sexton commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Stacked on #388 (the component addition); targets feat/cloud-environment-component so that PR stays reviewable as the baseline.

What

Two changes to the cloud-environment component:

1. Bake the repo's cloud-bootstrap at cache build (24abdab)

  • The setup script's final repo step now runs the checked-out repo's committed .claude/cloud-bootstrap.sh — best-effort, with CLAUDE_CODE_REMOTE=true and CLAUDE_PROJECT_DIR set to the checkout root. One name, no fallback paths: the fleet migration is wholesale, so a repo carrying only the old .claude/hooks/session-start.sh is deliberately a logged no-op, not a compatibility branch.

2. Data-driven plugin install + frozen calling contract (7471a3d)

  • New generic stage after the repo bootstrap: reads the checkout's .claude/settings.json, registers each extraKnownMarketplaces entry not already registered, installs each enabledPlugins: true entry not already installed (--scope user). Best-effort with WARN log lines; skips cleanly when claude/jq is missing or no plugin keys are declared. A repo that declares nothing gets nothing. Timing rationale: Claude Code builds its plugin registry at process start and never re-reads it, so only snapshot-baked installs are loaded at a session's first turn.
  • README gains a frozen calling-contract section: exact entry-point path and env vars, best-effort/exit-0 semantics, warm-cache vs correctness-guarantee division of responsibility, and the rule that future changes may add to the component but never rename the entry point, drop the env vars, or fail closed. It also restates that a merged component change reaches an environment only on its next cache rebuild.
  • SCRIPT_VERSION bumped to 2026-08-15.3.

Verification

  • shellcheck clean; components/cloud-environment/setup.test.sh passes (6/6); markdownlint-cli2 clean.
  • Ran the script live in a cloud session: a fixture checkout with .claude/cloud-bootstrap.sh gets it baked with both env vars set; a legacy-hook-only fixture logs the diagnostic no-op line. Plugin stage verified against this repo's 65 declared plugins: fresh install path installs a missing plugin, second run is a fast all-skip no-op (~1s), and both skip paths (no settings file, no plugin keys) log cleanly. Every run exits 0 in ~25s, well inside the ~5-minute cache-build budget, and writes the stamp strictly last.

Related

No linked issue.

Run the checked-out repo's committed .claude/cloud-bootstrap.sh as the
setup script's final step, best-effort, with CLAUDE_CODE_REMOTE=true and
CLAUDE_PROJECT_DIR set to the checkout root. One canonical name, no
fallback paths: every fleet repo commits its generic repository setup —
dependencies and plugin installs — at exactly that path, and a repo
without the file is a logged no-op.

Running the bootstrap at cache build is load-bearing for plugins: the
session's plugin registry is built at process start and never re-read,
so plugin installs must already be in the snapshot a session boots from.

Document the handoff in the component README and restate that a merged
component change reaches an environment only on its next cache rebuild.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UHbdXDm8B4yj81uQBy8M3M
@cursor

cursor Bot commented Aug 15, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@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: 24abdab84f

ℹ️ 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 on lines +118 to +120
if [[ -f .claude/cloud-bootstrap.sh ]]; then
if CLAUDE_CODE_REMOTE=true CLAUDE_PROJECT_DIR="$PWD" \
bash .claude/cloud-bootstrap.sh >>"$LOG" 2>&1; then

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Avoid baking plugins for only the cache-building repository

In the shared repo-agnostic environment described in README.md lines 10–15, a snapshot built while repo A is checked out can later warm a session for repo B. This block runs only A's bootstrap, so B's plugins are absent when its session starts; running B's bootstrap later cannot repair that state because the plugin registry has already been constructed, as lines 115–117 note. The cache must preload the fleet-wide plugin union, be keyed per repository, or otherwise execute each repository's plugin setup before that repository's process starts.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The cross-repo observation is correct, but it's a design premise rather than a gap: the snapshot is a warm cache, never the correctness path. That division is now documented as the frozen calling contract in the component README (7471a3d) — repos must not assume the component installed anything.

For the specific plugin concern: a repo-B session booting from a snapshot built on repo A still gets B's plugins, because cloud sessions install the plugins declared in the checked-out repo's project settings during session provisioning, before the session process constructs its registry — for any marketplace source the platform can resolve. The fleet's consumer repos declare github-source marketplaces, which resolve fine. The documented failure mode that motivates doing installs at cache build at all was checkout-relative directory sources (claude-code-plugins' own dogfooding, see the Plugins section of its .claude/hooks/session-start.sh), not the github sources this component serves.

Preloading a fleet-wide union here would invert the design: this repo-agnostic component would need to enumerate every consumer's plugin declarations — repo-specific knowledge the contract forbids — and the union would drift chronically, since snapshots rebuild only on script-field edits or ~7-day expiry. 7471a3d instead makes the stage data-driven from whatever checkout builds the cache, deliberately scoped as warm-up for the common case (the environment's most-used repo is typically the one it was built from).


Generated by Claude Code

@claude

claude Bot commented Aug 15, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 3m 26s —— View job


Code review complete ✅

  • Load /review:code-review lane instructions
  • Gather PR context (diff, CLAUDE.md, REVIEW.md)
  • Apply skip gate — not applicable (real review surface: script + docs rename)
  • Review changed files for correctness/maintainability
  • Post findings

No blocking findings.

What I checked

  • components/cloud-environment/setup.sh (diff vs. origin/feat/cloud-environment-component): the rename from .claude/hooks/session-start.sh.claude/cloud-bootstrap.sh is applied consistently — the header contract comment, the Track B comment, the bake step's if/else branches, and both log messages all agree on the new name. The added CLAUDE_PROJECT_DIR="$PWD" is set as a command-scoped prefix (not export), matching the existing CLAUDE_CODE_REMOTE=true pattern, and $PWD is a safe source for it given the bake step already relies on CWD being the repo checkout root for the preceding -f .claude/cloud-bootstrap.sh relative-path check (pre-existing assumption, unchanged by this diff).
  • The stamp-after-wait ordering contract (components/cloud-environment/setup.test.sh's ordering check) is untouched by this diff and still holds by inspection.
  • components/cloud-environment/README.md: the new "Repo bootstrap handoff" section and the "Update lifecycle" scope-boundary paragraph are consistent with the script's new naming and env vars.
  • Checked REVIEW.md atomicity/observability/security always-checks (this repo has no claude-security-review workflow, so security-scope checks apply to this lane too) — nothing in this diff writes related multi-location state without the existing stamp-last guarantee, touches auth/tenancy, or adds secrets/injection.

Not independently verified

Sandbox tool permissions in this run didn't allow executing bash, shellcheck, or the test script directly (approval-gated), so I could not independently reproduce the PR description's shellcheck/setup.test.sh/markdownlint-cli2 results — those remain author-claimed. My review is based on static reading of the diff and cross-checking file consistency, which found no correctness issues.

Branch: claude/cloud-env-setup-script-qmrrls

…ing contract

Add a generic plugin-install stage after the repo bootstrap: read the
checkout's .claude/settings.json, register each extraKnownMarketplaces
entry not already registered, and install each enabledPlugins entry not
already installed (--scope user). Every step is best-effort with a WARN
log line, and the stage skips cleanly when the claude CLI or jq is
missing or the file declares no plugin keys — a repo that declares
nothing gets nothing. The timing is load-bearing: Claude Code builds its
plugin registry at process start and never re-reads it, so only
snapshot-baked installs are loaded at a session's first turn. The
commit-drift refresh in claude-code-plugins' own hook is deliberately
not replicated; consumer repos use github-source marketplaces.

Document the frozen calling contract in the README: the exact
entry-point path and env vars, best-effort/exit-0 semantics, the
warm-cache vs correctness-guarantee division of responsibility, and the
rule that future changes may add to the component but never rename the
entry point, drop the env vars, or fail closed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UHbdXDm8B4yj81uQBy8M3M
@github-actions

Copy link
Copy Markdown

Claude has reviewed this PR 1 time. The lane skips further automatic reviews after 5; deleting this comment resets the count.

@kyle-sexton
kyle-sexton merged commit add10e4 into feat/cloud-environment-component Aug 15, 2026
46 of 47 checks passed
@kyle-sexton
kyle-sexton deleted the claude/cloud-env-setup-script-qmrrls branch August 15, 2026 05:54
kyle-sexton added a commit that referenced this pull request Aug 15, 2026
…#388)

Admit the shared Claude Code cloud-environment baseline as a component:
parallel install tracks for gh + PowerShell (apt), the fleet's exact
.NET SDK pins into /opt/dotnet, and Node 24.18.0 via nvm; timestamped
logging with a completion stamp written strictly last; always exits 0
inside the ~5-minute cache-build budget. The final step runs the
checked-out repo's committed .claude/cloud-bootstrap.sh
(CLAUDE_CODE_REMOTE=true, CLAUDE_PROJECT_DIR at the checkout root),
then a data-driven plugin stage registers extraKnownMarketplaces
entries and installs enabledPlugins entries from the checkout's
.claude/settings.json — plugin installs must be snapshot-baked because
Claude Code builds its plugin registry at process start and never
re-reads it. The README documents the paste-once account bootstrap, the
network prerequisite, the verification stamp, the update lifecycle, and
the frozen calling contract (includes #391).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UHbdXDm8B4yj81uQBy8M3M
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.

2 participants