Bootstrap config for Phoenix's Claude Code on the web (cloud) environments β the cloud counterpart to the config-leash repo, which covers the local Leash/Docker setup instead. Cloud environments only take a single Setup script and a single .env snippet, pasted into a UI dialog with no version history β so the actual content lives here instead, and the dialog just points at it.
cloud/pointer.shβ paste verbatim into the environment's Setup script field. Fetches and runscloud/setup.shbelow.cloud/setup.shβ the real logic: installsgh, lefthook, hadolint, trufflehog, extra Python versions, and semgrep; writescloud/gh-config.ymlandcloud/CLAUDE.md(below); syncs thephx,superpowers, andelements-of-styleplugins into~/.claude/skills/<name>/(see "Plugins" below).cloud/CLAUDE.mdβ personal user-level instructions. Cloud sessions don't carry over~/.claude/CLAUDE.mdfrom a local machine (only repo-committedCLAUDE.mdfiles do), so this is the only way to get it into cloud sessions at all. Generated bycloud/generate-claude-md.sh, run automatically by.github/workflows/generate-claude-md.ymlafter every push tomain(and bytodofixthis/config-claude's own workflow, when the shared content it publishes changes) β seecloud/CLAUDE.cloud-only.mdfor how to edit and preview it.cloud/CLAUDE.cloud-only.mdβ the cloud-specific personal instructions, plus how to maintain and regeneratecloud/CLAUDE.md. There's nocloud/CLAUDE.shared.mdfile in this repo at all β that content is canonical in, and only ever checked into,todofixthis/config-claude; this repo fetches it live instead of keeping a copy.cloud/generate-claude-md.shβ concatenatescloud/CLAUDE.cloud-only.mdwithtodofixthis/config-claude'sCLAUDE.shared.md(fetched live viagh api) intocloud/CLAUDE.md..github/workflows/generate-claude-md.ymlβ runs the above automatically on a push tomainthat touchescloud/CLAUDE.cloud-only.md, using theCONFIG_CLAUDE_READ_TOKENsecret below to authenticate the fetch, and pushes the regeneratedcloud/CLAUDE.mdas theCLAUDE_MD_BOT_APP_IDapp (also below) β a bypass actor on this repo's own branch-protection ruleset, since neither the defaultGITHUB_TOKENnor a plain PAT can push straight tomainhere.cloud/gh-config.ymlβghCLI preferences. Notegit_protocol: https, notsshβ cloud sessions have no SSH client, soghneeds HTTPS to have any credential to use.cloud/environment.envβ paste verbatim into the environment's Environment variables field.
- At claude.ai/code, open the environment dialog (the cloud icon above the message box β settings gear on the environment you're configuring).
- Set Network access to Custom, keep "also include default list of common package managers" checked, and add
*.cloudsmith.io(needed for lefthook's package repo β everything else installs from domains already on the Trusted default list). - Paste
cloud/pointer.sh's content into Setup script. - Paste
cloud/environment.env's content into Environment variables. - Save. The setup script runs once, on the first session in this environment, and is cached (~7 days, or until the setup script text or allowed domains change) for every session after that.
The workflow needs two credentials, for two unrelated reasons: a PAT to read todofixthis/config-claude (private), and a GitHub App to write back to this repo's own main past its branch-protection ruleset.
.github/workflows/generate-claude-md.yml fetches CLAUDE.shared.md from todofixthis/config-claude (private) β the default GITHUB_TOKEN a workflow run here gets is scoped to this repo only, and this repo never keeps its own copy of that file to fall back on. This is a GitHub Actions repository secret, not something the cloud session sandbox itself holds β it's unrelated to, and doesn't relax, the "no secrets store" rule under "What's deliberately not here" below, which is about that sandbox specifically. Set it up once:
- At github.com/settings/personal-access-tokens/new, create a fine-grained personal access token.
- Repository access: "Only select repositories" β
todofixthis/config-claude. - Permissions: Repository permissions β Contents β Read-only. No other permission is needed.
- Set an expiration you're comfortable renewing, or "No expiration" if you'd rather not think about it again β an expired token fails the workflow the same way a missing one does (loudly, not silently), so there's no safety cost either way beyond the renewal chore.
- Generate the token and copy it.
- In this repo's own Settings β Secrets and variables β Actions, add a New repository secret named
CONFIG_CLAUDE_READ_TOKEN, and paste the token as its value.
main's branch-protection ruleset requires every change to go through a pull request, with no bypass actor configured β so even this repo's own GITHUB_TOKEN gets rejected (GH013) on a plain push. Adding a GitHub App to the ruleset's bypass list fixes that for whichever token a workflow explicitly generates from it; todofixthis/config-claude's own workflow generates a token from the same App to push here across repos, so one App and one bypass-list entry cover both. Set it up once:
- At github.com/settings/apps/new, register a new GitHub App β name doesn't matter (e.g.
config-claude-md-bot). Under Webhook, uncheck Active; this App never receives events. - Permissions β Repository permissions β Contents β Read and write. No other permission is needed.
- Where can this GitHub App be installed? β Only on this account.
- Create the App, then generate and download a private key from its settings page.
- From the App's settings page, Install App on
todofixthis/config-claude-code-cloudonly β it never needstodofixthis/config-claudeitself. - In this repo's Settings β Rules β Rulesets β main, add the App to the Bypass list with bypass mode Always.
- In this repo's own Settings β Secrets and variables β Actions, add two New repository secrets:
CLAUDE_MD_BOT_APP_ID(the App ID, on its settings page) andCLAUDE_MD_BOT_APP_PRIVATE_KEY(the private key file downloaded in step 4, pasted whole). - Repeat step 7 in
todofixthis/config-claude's own Settings β Secrets and variables β Actions β its workflow generates its own installation token from the same App to push here.
Once both are set up, any push to main that changes cloud/CLAUDE.cloud-only.md triggers this repo's workflow (as does a push to todofixthis/config-claude's main that changes CLAUDE.shared.md). You can also fire either manually from the Actions tab (workflow_dispatch) to confirm it's wired up β but only after merging the workflow file to main; workflow_dispatch isn't available for a workflow that only exists on a branch.
phx, superpowers, and elements-of-style are skill libraries (superpowers also ships one SessionStart hook) β none of the three ship agents, commands, or MCP servers. setup.sh doesn't install them as plugins in the usual sense. It clones each plugin's own repo β not the shared superpowers-marketplace repo, which is just a pointer catalogue with no skill content of its own β and copies its .claude-plugin/, skills/, hooks/, agents/, commands/, and .mcp.json (whichever exist) straight into ~/.claude/skills/<name>/.
That's deliberate, not a shortcut: the marketplace path (extraKnownMarketplaces + claude plugin install) clones the plugin into ~/.claude/plugins/cache fine, but run non-interactively from a setup script it never persists the "installed" record β installed_plugins.json comes out empty and the skills never load, even though settings.json looks correct. Claude Code separately auto-loads any directory at ~/.claude/skills/<name>/ that carries a .claude-plugin/plugin.json, as <name>@skills-dir, with no marketplace or settings.json entry β confirmed to work, hook included, by testing it in a session. cloud/setup.sh uses that path for all three plugins instead.
One consequence: don't also enable these three via the marketplace path (extraKnownMarketplaces/enabledPlugins in settings.json) β an installed marketplace plugin takes precedence over a skills-dir plugin of the same name, so the skills-dir copy would silently stop loading.
- Editing
setup.shorgh-config.yml: commit the change here, then bump the version comment at the top ofcloud/pointer.shand re-pastepointer.sh's content into the environment's Setup script field. This step is the whole reasonpointer.shexists: the environment only re-runs its setup script (and rebuilds the cached snapshot) when that field's own text changes β never when the file it fetches does. Skipping the re-paste means the change sits in this repo but never reaches a session. - Editing
CLAUDE.cloud-only.md: commit and push tomainβ.github/workflows/generate-claude-md.ymlregeneratescloud/CLAUDE.mdand pushes automatically; then follow the bump-and-re-paste step above (seecloud/CLAUDE.cloud-only.mdfor the full procedure). - Editing shared content: not here β there's no
CLAUDE.shared.mdfile in this repo to edit. Edit it intodofixthis/config-claude'sCLAUDE.shared.mdinstead; that repo's own workflow pushes the regeneratedcloud/CLAUDE.mdinto this repo automatically (seecloud/CLAUDE.cloud-only.mdfor the full procedure). - Editing
pointer.shorenvironment.envitself: re-paste directly, no version bump needed (the text already changed). - Adding a plugin: add a
sync_skills_dir_plugincall for it incloud/setup.sh(see "Plugins" above), then follow the bump-and-re-paste step above. - A cloud session editing
~/.claude/CLAUDE.mdin place (e.g.phx:reflectiondeciding to record a new pattern): that's the fetched copy, not this repo β the edit is invisible everywhere else and is gone at the next cache rebuild.cloud/CLAUDE.cloud-only.mdcarries this same warning (which flows into the generatedcloud/CLAUDE.md, and so into the fetched copy), since that's what a session is reading right when it'd make this mistake.
Two different things were living in one place: toolchain installs, which change rarely, and personal preferences (CLAUDE.md, in particular), which change often β and the dialog gives neither of them git history, diffs, or review. Splitting the real content into this repo fixes that; pointer.sh is the two-line adapter that makes the dialog agree to defer to it.
- GPG commit signing. Cloud environments have no secrets store, and Anthropic's own docs say signing keys are kept out of the session sandbox entirely β there's no code path for a personal key to plug into, quite apart from nowhere safe to store one.
- PyPI publishing credentials. Same reasoning β no secrets store, so no token lives here. Publish from local Leash instead.
- SSH keys. Cloud sessions have no SSH client at all; all GitHub git operations go through Anthropic's own GitHub proxy with short-lived scoped credentials instead.