# Cloudflare CI runs build pipelines inside Workers and Sandboxes

> The @cloudflare/ci package is a Cloudflare-native continuous integration engine built on Workflows and Sandbox, published as TypeScript source rather than a runnable Node.js binary. It suits teams already deploying to Workers, and it does not suit teams that want a CI runner on their own machines.

**cloudflare/ci** — Cloudflare-native continuous integration powered by Workflows and Sandbox

- Repository: https://github.com/cloudflare/ci
- Stars: 611 · Forks: 18
- Language: TypeScript
- License: Apache-2.0
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/cloudflare-ci

## A CI engine that only runs on Workers

Most continuous integration systems assume you have a machine to run things on, or a container image they can schedule. Cloudflare CI removes both assumptions and replaces them with the platform the project already lives on. The repository root is the publishable @cloudflare/ci package, and deployable Workers live under examples/. The package targets Cloudflare Workers and publishes TypeScript source for Workers-aware bundlers such as Wrangler. It is explicitly not a directly executable Node.js package, which means there is no CLI you can run from a terminal to trigger a build, and no agent binary to install on a build box. Instead, the CI engine is itself a Worker. Its primitives are exposed through two entry points: the main package for authoring workflows, and @cloudflare/ci/worker for the pieces a deployable Worker entry point needs, such as HTTP routes and the queue handler. This is a genuinely different shape from a hosted CI product, and it is worth being clear that adopting it is a decision to run your pipeline on Cloudflare, not merely a decision about which UI you use to watch it.

## Workflows provide the durable retry model

The reliability story comes from Cloudflare Workflows, and the package is designed around the constraint that comes with them. Runner commands execute inside retryable Workflow steps, and the README states the consequence plainly: commands with external side effects must therefore be idempotent, as required by Cloudflare Workflows. That is a design constraint on your pipeline, not on the library. A step that deploys, sends a message or writes a row will be attempted again if the Workflow retries, so a command that is not safe to run twice will cause a real incident the first time a retry happens. This is the single most important thing to understand before writing pipelines here. The compensating advantage is durability: a Workflow keeps its state and can resume, so a long build that loses a Worker at the halfway mark is not necessarily lost work. The runtime is what makes that possible, since a Worker request can be terminated without the process ending, and the package leans on that instead of trying to keep a long lived process alive.

## Sandbox is where the commands actually execute

Workflows orchestrate, and Sandbox runs the commands. The dependency list in the package manifest shows @cloudflare/sandbox pinned at 0.12.1 as a runtime dependency, next to zod, which suggests the schema validation of pipeline inputs and outputs is part of the design rather than an afterthought. The practical distinction matters when you decide what a runner command can do. A Workflow step is a unit of orchestration with durable state; a Sandbox is the isolation boundary for the command that touches your repository, your build tooling or your cloud provider. Splitting the two means the failure handling for each can be different: an orchestration retry is cheap and automatic, while a sandboxed command is where you control the environment and its credentials. The README also points out that the HTTP routes, queue handler, Wrangler configuration, bindings and the concrete Workflow classes remain application code in each example. That is a deliberate line. The package gives you the building blocks and the failure diagnostics, and your project keeps ownership of the pipeline shape.

## The authoring API and what stays in your repo

Workflows import their authoring API from the package root, and the documented import surface gives you a good sense of the shape.

```ts
import {
  CIWorkflow,
  isCiRunnerFailure,
  type CiContext,
  type CiParams,
  type CiRunnerFailureDiagnostics,
  type CiRunnerResult,
  type CloudflareArtifacts,
} from '@cloudflare/ci';
```

The type names tell the story of a pipeline run. CiContext and CiParams describe what a run is given, CiRunnerResult is what came back, CiRunnerFailureDiagnostics is the neutral failure information, and CloudflareArtifacts is the artifact handle. The isCiRunnerFailure helper is the guard that lets you branch on a failed runner without inspecting the result shape by hand. The package intentionally uses Workers modules and Cloudflare runtime libraries internally rather than providing a Node.js-compatible build, which is why the exports map in the manifest points types and import straight at source files under src/ rather than at a compiled dist directory. The published files list src, README.md, CHANGELOG.md, LICENSE and NOTICE, and test files are excluded from the tarball. If your bundler cannot consume TypeScript source directly, that is an adoption blocker, not a configuration detail.

## Logs are raw output, and that is a security decision

The README is unusually direct about one thing: CiRunnerResult.logs contains raw command output and is not secret-redacted. Only provider notification previews and failure messages are redacted. That distinction has teeth in practice, because CI logs are exactly where credentials leak. A command that echoes an environment variable, prints a config file or prints a resolved remote URL will put that text into the log field verbatim, and the package will not scrub it for you. If you plan to surface logs in a chat notification or a pull request comment, you need to filter them yourself before they leave the Worker. This is not an incidental omission, since the package has a first class concept of neutral runner failure diagnostics, which is a different thing from log content and is intended to be safe to pass around. The design distinguishes a structured failure summary from raw output, and only the first is treated as shareable. Anyone building on this needs to keep that separation intact rather than forwarding the whole result object into a webhook.

