Repository navigation
feat(claude-code): ship Cloudflare cf CLI with telemetry off - #204
Merged
Merged
Conversation
Install Cloudflare's cf CLI (open beta) in both targets, pinned and bumped by Renovate with the same 3-day soak as the other devcontainer tools. - Delete cf's bundled workerd runtime (hard-linked twice, 133 MB): cf dev and --local commands run the project's own cf copy. cf is 92 MB instead of 225 MB. - CF_SEND_TELEMETRY=false and WRANGLER_SEND_METRICS=false. - Managed /etc/claude-code/CLAUDE.md: prefer cf unless the project has a Wrangler config and no cloudflare.config.ts, where cf dev/build/deploy would rewrite package.json without asking. - Templates persist ~/.config/cloudflare in a named volume so cf auth login survives rebuilds; the sandbox firewall template allows api.cloudflare.com and dash.cloudflare.com. - CI verify checks cf, the managed CLAUDE.md, telemetry env and volume owner. - READMEs recommend migrating Workers projects to cloudflare.config.ts.
# Conflicts: # .github/workflows/ci.yml # claude-code/.devcontainer/Dockerfile
Review follow-ups, each swapping custom code for a built-in feature: - Move the cf guidance from a separate /etc/claude-code/CLAUDE.md into the claudeMd key of managed-settings.json, which master now uses for the browser guidance. Same precedence per the Claude Code docs; one file fewer. - Install cf with npm --ignore-scripts. workerd's postinstall is what hard-linked its binary a second time, so one rm now frees the 133 MB, and no third-party install scripts run in the image build. - Managed permissions.ask for `cf * --force*` / `cf * -f*`: cf aborts destructive commands without a terminal unless they carry that flag. - README: recommend a least-privilege API token for sandbox agents and CI.
…th CI - gh: oh-my-zsh's built-in gh plugin, which regenerates _gh from `gh completion` on each shell start. - cf: `cf complete zsh >> ~/.zshrc` at build, as Cloudflare documents. The script asks cf for candidates, so cf upgrades don't make it stale. - Verify checks both completions are registered (`_comps[gh]`, `_comps[cf]`). - build-claude-code.yml's verify commands had fallen behind ci.yml's (no agent-browser, browser-skill or agent-browser config checks); they are now identical, so the post-merge build checks what the PR build checked.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Ships Cloudflare's new
cfCLI in both claude-code targets, with telemetry off, and recommends that consumer repos migrate to the typedcloudflare.config.ts.Why
cf(open beta since 2026-09-28) covers the whole Cloudflare API (~2,900 commands, compared with ~280 in Wrangler), prints JSON and finds commands locally withcf cli search. Once the beta ends, Cloudflare will maintain Wrangler for only 18 more months. The Cloudflare MCP server stays: it also searches current Cloudflare docs, andcfdoesn't yet cover everything (wrangler tail, setting a single secret).Changes
cffrom npm, pinned inCF_VERSION. It sits in thesharedstage after Chromium and before Claude Code, so Claude Code bumps don't reinstall it. SetsCF_SEND_TELEMETRY=falseandWRANGLER_SEND_METRICS=false, and pre-creates a node-owned~/.config/cloudflare.npm --ignore-scripts, then deletescf's bundledworkerdruntime (133 MB). That bringscffrom 225 MB to 92 MB. Skipping install scripts is what keeps it to onerm:workerd's postinstall would otherwise hard-link the binary a second time. It also means no third-party install code runs in the build.managed-settings.json):claudeMdkey tells every session to prefercf, but not in a project with a Wrangler config and nocloudflare.config.ts. There,cf dev/build/deployrewritepackage.json, the lockfile andvite.config.tswithout asking when there's no terminal.permissions.askcoversBash(cf * --force*)andBash(cf * -f*). Without a terminal,cfaborts deletes unless they carry that flag, so Claude Code asks before every destructive Cloudflare call. Bypass mode skips prompts by design.ghthrough oh-my-zsh's built-inghplugin, which regenerates_ghon each shell start.cfthroughcf complete zsh >> ~/.zshrcat build time, as Cloudflare documents. The script askscffor candidates, so it doesn't go stale across upgrades.cfjoins the "devcontainer tools" group, so new releases wait 3 days before auto-merging.devcontainer.jsonfiles gain amyproject-cloudflare-config-*volume, plus thechownsafety net, socf auth loginsurvives rebuilds. The sandbox firewall template allowsapi.cloudflare.comanddash.cloudflare.com.ci.ymlandbuild-claude-code.yml): checkscf --version,cf cli search, thecfguidance inclaudeMd, theaskrule, both telemetry variables, the owner of~/.config/cloudflare, and that both completions are registered.build-claude-code.yml's verify commands had fallen behindci.yml's: they were missing the agent-browser, browser-skill and agent-browser config checks. The two are now identical, so the post-merge build checks what the PR build checked.cf)" section and "Recommended: migrate Workers projects tocloudflare.config.ts". It also recommends a least-privilege API token for agents in the sandbox, which shares the login, and for CI. The hugo-bun-node README now points tocf.Notes
cf devand--localcommands needcfas a project dev dependency, whichcf initandcf migrateadd. The globalcfthen runs the project's copy, which has its ownworkerd. I checked this: in a project,cf d1 raw <id> --localworks; in a bare directory it fails with a clear "workerd could not be found" error. API commands don't needworkerd.cf:claude-buncan't run it: it has no Node, andcfcan't loadcloudflare.config.tsunder Bun.ralphex-fehas Node 24, but it's a standalone ralphex runner and out of scope here. (Corrected after merge: this note originally saidralphex-fehad no Node too.).devcontainer/(the upstream-sync skill picks this up), then runcf auth login --no-browseronce.cf auth login(OAuth device flow) contacts onlydash.cloudflare.com, and API calls go toapi.cloudflare.com. Those IPs return 403 for other Cloudflare-hosted sites (workers.dev,chatgpt.com), so the allowlist doesn't open the rest of Cloudflare's network. End to end through the sandbox firewall (sandbox image,NET_ADMIN, the template script):example.comstays blocked,cf auth login --no-browserreaches the device-code step, and an API call with a dummy token gets a real 400 fromapi.cloudflare.com.claudeMd, not a file: the Claude Code docs give a/etc/claude-code/CLAUDE.mdfile and theclaudeMdkey the same precedence.masternow usesclaudeMdfor the browser guidance, so this PR follows suit.wranglerskill: it already says to usecfwhencloudflare.config.tsexists, but it loads only on demand. The standingclaudeMdline is what Cloudflare's agent docs recommend.ci.ymlverify commands pass on each. Completion returns real candidates:cf complete -- dns recgivesrecords.