This repository deploys a self-hosted Cloudflare OS: up to seven Workers, plus any optional Gatekeepers a deployment selects, configured by deployment.jsonc and built from the pinned cloudflare-os submodule.
cloudflare-os/: upstream, pinned by the gitlink. Never edit it here; it changes only by moving the pin.packages/cf-os: thecf-osCLI (pnpm cf-os <command>), which configures, checks, deploys and updates the project.src/coreis pure logic; Cloudflare API calls go throughsrc/cf-client.ts.packages/custom-gatekeeper,packages/error-reporter: this repository's own Workers..agents/skills/cloudflare-os-operator: load it for anything touching a deployment: Access,deployment.jsonc, deploys, migrations, rollback.
Updating is always cf-os update, never a hand-moved gitlink or a hand-merged starter:
npx cf-os@latest updatemerges the starter'smainand checks out the pin it brings.--upstream(upstream'smain) or--to <commit|tag|branch>stages a newer pin, uncommitted, for review;--preview --to <branch|pull/N>pins one for a preview only. In the starter repository itself there is no starter to merge, sopnpm cf-os update --upstreamis the whole step.--dry-runfirst shows both commit ranges. Then carry out.cf-os/update.mdand its checklist,references/updating.md, before committing the pin.
Checks:
pnpm lint(lint, type-check, build) andpnpm testbefore pushing.pnpm cf-os checkgenerates every Worker's config and dry-runs each deploy.cf-ostests arenode:test:node --test packages/cf-os/src/<file>.test.ts. The Workers' tests run on Vitest.pnpm cf-os deploydeploys for real, with no confirmation: only when the operator asks.
IMPORTANT: This repository uses pnpm, not npm. The one exception is npx cf-os@latest, which fetches the newest published CLI.
IMPORTANT: A global or npx cf-os runs main.ts, commands/scaffold.ts and commands/update.ts from the published package, without the submodule. Nothing they import statically may reach @gadgets/*; main.test.ts checks it.
IMPORTANT: Results meant for scripts go to stdout as JSON; everything else, a spawned tool's output included, goes to stderr. Every prompt has a flag or config equivalent, and without a terminal a missing answer fails naming it.
Comments say what the code is and why, not what changed. A behaviour change updates the docs that describe it (packages/cf-os/README.md, docs/, the operator skill) in the same commit.