## Two examples: a plain pipeline and a self-healing one

The repository ships two self contained deployable Workers under examples/. The first, cloudflare-artifacts, is described as a basic install, check and deploy pipeline, which is the smallest useful shape and the right starting point for evaluation. The second, self-healing, adds an application-owned Healing Agent that consumes the package's neutral runner failure diagnostics. That second example is the interesting one for understanding the intended direction of travel. Instead of a failed pipeline simply failing, the failure information is fed to an agent that can decide what to do next. The README is careful about the boundary: the Healing Agent, its tools and its AI dependencies are not part of @cloudflare/ci. You get the diagnostics and you build the responder, which means the AI parts are your code, your prompts and your model costs, and you are responsible for what an agent is allowed to do with a failed build. Each example has an independent package manifest, lockfile, TypeScript configuration and Wrangler configuration, deliberately structured so Cloudflare can deploy the example subdirectory as a standalone repository.

## The development loop and the licensing terms

The local workflow for contributors is a short list of pnpm scripts, and the build script is worth noticing because it reveals how the package is meant to be consumed.

```bash
pnpm install
pnpm test
pnpm typecheck
pnpm lint
pnpm format:check
pnpm build
```

The build script is tsc --noEmit, meaning there is no compile step that emits JavaScript, because the package ships TypeScript source and lets the Workers-aware bundler do the transformation. Typecheck runs the same command. Linting uses oxlint and formatting uses oxfmt, and the prepublishOnly script chains test, typecheck, lint and format:check together, so a publish cannot skip any of them. Tests run through vitest with a passWithNoTests flag. The licence is Apache-2.0, copyright 2026 Cloudflare, Inc., which permits use, modification and redistribution including in commercial products, with the usual attribution and notice requirements, and without the copyleft obligations that would attach to derived works. That matters here because your pipeline will embed the package into a Worker you deploy, and Apache-2.0 keeps that straightforward. The one release listed is v0.2.0 on 2026-09-14, and the last push was on 2026-10-21.

## When Cloudflare CI is the wrong shape

There are clear cases where this package is the wrong answer, and the limitations are structural rather than fixable. If your builds must run on hardware you control, on a GPU, or inside a network that Cloudflare cannot reach, there is no escape hatch, because the execution environment is the platform. If your team is not already deploying Workers, adopting this means adopting a second runtime for your build system, and the nodejs_compat compatibility flag is a hint that Workers is not a drop-in Node.js environment. If you need to run the same pipeline against multiple cloud providers, the examples here are Cloudflare specific by construction, since the Sandbox dependency and the Cloudflare runtime libraries are not abstractions behind a provider interface. A self-hosted runner or a conventional hosted CI service keeps the execution environment a choice you can change later, and that is the alternative worth weighing. Cloudflare CI wins on latency and on keeping everything in one platform, and pays for it in portability.

## Conclusion

Adopt @cloudflare/ci if your build and deploy steps already run inside Cloudflare and your team can accept that pipeline logic lives in a Worker rather than in a runner image you control. Do not adopt it if you need a self-hosted agent, a Node.js executable, or non Cloudflare targets in the same pipeline. Two things to verify before writing your first workflow: that you have enabled the nodejs_compat compatibility flag for Workers importing @cloudflare/ci/worker, and that every runner command is safe to re-execute, because commands with external side effects run inside retryable Workflow steps and must be idempotent. Start with the examples/cloudflare-artifacts example, which covers install, check and deploy, and read CiRunnerResult.logs knowing it is raw command output that is not secret-redacted before you wire it into a channel where anyone can read it.

## FAQ

### What is @cloudflare/ci?

It is a Cloudflare-native continuous integration engine built on Cloudflare Workflows and Sandbox, published as TypeScript source rather than a directly executable Node.js package. The repository root is the package, and deployable Workers live under examples/.

### How do I install @cloudflare/ci?

Add it to a Workers project with pnpm add @cloudflare/ci. Workers that import @cloudflare/ci/worker must enable the nodejs_compat compatibility flag.

### Why do my runner commands have to be idempotent?

Runner commands execute inside retryable Workflow steps, so a command with external side effects may run more than once. The documentation states that such commands must be idempotent, as required by Cloudflare Workflows.

### Are Cloudflare CI logs safe to share?

No. CiRunnerResult.logs contains raw command output and is not secret-redacted. Only provider notification previews and failure messages are redacted, so logs should be filtered before you send them anywhere.

### Does the self-healing example include the AI agent?

No. The examples/self-healing example adds an application-owned Healing Agent that consumes the package's runner failure diagnostics, but the agent, its tools and its AI dependencies are not part of @cloudflare/ci.

## Sources

- [cloudflare/ci on GitHub](https://github.com/cloudflare/ci)
- [Issues](https://github.com/cloudflare/ci/issues)
- [License: Apache-2.0](https://github.com/cloudflare/ci/blob/main/LICENSE)
- [README](https://github.com/cloudflare/ci/blob/main/README.md)
- [Releases](https://github.com/cloudflare/ci/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/cloudflare-ci
